12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- // +build linux
- 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"
- )
- // 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 {
- 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 {
- return err
- }
- 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 {
- return err
- }
- err = syscall.SetNonblock(int(file.Fd()), true)
- if err != nil {
- return err
- }
- 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 {
- return false, err
- }
- return v6only == 1, nil
- }
- func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
- file, err := conn.File()
- if err != nil {
- return nil, err
- }
- return syscall.Getsockname(int(file.Fd()))
- }
|