mirror of
https://github.com/coredns/coredns.git
synced 2026-10-24 11:15:43 -04:00
core/dnsserver: preserve UDP packet destination addresses (#8644)
* core/dnsserver: preserve UDP packet destination addresses Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com> * test: modernize reverse UDP reply traversal Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com> * test: account for Unix IPv4 source-control capabilities Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com> --------- Signed-off-by: houyuwushang <180804215+houyuwushang@users.noreply.github.com>
This commit is contained in:
107
core/dnsserver/udp_windows.go
Normal file
107
core/dnsserver/udp_windows.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// WSACMSGHDR contains a native-size length followed by two 32-bit integers.
|
||||
// Each control message is aligned to SIZE_T; its length excludes tail padding.
|
||||
const udpCmsgWord = strconv.IntSize / 8
|
||||
const udpCmsgHeader = udpCmsgWord + 8
|
||||
|
||||
var udpOOBSize = udpCmsgAlign(udpCmsgHeader+8) + udpCmsgAlign(udpCmsgHeader+20)
|
||||
|
||||
func udpCmsgAlign(n int) int { return (n + udpCmsgWord - 1) & ^(udpCmsgWord - 1) }
|
||||
|
||||
func enableUDPPacketInfo(conn *net.UDPConn) bool {
|
||||
raw, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
var err4, err6 error
|
||||
err = raw.Control(func(fd uintptr) {
|
||||
// Dual-stack sockets need both options to receive both families.
|
||||
err4 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_PKTINFO, 1)
|
||||
err6 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, windows.IPV6_PKTINFO, 1)
|
||||
})
|
||||
return err == nil && (err4 == nil || err6 == nil)
|
||||
}
|
||||
|
||||
func parseUDPPacketInfo(oob []byte, flags int) udpPacketInfo {
|
||||
if flags&windows.MSG_CTRUNC != 0 {
|
||||
return udpPacketInfo{}
|
||||
}
|
||||
for len(oob) >= udpCmsgHeader {
|
||||
var length uint64
|
||||
if udpCmsgWord == 8 {
|
||||
length = binary.NativeEndian.Uint64(oob)
|
||||
} else {
|
||||
length = uint64(binary.NativeEndian.Uint32(oob))
|
||||
}
|
||||
if length < udpCmsgHeader || length > uint64(len(oob)) || length > math.MaxInt32 {
|
||||
return udpPacketInfo{}
|
||||
}
|
||||
level := binary.NativeEndian.Uint32(oob[udpCmsgWord:])
|
||||
kind := binary.NativeEndian.Uint32(oob[udpCmsgWord+4:])
|
||||
data := oob[udpCmsgHeader:length]
|
||||
ipLen := 0
|
||||
switch {
|
||||
case level == windows.IPPROTO_IP && kind == windows.IP_PKTINFO:
|
||||
ipLen = net.IPv4len
|
||||
case level == windows.IPPROTO_IPV6 && kind == windows.IPV6_PKTINFO:
|
||||
ipLen = net.IPv6len
|
||||
}
|
||||
if ipLen != 0 {
|
||||
if len(data) < ipLen+4 {
|
||||
return udpPacketInfo{}
|
||||
}
|
||||
ifIndex := binary.NativeEndian.Uint32(data[ipLen:])
|
||||
if ifIndex > math.MaxInt32 {
|
||||
return udpPacketInfo{}
|
||||
}
|
||||
return udpPacketInfo{dst: net.IP(data[:ipLen]), ifIndex: int(ifIndex)}
|
||||
}
|
||||
next := udpCmsgAlign(int(length))
|
||||
if next < int(length) || next > len(oob) {
|
||||
break
|
||||
}
|
||||
oob = oob[next:]
|
||||
}
|
||||
return udpPacketInfo{}
|
||||
}
|
||||
|
||||
func udpSourceControl(info udpPacketInfo) []byte {
|
||||
if info.dst == nil || info.dst.IsUnspecified() || info.dst.IsMulticast() {
|
||||
return nil
|
||||
}
|
||||
ifIndex := info.replyInterface()
|
||||
if ifIndex < 0 || ifIndex > math.MaxInt32 {
|
||||
return nil
|
||||
}
|
||||
ip := info.dst.To4()
|
||||
level, kind := uint32(windows.IPPROTO_IP), uint32(windows.IP_PKTINFO)
|
||||
if ip == nil {
|
||||
ip = info.dst.To16()
|
||||
level, kind = windows.IPPROTO_IPV6, windows.IPV6_PKTINFO
|
||||
}
|
||||
if ip == nil {
|
||||
return nil
|
||||
}
|
||||
length := udpCmsgHeader + len(ip) + 4
|
||||
oob := make([]byte, udpCmsgAlign(length))
|
||||
if udpCmsgWord == 8 {
|
||||
binary.NativeEndian.PutUint64(oob, uint64(length))
|
||||
} else {
|
||||
binary.NativeEndian.PutUint32(oob, uint32(length)) //nolint:gosec // Header plus a 4- or 16-byte IP and a 4-byte interface.
|
||||
}
|
||||
binary.NativeEndian.PutUint32(oob[udpCmsgWord:], level)
|
||||
binary.NativeEndian.PutUint32(oob[udpCmsgWord+4:], kind)
|
||||
copy(oob[udpCmsgHeader:], ip)
|
||||
binary.NativeEndian.PutUint32(oob[udpCmsgHeader+len(ip):], uint32(ifIndex))
|
||||
return oob
|
||||
}
|
||||
Reference in New Issue
Block a user