diff --git a/udp.go b/udp.go index 9ff790c8..c03f9653 100644 --- a/udp.go +++ b/udp.go @@ -17,8 +17,13 @@ type UDPConn struct { *net.UDPConn } +// Wrap a net.UDPConn with dns.UDPConn struct +// Initialize the underlying net.UDPConn for supporting "sessions" +// Sessions solve https://github.com/miekg/dns/issues/95 func NewUDPConn(conn *net.UDPConn) (newconn *UDPConn, err error) { + // this function is implemented on a per platform basis. See udp_*.go for more details err = udpSocketOobData(conn) + if err != nil { return } @@ -26,6 +31,8 @@ func NewUDPConn(conn *net.UDPConn) (newconn *UDPConn, err error) { return &UDPConn{conn}, nil } +// Just like net.UDPConn.ReadFrom(), but returns a session object instead of net.UDPAddr +// (RemoteAddr() is available from the UDPSession object) func (conn *UDPConn) ReadFromSessionUDP(b []byte) (n int, session *UDPSession, err error) { oob := make([]byte, 40) @@ -39,6 +46,7 @@ func (conn *UDPConn) ReadFromSessionUDP(b []byte) (n int, session *UDPSession, e return } +// Just like net.UDPConn.WritetTo(), but uses a session object instead of net.Addr func (conn *UDPConn) WriteToSessionUDP(b []byte, session *UDPSession) (n int, err error) { n, _, err = conn.WriteMsgUDP(b, session.context, session.raddr) return diff --git a/udp_linux.go b/udp_linux.go index a0b0f98e..edf90283 100644 --- a/udp_linux.go +++ b/udp_linux.go @@ -7,17 +7,22 @@ import ( "syscall" ) +// Linux implementation for preparing the socket for sessions +// Based on http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket +// and http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/ func udpSocketOobData(conn *net.UDPConn) (err error) { file, err := conn.File() if err != nil { return } + // IPv4 support err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1) if err != nil { return } + // IPv6 support err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1) return diff --git a/udp_other.go b/udp_other.go index 0f7adfab..7fd2d163 100644 --- a/udp_other.go +++ b/udp_other.go @@ -6,6 +6,9 @@ import ( "net" ) +// Default implementation for preparing the socket for sessions +// This actually does nothing. See udp_linux.go for an example of how to implement this. +// Make sure you edit the comment on the top of this file accordingly when adding implementations func udpSocketOobData(conn *net.UDPConn) (err error) { return }