mirror of
https://github.com/miekg/dns.git
synced 2025-10-11 09:51:01 +02:00
Previously, the oob data was just stored and sent to WriteMsgUDP but it ignores the Src field when writing. Instead, now it is setting the Src to the original Dst and handling IPv4 IPs over IPv6 correctly.
119 lines
3.0 KiB
Go
119 lines
3.0 KiB
Go
package socket
|
|
|
|
import (
|
|
"errors"
|
|
"unsafe"
|
|
)
|
|
|
|
func controlHeaderLen() int {
|
|
return roundup(sizeofCmsghdr)
|
|
}
|
|
|
|
func controlMessageLen(dataLen int) int {
|
|
return roundup(sizeofCmsghdr) + dataLen
|
|
}
|
|
|
|
// returns the whole length of control message.
|
|
func ControlMessageSpace(dataLen int) int {
|
|
return roundup(sizeofCmsghdr) + roundup(dataLen)
|
|
}
|
|
|
|
// A ControlMessage represents the head message in a stream of control
|
|
// messages.
|
|
//
|
|
// A control message comprises of a header, data and a few padding
|
|
// fields to conform to the interface to the kernel.
|
|
//
|
|
// See RFC 3542 for further information.
|
|
type ControlMessage []byte
|
|
|
|
// Data returns the data field of the control message at the head.
|
|
func (m ControlMessage) Data(dataLen int) []byte {
|
|
l := controlHeaderLen()
|
|
if len(m) < l || len(m) < l+dataLen {
|
|
return nil
|
|
}
|
|
return m[l : l+dataLen]
|
|
}
|
|
|
|
// ParseHeader parses and returns the header fields of the control
|
|
// message at the head.
|
|
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
|
|
l := controlHeaderLen()
|
|
if len(m) < l {
|
|
return 0, 0, 0, errors.New("short message")
|
|
}
|
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
|
|
}
|
|
|
|
// Next returns the control message at the next.
|
|
func (m ControlMessage) Next(dataLen int) ControlMessage {
|
|
l := ControlMessageSpace(dataLen)
|
|
if len(m) < l {
|
|
return nil
|
|
}
|
|
return m[l:]
|
|
}
|
|
|
|
// MarshalHeader marshals the header fields of the control message at
|
|
// the head.
|
|
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
|
|
if len(m) < controlHeaderLen() {
|
|
return errors.New("short message")
|
|
}
|
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
h.set(controlMessageLen(dataLen), lvl, typ)
|
|
return nil
|
|
}
|
|
|
|
// Marshal marshals the control message at the head, and returns the next
|
|
// control message.
|
|
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
|
|
l := len(data)
|
|
if len(m) < ControlMessageSpace(l) {
|
|
return nil, errors.New("short message")
|
|
}
|
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
h.set(controlMessageLen(l), lvl, typ)
|
|
if l > 0 {
|
|
copy(m.Data(l), data)
|
|
}
|
|
return m.Next(l), nil
|
|
}
|
|
|
|
// Parse parses as a single or multiple control messages.
|
|
func (m ControlMessage) Parse() ([]ControlMessage, error) {
|
|
var ms []ControlMessage
|
|
for len(m) >= controlHeaderLen() {
|
|
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
|
|
l := h.len()
|
|
if l <= 0 {
|
|
return nil, errors.New("invalid header length")
|
|
}
|
|
if uint64(l) < uint64(controlHeaderLen()) {
|
|
return nil, errors.New("invalid message length")
|
|
}
|
|
if uint64(l) > uint64(len(m)) {
|
|
return nil, errors.New("short buffer")
|
|
}
|
|
ms = append(ms, ControlMessage(m[:l]))
|
|
ll := l - controlHeaderLen()
|
|
if len(m) >= ControlMessageSpace(ll) {
|
|
m = m[ControlMessageSpace(ll):]
|
|
} else {
|
|
m = m[controlMessageLen(ll):]
|
|
}
|
|
}
|
|
return ms, nil
|
|
}
|
|
|
|
// NewControlMessage returns a new stream of control messages.
|
|
func NewControlMessage(dataLen []int) ControlMessage {
|
|
var l int
|
|
for i := range dataLen {
|
|
l += ControlMessageSpace(dataLen[i])
|
|
}
|
|
return make([]byte, l)
|
|
}
|