[ISSUE-95] Patch only relevant stacks (v4, v6, dual)

This commit is contained in:
Omri Bahumi 2014-07-08 15:18:33 +03:00
parent 44f988ea86
commit aea5c1da03
3 changed files with 50 additions and 11 deletions

32
udp.go
View File

@ -2,6 +2,7 @@ package dns
import ( import (
"net" "net"
"syscall"
) )
type UDPSession struct { type UDPSession struct {
@ -22,7 +23,7 @@ type UDPConn struct {
// Sessions solve https://github.com/miekg/dns/issues/95 // Sessions solve https://github.com/miekg/dns/issues/95
func NewUDPConn(conn *net.UDPConn) (newconn *UDPConn, err error) { func NewUDPConn(conn *net.UDPConn) (newconn *UDPConn, err error) {
// this function is implemented on a per platform basis. See udp_*.go for more details // this function is implemented on a per platform basis. See udp_*.go for more details
err = udpSocketOobData(conn) err = udpPatchSocket(conn)
if err != nil { if err != nil {
return return
@ -51,3 +52,32 @@ func (conn *UDPConn) WriteToSessionUDP(b []byte, session *UDPSession) (n int, er
n, _, err = conn.WriteMsgUDP(b, session.context, session.raddr) n, _, err = conn.WriteMsgUDP(b, session.context, session.raddr)
return return
} }
func udpPatchSocket(conn *net.UDPConn) (err error) {
file, err := conn.File()
if err != nil {
return
}
sa, err := syscall.Getsockname(int(file.Fd()))
ipv4, ipv6 := false, false
switch sa.(type) {
case *syscall.SockaddrInet6:
ipv6 = true
// dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
if err != nil {
return err
}
if v6only == 0 {
ipv4 = true
}
case *syscall.SockaddrInet4:
ipv4 = true
}
return udpPatchSocketTypes(conn, ipv4, ipv6)
}

View File

@ -10,20 +10,29 @@ import (
// Linux implementation for preparing the socket for sessions // Linux implementation for preparing the socket for sessions
// Based on http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket // 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/ // and http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/
func udpSocketOobData(conn *net.UDPConn) (err error) { func udpPatchSocketTypes(conn *net.UDPConn, ipv4, ipv6 bool) (err error) {
file, err := conn.File() file, err := conn.File()
if err != nil { if err != nil {
return return
} }
// IPv4 support if ipv4 {
err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1) // socket supports IPv4
if err != nil {
return err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1)
if err != nil {
return err
}
} }
// IPv6 support if ipv6 {
err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1) // socket supports IPv6
return err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1)
if err != nil {
return err
}
}
return nil
} }

View File

@ -9,6 +9,6 @@ import (
// Default implementation for preparing the socket for sessions // Default implementation for preparing the socket for sessions
// This actually does nothing. See udp_linux.go for an example of how to implement this. // 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 // Make sure you edit the comment on the top of this file accordingly when adding implementations
func udpSocketOobData(conn *net.UDPConn) (err error) { func udpPatchSocketTypes(conn *net.UDPConn, ipv4, ipv6 bool) (err error) {
return return nil
} }