diff --git a/transport/internet/sockopt_darwin.go b/transport/internet/sockopt_darwin.go index 79e2133a..86af492a 100644 --- a/transport/internet/sockopt_darwin.go +++ b/transport/internet/sockopt_darwin.go @@ -1,7 +1,7 @@ package internet import ( - network "net" + gonet "net" "os" "syscall" "unsafe" @@ -108,13 +108,58 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf return err } } - if config.Interface != "" { - InterfaceIndex := getInterfaceIndexByName(config.Interface) - if InterfaceIndex != 0 { - if err := unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, InterfaceIndex); err != nil { - return errors.New("failed to set Interface").Base(err) + + if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { + if config.TcpKeepAliveIdle > 0 { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_KEEPALIVE, int(config.TcpKeepAliveInterval)); err != nil { + return errors.New("failed to set TCP_KEEPINTVL", err) } } + if config.TcpKeepAliveInterval > 0 { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, sysTCP_KEEPINTVL, int(config.TcpKeepAliveIdle)); err != nil { + return errors.New("failed to set TCP_KEEPIDLE", err) + } + } + if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1); err != nil { + return errors.New("failed to set SO_KEEPALIVE", err) + } + } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 { + if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 0); err != nil { + return errors.New("failed to unset SO_KEEPALIVE", err) + } + } + } + + if config.Interface != "" { + iface, err := gonet.InterfaceByName(config.Interface) + + if err != nil { + return errors.New("failed to get interface ", config.Interface).Base(err) + } + if network == "tcp6" || network == "udp6" { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, iface.Index); err != nil { + return errors.New("failed to set IPV6_BOUND_IF").Base(err) + } + } else { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, iface.Index); err != nil { + return errors.New("failed to set IP_BOUND_IF").Base(err) + } + } + } + + return nil +} + +func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { + if isTCPSocket(network) { + tfo := config.ParseTFOValue() + if tfo > 0 { + tfo = TCP_FASTOPEN_SERVER + } + if tfo >= 0 { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_FASTOPEN, tfo); err != nil { + return err + } } if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { @@ -138,46 +183,19 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf } } - return nil -} + if config.Interface != "" { + iface, err := gonet.InterfaceByName(config.Interface) -func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { - if isTCPSocket(network) { - tfo := config.ParseTFOValue() - if tfo > 0 { - tfo = TCP_FASTOPEN_SERVER + if err != nil { + return errors.New("failed to get interface ", config.Interface).Base(err) } - if tfo >= 0 { - if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_FASTOPEN, tfo); err != nil { - return err + if network == "tcp6" || network == "udp6" { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, iface.Index); err != nil { + return errors.New("failed to set IPV6_BOUND_IF").Base(err) } - } - if config.Interface != "" { - InterfaceIndex := getInterfaceIndexByName(config.Interface) - if InterfaceIndex != 0 { - if err := unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, InterfaceIndex); err != nil { - return errors.New("failed to set Interface").Base(err) - } - } - } - - if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { - if config.TcpKeepAliveIdle > 0 { - if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_KEEPALIVE, int(config.TcpKeepAliveInterval)); err != nil { - return errors.New("failed to set TCP_KEEPINTVL", err) - } - } - if config.TcpKeepAliveInterval > 0 { - if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, sysTCP_KEEPINTVL, int(config.TcpKeepAliveIdle)); err != nil { - return errors.New("failed to set TCP_KEEPIDLE", err) - } - } - if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1); err != nil { - return errors.New("failed to set SO_KEEPALIVE", err) - } - } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 { - if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 0); err != nil { - return errors.New("failed to unset SO_KEEPALIVE", err) + } else { + if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, iface.Index); err != nil { + return errors.New("failed to set IP_BOUND_IF").Base(err) } } } @@ -224,24 +242,3 @@ func setReusePort(fd uintptr) error { } return nil } -func getInterfaceIndexByName(name string) int { - ifaces, err := network.Interfaces() - if err == nil { - for _, iface := range ifaces { - if (iface.Flags&network.FlagUp == network.FlagUp) && (iface.Flags&network.FlagLoopback != network.FlagLoopback) { - addrs, _ := iface.Addrs() - for _, addr := range addrs { - if ipnet, ok := addr.(*network.IPNet); ok && !ipnet.IP.IsLoopback() { - if ipnet.IP.To4() != nil { - if iface.Name == name { - return iface.Index - } - } - } - } - } - - } - } - return 0 -}