1// +build linux 2 3package dns 4 5// See: 6// * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and 7// * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/ 8// 9// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing 10// interface, this might not always be the correct one. This code will make sure the egress 11// packet's interface matched the ingress' one. 12 13import ( 14 "net" 15 "syscall" 16) 17 18// setUDPSocketOptions4 prepares the v4 socket for sessions. 19func setUDPSocketOptions4(conn *net.UDPConn) error { 20 file, err := conn.File() 21 if err != nil { 22 return err 23 } 24 if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil { 25 return err 26 } 27 // Calling File() above results in the connection becoming blocking, we must fix that. 28 // See https://github.com/miekg/dns/issues/279 29 err = syscall.SetNonblock(int(file.Fd()), true) 30 if err != nil { 31 return err 32 } 33 return nil 34} 35 36// setUDPSocketOptions6 prepares the v6 socket for sessions. 37func setUDPSocketOptions6(conn *net.UDPConn) error { 38 file, err := conn.File() 39 if err != nil { 40 return err 41 } 42 if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil { 43 return err 44 } 45 err = syscall.SetNonblock(int(file.Fd()), true) 46 if err != nil { 47 return err 48 } 49 return nil 50} 51 52// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined 53// (dualstack). 54func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { 55 file, err := conn.File() 56 if err != nil { 57 return false, err 58 } 59 // dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections 60 v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY) 61 if err != nil { 62 return false, err 63 } 64 return v6only == 1, nil 65} 66 67func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { 68 file, err := conn.File() 69 if err != nil { 70 return nil, err 71 } 72 return syscall.Getsockname(int(file.Fd())) 73} 74