Cleanup the pull request somewhat
This commit is contained in:
parent
448e8eb700
commit
97b62e4aff
66
udp.go
66
udp.go
|
@ -18,70 +18,56 @@ func (session *UDPSession) RemoteAddr() net.Addr {
|
||||||
return session.raddr
|
return session.raddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UDPConn wrap a net.UDPConn with dns.UDPConn struct
|
||||||
type UDPConn struct {
|
type UDPConn struct {
|
||||||
*net.UDPConn
|
*net.UDPConn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap a net.UDPConn with dns.UDPConn struct
|
// NewUDPConn return a new UDPConn.
|
||||||
// Initialize the underlying net.UDPConn for supporting "sessions"
|
// Initialize the underlying net.UDPConn for supporting "sessions"
|
||||||
// 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) (*UDPConn, 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 = udpPatchSocket(conn)
|
conn := new(net.UDPConn)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
session = &UDPSession{raddr, oob[:oobn]}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func udpPatchSocket(conn *net.UDPConn) (err error) {
|
|
||||||
file, err := conn.File()
|
file, err := conn.File()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sa, err := syscall.Getsockname(int(file.Fd()))
|
sa, err := syscall.Getsockname(int(file.Fd()))
|
||||||
|
|
||||||
ipv4, ipv6 := false, false
|
|
||||||
switch sa.(type) {
|
switch sa.(type) {
|
||||||
case *syscall.SockaddrInet6:
|
case *syscall.SockaddrInet6:
|
||||||
ipv6 = true
|
|
||||||
|
|
||||||
// dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
|
// 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)
|
v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
SetUDPSocketOptions6(conn)
|
||||||
|
|
||||||
if v6only == 0 {
|
if v6only == 0 {
|
||||||
ipv4 = true
|
SetUDPSocketOptions4(conn)
|
||||||
}
|
}
|
||||||
case *syscall.SockaddrInet4:
|
case *syscall.SockaddrInet4:
|
||||||
ipv4 = true
|
SetUDPSocketOptions4(conn)
|
||||||
|
}
|
||||||
|
return &UDPConn{conn}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFromSessionUDP ... 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) (int, *UDPSession, error) {
|
||||||
|
oob := make([]byte, 40)
|
||||||
|
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return udpPatchSocketTypes(conn, ipv4, ipv6)
|
session := &UDPSession{raddr, oob[:oobn]}
|
||||||
|
return n, session, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToSessionUDP Just like net.UDPConn.WritetTo(), but uses a session object instead of net.Addr
|
||||||
|
func (conn *UDPConn) WriteToSessionUDP(b []byte, session *UDPSession) (int, error) {
|
||||||
|
n, _, err = conn.WriteMsgUDP(b, session.context, session.raddr)
|
||||||
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
53
udp_linux.go
53
udp_linux.go
|
@ -1,43 +1,42 @@
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Extensions of the original work are copyright (c) 2011 Miek Gieben
|
|
||||||
|
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
|
// See:
|
||||||
|
// * 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/
|
||||||
|
//
|
||||||
|
// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outoging
|
||||||
|
// interface, this might not always be the correct one. This code will make sure the egress
|
||||||
|
// packet's interface matched the ingress' one.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Linux implementation for preparing the socket for sessions
|
// SetUDPSocketOptions4 prepares the v4 socket for sessions.
|
||||||
// Based on http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket
|
func SetUDPSocketOptions4(conn *net.UDPConn) error {
|
||||||
// and http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/
|
// We got the .File() in NewUDPConn, this this will work
|
||||||
func udpPatchSocketTypes(conn *net.UDPConn, ipv4, ipv6 bool) (err error) {
|
file, _ := conn.File()
|
||||||
file, err := conn.File()
|
err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUDPSocketOptions6 prepares the v6 socket for sessions.
|
||||||
|
func SetUDPSocketOptions6(conn *net.UDPConn) error {
|
||||||
|
// We got the .File() in NewUDPConn, this this will work
|
||||||
|
file, _ := conn.File()
|
||||||
|
err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ipv4 {
|
|
||||||
// socket supports IPv4
|
|
||||||
|
|
||||||
err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ipv6 {
|
|
||||||
// socket supports IPv6
|
|
||||||
|
|
||||||
err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
13
udp_other.go
13
udp_other.go
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2011 Miek Gieben. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// Extensions of the original work are copyright (c) 2011 Miek Gieben
|
|
||||||
|
|
||||||
// +build !linux
|
// +build !linux
|
||||||
|
|
||||||
|
@ -11,9 +10,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default implementation for preparing the socket for sessions
|
// These actually do 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
|
func SetUDPSocketOptions4(conn *net.UDPConn) error { return nil }
|
||||||
func udpPatchSocketTypes(conn *net.UDPConn, ipv4, ipv6 bool) (err error) {
|
func SetUDPSocketOptions6(conn *net.UDPConn) error { return nil }
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue