github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/transport/internet/sockopt_freebsd.go (about) 1 package internet 2 3 import ( 4 "encoding/binary" 5 "net" 6 "os" 7 "syscall" 8 "unsafe" 9 10 "golang.org/x/sys/unix" 11 ) 12 13 const ( 14 sysPFINOUT = 0x0 15 sysPFIN = 0x1 16 sysPFOUT = 0x2 17 sysPFFWD = 0x3 18 sysDIOCNATLOOK = 0xc04c4417 19 ) 20 21 type pfiocNatlook struct { 22 Saddr [16]byte /* pf_addr */ 23 Daddr [16]byte /* pf_addr */ 24 Rsaddr [16]byte /* pf_addr */ 25 Rdaddr [16]byte /* pf_addr */ 26 Sport uint16 27 Dport uint16 28 Rsport uint16 29 Rdport uint16 30 Af uint8 31 Proto uint8 32 Direction uint8 33 Pad [1]byte 34 } 35 36 const ( 37 sizeofPfiocNatlook = 0x4c 38 soReUsePort = 0x00000200 39 soReUsePortLB = 0x00010000 40 ) 41 42 func ioctl(s uintptr, ioc int, b []byte) error { 43 if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, s, uintptr(ioc), uintptr(unsafe.Pointer(&b[0]))); errno != 0 { 44 return error(errno) 45 } 46 return nil 47 } 48 49 func (nl *pfiocNatlook) rdPort() int { 50 return int(binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&nl.Rdport))[:])) 51 } 52 53 func (nl *pfiocNatlook) setPort(remote, local int) { 54 binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Sport))[:], uint16(remote)) 55 binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Dport))[:], uint16(local)) 56 } 57 58 // OriginalDst uses ioctl to read original destination from /dev/pf 59 func OriginalDst(la, ra net.Addr) (net.IP, int, error) { 60 f, err := os.Open("/dev/pf") 61 if err != nil { 62 return net.IP{}, -1, newError("failed to open device /dev/pf").Base(err) 63 } 64 defer f.Close() 65 fd := f.Fd() 66 b := make([]byte, sizeofPfiocNatlook) 67 nl := (*pfiocNatlook)(unsafe.Pointer(&b[0])) 68 var raIP, laIP net.IP 69 var raPort, laPort int 70 switch la.(type) { 71 case *net.TCPAddr: 72 raIP = ra.(*net.TCPAddr).IP 73 laIP = la.(*net.TCPAddr).IP 74 raPort = ra.(*net.TCPAddr).Port 75 laPort = la.(*net.TCPAddr).Port 76 nl.Proto = syscall.IPPROTO_TCP 77 case *net.UDPAddr: 78 raIP = ra.(*net.UDPAddr).IP 79 laIP = la.(*net.UDPAddr).IP 80 raPort = ra.(*net.UDPAddr).Port 81 laPort = la.(*net.UDPAddr).Port 82 nl.Proto = syscall.IPPROTO_UDP 83 } 84 if raIP.To4() != nil { 85 if laIP.IsUnspecified() { 86 laIP = net.ParseIP("127.0.0.1") 87 } 88 copy(nl.Saddr[:net.IPv4len], raIP.To4()) 89 copy(nl.Daddr[:net.IPv4len], laIP.To4()) 90 nl.Af = syscall.AF_INET 91 } 92 if raIP.To16() != nil && raIP.To4() == nil { 93 if laIP.IsUnspecified() { 94 laIP = net.ParseIP("::1") 95 } 96 copy(nl.Saddr[:], raIP) 97 copy(nl.Daddr[:], laIP) 98 nl.Af = syscall.AF_INET6 99 } 100 nl.setPort(raPort, laPort) 101 ioc := uintptr(sysDIOCNATLOOK) 102 for _, dir := range []byte{sysPFOUT, sysPFIN} { 103 nl.Direction = dir 104 err = ioctl(fd, int(ioc), b) 105 if err == nil || err != syscall.ENOENT { 106 break 107 } 108 } 109 if err != nil { 110 return net.IP{}, -1, os.NewSyscallError("ioctl", err) 111 } 112 113 odPort := nl.rdPort() 114 var odIP net.IP 115 switch nl.Af { 116 case syscall.AF_INET: 117 odIP = make(net.IP, net.IPv4len) 118 copy(odIP, nl.Rdaddr[:net.IPv4len]) 119 case syscall.AF_INET6: 120 odIP = make(net.IP, net.IPv6len) 121 copy(odIP, nl.Rdaddr[:]) 122 } 123 return odIP, odPort, nil 124 } 125 126 func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error { 127 if config.Mark != 0 { 128 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil { 129 return newError("failed to set SO_USER_COOKIE").Base(err) 130 } 131 } 132 133 if isTCPSocket(network) { 134 switch config.Tfo { 135 case SocketConfig_Enable: 136 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil { 137 return newError("failed to set TCP_FASTOPEN_CONNECT=1").Base(err) 138 } 139 case SocketConfig_Disable: 140 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil { 141 return newError("failed to set TCP_FASTOPEN_CONNECT=0").Base(err) 142 } 143 } 144 145 if config.TcpKeepAliveIdle > 0 { 146 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil { 147 return newError("failed to set TCP_KEEPIDLE").Base(err) 148 } 149 } 150 if config.TcpKeepAliveInterval > 0 { 151 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil { 152 return newError("failed to set TCP_KEEPINTVL").Base(err) 153 } 154 } 155 if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { 156 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { 157 return newError("failed to set SO_KEEPALIVE").Base(err) 158 } 159 } 160 } 161 162 if config.Tproxy.IsEnabled() { 163 ip, _, _ := net.SplitHostPort(address) 164 if net.ParseIP(ip).To4() != nil { 165 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil { 166 return newError("failed to set outbound IP_BINDANY").Base(err) 167 } 168 } else { 169 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil { 170 return newError("failed to set outbound IPV6_BINDANY").Base(err) 171 } 172 } 173 } 174 175 if config.TxBufSize != 0 { 176 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, int(config.TxBufSize)); err != nil { 177 return newError("failed to set SO_SNDBUF").Base(err) 178 } 179 } 180 181 if config.RxBufSize != 0 { 182 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, int(config.RxBufSize)); err != nil { 183 return newError("failed to set SO_RCVBUF").Base(err) 184 } 185 } 186 187 return nil 188 } 189 190 func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { 191 if config.Mark != 0 { 192 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil { 193 return newError("failed to set SO_USER_COOKIE").Base(err) 194 } 195 } 196 if isTCPSocket(network) { 197 switch config.Tfo { 198 case SocketConfig_Enable: 199 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil { 200 return newError("failed to set TCP_FASTOPEN=1").Base(err) 201 } 202 case SocketConfig_Disable: 203 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil { 204 return newError("failed to set TCP_FASTOPEN=0").Base(err) 205 } 206 } 207 if config.TcpKeepAliveIdle > 0 { 208 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil { 209 return newError("failed to set TCP_KEEPIDLE").Base(err) 210 } 211 } 212 if config.TcpKeepAliveInterval > 0 { 213 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil { 214 return newError("failed to set TCP_KEEPINTVL").Base(err) 215 } 216 } 217 if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 { 218 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { 219 return newError("failed to set SO_KEEPALIVE").Base(err) 220 } 221 } 222 } 223 224 if config.Tproxy.IsEnabled() { 225 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil { 226 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil { 227 return newError("failed to set inbound IP_BINDANY").Base(err) 228 } 229 } 230 } 231 232 if config.TxBufSize != 0 { 233 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, int(config.TxBufSize)); err != nil { 234 return newError("failed to set SO_SNDBUF").Base(err) 235 } 236 } 237 238 if config.RxBufSize != 0 { 239 if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, int(config.RxBufSize)); err != nil { 240 return newError("failed to set SO_RCVBUF").Base(err) 241 } 242 } 243 244 return nil 245 } 246 247 func bindAddr(fd uintptr, ip []byte, port uint32) error { 248 setReuseAddr(fd) 249 setReusePort(fd) 250 251 var sockaddr syscall.Sockaddr 252 253 switch len(ip) { 254 case net.IPv4len: 255 a4 := &syscall.SockaddrInet4{ 256 Port: int(port), 257 } 258 copy(a4.Addr[:], ip) 259 sockaddr = a4 260 case net.IPv6len: 261 a6 := &syscall.SockaddrInet6{ 262 Port: int(port), 263 } 264 copy(a6.Addr[:], ip) 265 sockaddr = a6 266 default: 267 return newError("unexpected length of ip") 268 } 269 270 return syscall.Bind(int(fd), sockaddr) 271 } 272 273 func setReuseAddr(fd uintptr) error { 274 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { 275 return newError("failed to set SO_REUSEADDR").Base(err).AtWarning() 276 } 277 return nil 278 } 279 280 func setReusePort(fd uintptr) error { 281 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil { 282 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePort, 1); err != nil { 283 return newError("failed to set SO_REUSEPORT").Base(err).AtWarning() 284 } 285 } 286 return nil 287 }