github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/transport/internet/sockopt_darwin.go (about) 1 package internet 2 3 import ( 4 network "net" 5 "os" 6 "syscall" 7 "unsafe" 8 9 "github.com/xtls/xray-core/common/net" 10 "golang.org/x/sys/unix" 11 ) 12 13 const ( 14 // TCP_FASTOPEN_SERVER is the value to enable TCP fast open on darwin for server connections. 15 TCP_FASTOPEN_SERVER = 0x01 16 // TCP_FASTOPEN_CLIENT is the value to enable TCP fast open on darwin for client connections. 17 TCP_FASTOPEN_CLIENT = 0x02 // nolint: revive,stylecheck 18 // syscall.TCP_KEEPINTVL is missing on some darwin architectures. 19 sysTCP_KEEPINTVL = 0x101 // nolint: revive,stylecheck 20 ) 21 22 const ( 23 PfOut = 2 24 IOCOut = 0x40000000 25 IOCIn = 0x80000000 26 IOCInOut = IOCIn | IOCOut 27 IOCPARMMask = 0x1FFF 28 LEN = 4*16 + 4*4 + 4*1 29 // #define _IOC(inout,group,num,len) (inout | ((len & IOCPARMMask) << 16) | ((group) << 8) | (num)) 30 // #define _IOWR(g,n,t) _IOC(IOCInOut, (g), (n), sizeof(t)) 31 // #define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook) 32 DIOCNATLOOK = IOCInOut | ((LEN & IOCPARMMask) << 16) | ('D' << 8) | 23 33 ) 34 35 // OriginalDst uses ioctl to read original destination from /dev/pf 36 func OriginalDst(la, ra net.Addr) (net.IP, int, error) { 37 f, err := os.Open("/dev/pf") 38 if err != nil { 39 return net.IP{}, -1, newError("failed to open device /dev/pf").Base(err) 40 } 41 defer f.Close() 42 fd := f.Fd() 43 nl := struct { // struct pfioc_natlook 44 saddr, daddr, rsaddr, rdaddr [16]byte 45 sxport, dxport, rsxport, rdxport [4]byte 46 af, proto, protoVariant, direction uint8 47 }{ 48 af: syscall.AF_INET, 49 proto: syscall.IPPROTO_TCP, 50 direction: PfOut, 51 } 52 var raIP, laIP net.IP 53 var raPort, laPort int 54 switch la.(type) { 55 case *net.TCPAddr: 56 raIP = ra.(*net.TCPAddr).IP 57 laIP = la.(*net.TCPAddr).IP 58 raPort = ra.(*net.TCPAddr).Port 59 laPort = la.(*net.TCPAddr).Port 60 case *net.UDPAddr: 61 raIP = ra.(*net.UDPAddr).IP 62 laIP = la.(*net.UDPAddr).IP 63 raPort = ra.(*net.UDPAddr).Port 64 laPort = la.(*net.UDPAddr).Port 65 } 66 if raIP.To4() != nil { 67 if laIP.IsUnspecified() { 68 laIP = net.ParseIP("127.0.0.1") 69 } 70 copy(nl.saddr[:net.IPv4len], raIP.To4()) 71 copy(nl.daddr[:net.IPv4len], laIP.To4()) 72 } 73 if raIP.To16() != nil && raIP.To4() == nil { 74 if laIP.IsUnspecified() { 75 laIP = net.ParseIP("::1") 76 } 77 copy(nl.saddr[:], raIP) 78 copy(nl.daddr[:], laIP) 79 } 80 nl.sxport[0], nl.sxport[1] = byte(raPort>>8), byte(raPort) 81 nl.dxport[0], nl.dxport[1] = byte(laPort>>8), byte(laPort) 82 if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 { 83 return net.IP{}, -1, os.NewSyscallError("ioctl", err) 84 } 85 86 odPort := nl.rdxport 87 var odIP net.IP 88 switch nl.af { 89 case syscall.AF_INET: 90 odIP = make(net.IP, net.IPv4len) 91 copy(odIP, nl.rdaddr[:net.IPv4len]) 92 case syscall.AF_INET6: 93 odIP = make(net.IP, net.IPv6len) 94 copy(odIP, nl.rdaddr[:]) 95 } 96 return odIP, int(net.PortFromBytes(odPort[:2])), nil 97 } 98 99 func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error { 100 if isTCPSocket(network) { 101 tfo := config.ParseTFOValue() 102 if tfo > 0 { 103 tfo = TCP_FASTOPEN_CLIENT 104 } 105 if tfo >= 0 { 106 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_FASTOPEN, tfo); err != nil { 107 return err 108 } 109 } 110 if config.Interface != "" { 111 InterfaceIndex := getInterfaceIndexByName(config.Interface) 112 if InterfaceIndex != 0 { 113 if err := unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, InterfaceIndex); err != nil { 114 return newError("failed to set Interface").Base(err) 115 } 116 } 117 } 118 119 if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { 120 if config.TcpKeepAliveIdle > 0 { 121 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_KEEPALIVE, int(config.TcpKeepAliveInterval)); err != nil { 122 return newError("failed to set TCP_KEEPINTVL", err) 123 } 124 } 125 if config.TcpKeepAliveInterval > 0 { 126 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, sysTCP_KEEPINTVL, int(config.TcpKeepAliveIdle)); err != nil { 127 return newError("failed to set TCP_KEEPIDLE", err) 128 } 129 } 130 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1); err != nil { 131 return newError("failed to set SO_KEEPALIVE", err) 132 } 133 } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 { 134 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 0); err != nil { 135 return newError("failed to unset SO_KEEPALIVE", err) 136 } 137 } 138 139 if config.TcpNoDelay { 140 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_NODELAY, 1); err != nil { 141 return newError("failed to set TCP_NODELAY", err) 142 } 143 } 144 } 145 146 return nil 147 } 148 149 func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { 150 if isTCPSocket(network) { 151 tfo := config.ParseTFOValue() 152 if tfo > 0 { 153 tfo = TCP_FASTOPEN_SERVER 154 } 155 if tfo >= 0 { 156 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_FASTOPEN, tfo); err != nil { 157 return err 158 } 159 } 160 if config.Interface != "" { 161 InterfaceIndex := getInterfaceIndexByName(config.Interface) 162 if InterfaceIndex != 0 { 163 if err := unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, InterfaceIndex); err != nil { 164 return newError("failed to set Interface").Base(err) 165 } 166 } 167 } 168 169 if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { 170 if config.TcpKeepAliveIdle > 0 { 171 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_KEEPALIVE, int(config.TcpKeepAliveInterval)); err != nil { 172 return newError("failed to set TCP_KEEPINTVL", err) 173 } 174 } 175 if config.TcpKeepAliveInterval > 0 { 176 if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, sysTCP_KEEPINTVL, int(config.TcpKeepAliveIdle)); err != nil { 177 return newError("failed to set TCP_KEEPIDLE", err) 178 } 179 } 180 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1); err != nil { 181 return newError("failed to set SO_KEEPALIVE", err) 182 } 183 } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 { 184 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 0); err != nil { 185 return newError("failed to unset SO_KEEPALIVE", err) 186 } 187 } 188 } 189 190 return nil 191 } 192 193 func bindAddr(fd uintptr, address []byte, port uint32) error { 194 setReuseAddr(fd) 195 setReusePort(fd) 196 197 var sockaddr unix.Sockaddr 198 199 switch len(address) { 200 case net.IPv4len: 201 a4 := &unix.SockaddrInet4{ 202 Port: int(port), 203 } 204 copy(a4.Addr[:], address) 205 sockaddr = a4 206 case net.IPv6len: 207 a6 := &unix.SockaddrInet6{ 208 Port: int(port), 209 } 210 copy(a6.Addr[:], address) 211 sockaddr = a6 212 default: 213 return newError("unexpected length of ip") 214 } 215 216 return unix.Bind(int(fd), sockaddr) 217 } 218 219 func setReuseAddr(fd uintptr) error { 220 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil { 221 return newError("failed to set SO_REUSEADDR").Base(err).AtWarning() 222 } 223 return nil 224 } 225 226 func setReusePort(fd uintptr) error { 227 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { 228 return newError("failed to set SO_REUSEPORT").Base(err).AtWarning() 229 } 230 return nil 231 } 232 func getInterfaceIndexByName(name string) int { 233 ifaces, err := network.Interfaces() 234 if err == nil { 235 for _, iface := range ifaces { 236 if (iface.Flags&network.FlagUp == network.FlagUp) && (iface.Flags&network.FlagLoopback != network.FlagLoopback) { 237 addrs, _ := iface.Addrs() 238 for _, addr := range addrs { 239 if ipnet, ok := addr.(*network.IPNet); ok && !ipnet.IP.IsLoopback() { 240 if ipnet.IP.To4() != nil { 241 if iface.Name == name { 242 return iface.Index 243 } 244 } 245 } 246 } 247 } 248 249 } 250 } 251 return 0 252 }