mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 21:35:52 +00:00
9dc7194321
See https://github.com/hashicorp/consul/issues/3977 While trying to improve furthermore #3948 (This pull request is still valid since we are not using Compression to compute the result anyway). I saw a strange behaviour of dns library. Basically, msg.Len() and len(msg.Pack()) disagree on Message len. Thus, calculation of DNS response is false consul relies on msg.Len() instead of the result of Pack() This is linked to miekg/dns#453 and a fix has been provided with miekg/dns#454 Would it be possible to upgrade miekg/dns to a more recent function ? Consul might for instance upgrade to a post 1.0 release such as https://github.com/miekg/dns/releases/tag/v1.0.4
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
// +build !windows
|
|
|
|
package dns
|
|
|
|
import (
|
|
"net"
|
|
|
|
"golang.org/x/net/ipv4"
|
|
"golang.org/x/net/ipv6"
|
|
)
|
|
|
|
// SessionUDP holds the remote address and the associated
|
|
// out-of-band data.
|
|
type SessionUDP struct {
|
|
raddr *net.UDPAddr
|
|
context []byte
|
|
}
|
|
|
|
// RemoteAddr returns the remote network address.
|
|
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
|
|
|
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
|
// net.UDPAddr.
|
|
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
|
oob := make([]byte, 40)
|
|
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
|
if err != nil {
|
|
return n, nil, err
|
|
}
|
|
return n, &SessionUDP{raddr, oob[:oobn]}, err
|
|
}
|
|
|
|
// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
|
|
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
|
oob := correctSource(session.context)
|
|
n, _, err := conn.WriteMsgUDP(b, oob, session.raddr)
|
|
return n, err
|
|
}
|
|
|
|
func setUDPSocketOptions(conn *net.UDPConn) error {
|
|
// Try setting the flags for both families and ignore the errors unless they
|
|
// both error.
|
|
err6 := ipv6.NewPacketConn(conn).SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true)
|
|
err4 := ipv4.NewPacketConn(conn).SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true)
|
|
if err6 != nil && err4 != nil {
|
|
return err4
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// parseDstFromOOB takes oob data and returns the destination IP.
|
|
func parseDstFromOOB(oob []byte) net.IP {
|
|
// Start with IPv6 and then fallback to IPv4
|
|
// TODO(fastest963): Figure out a way to prefer one or the other. Looking at
|
|
// the lvl of the header for a 0 or 41 isn't cross-platform.
|
|
var dst net.IP
|
|
cm6 := new(ipv6.ControlMessage)
|
|
if cm6.Parse(oob) == nil {
|
|
dst = cm6.Dst
|
|
}
|
|
if dst == nil {
|
|
cm4 := new(ipv4.ControlMessage)
|
|
if cm4.Parse(oob) == nil {
|
|
dst = cm4.Dst
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// correctSource takes oob data and returns new oob data with the Src equal to the Dst
|
|
func correctSource(oob []byte) []byte {
|
|
dst := parseDstFromOOB(oob)
|
|
if dst == nil {
|
|
return nil
|
|
}
|
|
// If the dst is definitely an IPv6, then use ipv6's ControlMessage to
|
|
// respond otherwise use ipv4's because ipv6's marshal ignores ipv4
|
|
// addresses.
|
|
if dst.To4() == nil {
|
|
cm := new(ipv6.ControlMessage)
|
|
cm.Src = dst
|
|
oob = cm.Marshal()
|
|
} else {
|
|
cm := new(ipv4.ControlMessage)
|
|
cm.Src = dst
|
|
oob = cm.Marshal()
|
|
}
|
|
return oob
|
|
}
|