mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	The vendor/ folder was created with the help of @FiloSottile's gvt and vendorcheck. Any dependencies of Caddy plugins outside this repo are not vendored. We do not remove any unused, vendored packages because vendorcheck -u only checks using the current build configuration; i.e. packages that may be imported by files toggled by build tags of other systems. CI tests have been updated to ignore the vendor/ folder. When Go 1.9 is released, a few of the go commands should be revised to again use ./... as it will ignore the vendor folder by default.
		
			
				
	
	
		
			106 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// +build linux,!appengine
 | 
						|
 | 
						|
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 outgoing
 | 
						|
// interface, this might not always be the correct one. This code will make sure the egress
 | 
						|
// packet's interface matched the ingress' one.
 | 
						|
 | 
						|
import (
 | 
						|
	"net"
 | 
						|
	"syscall"
 | 
						|
)
 | 
						|
 | 
						|
// setUDPSocketOptions sets the UDP socket options.
 | 
						|
// This function is implemented on a per platform basis. See udp_*.go for more details
 | 
						|
func setUDPSocketOptions(conn *net.UDPConn) error {
 | 
						|
	sa, err := getUDPSocketName(conn)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	switch sa.(type) {
 | 
						|
	case *syscall.SockaddrInet6:
 | 
						|
		v6only, err := getUDPSocketOptions6Only(conn)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		setUDPSocketOptions6(conn)
 | 
						|
		if !v6only {
 | 
						|
			setUDPSocketOptions4(conn)
 | 
						|
		}
 | 
						|
	case *syscall.SockaddrInet4:
 | 
						|
		setUDPSocketOptions4(conn)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// setUDPSocketOptions4 prepares the v4 socket for sessions.
 | 
						|
func setUDPSocketOptions4(conn *net.UDPConn) error {
 | 
						|
	file, err := conn.File()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
 | 
						|
		file.Close()
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// Calling File() above results in the connection becoming blocking, we must fix that.
 | 
						|
	// See https://github.com/miekg/dns/issues/279
 | 
						|
	err = syscall.SetNonblock(int(file.Fd()), true)
 | 
						|
	if err != nil {
 | 
						|
		file.Close()
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	file.Close()
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// setUDPSocketOptions6 prepares the v6 socket for sessions.
 | 
						|
func setUDPSocketOptions6(conn *net.UDPConn) error {
 | 
						|
	file, err := conn.File()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
 | 
						|
		file.Close()
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	err = syscall.SetNonblock(int(file.Fd()), true)
 | 
						|
	if err != nil {
 | 
						|
		file.Close()
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	file.Close()
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined
 | 
						|
// (dualstack).
 | 
						|
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) {
 | 
						|
	file, err := conn.File()
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
	// 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 {
 | 
						|
		file.Close()
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
	file.Close()
 | 
						|
	return v6only == 1, nil
 | 
						|
}
 | 
						|
 | 
						|
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
 | 
						|
	file, err := conn.File()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer file.Close()
 | 
						|
	return syscall.Getsockname(int(file.Fd()))
 | 
						|
}
 |