github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/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 func (nl *pfiocNatlook) rdPort() int { 49 return int(binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&nl.Rdport))[:])) 50 } 51 52 func (nl *pfiocNatlook) setPort(remote, local int) { 53 binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Sport))[:], uint16(remote)) 54 binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Dport))[:], uint16(local)) 55 } 56 57 // OriginalDst uses ioctl to read original destination from /dev/pf 58 func OriginalDst(la, ra net.Addr) (net.IP, int, error) { 59 f, err := os.Open("/dev/pf") 60 if err != nil { 61 return net.IP{}, -1, newError("failed to open device /dev/pf").Base(err) 62 } 63 defer f.Close() 64 fd := f.Fd() 65 b := make([]byte, sizeofPfiocNatlook) 66 nl := (*pfiocNatlook)(unsafe.Pointer(&b[0])) 67 var raIP, laIP net.IP 68 var raPort, laPort int 69 switch la.(type) { 70 case *net.TCPAddr: 71 raIP = ra.(*net.TCPAddr).IP 72 laIP = la.(*net.TCPAddr).IP 73 raPort = ra.(*net.TCPAddr).Port 74 laPort = la.(*net.TCPAddr).Port 75 nl.Proto = syscall.IPPROTO_TCP 76 case *net.UDPAddr: 77 raIP = ra.(*net.UDPAddr).IP 78 laIP = la.(*net.UDPAddr).IP 79 raPort = ra.(*net.UDPAddr).Port 80 laPort = la.(*net.UDPAddr).Port 81 nl.Proto = syscall.IPPROTO_UDP 82 } 83 if raIP.To4() != nil { 84 if laIP.IsUnspecified() { 85 laIP = net.ParseIP("127.0.0.1") 86 } 87 copy(nl.Saddr[:net.IPv4len], raIP.To4()) 88 copy(nl.Daddr[:net.IPv4len], laIP.To4()) 89 nl.Af = syscall.AF_INET 90 } 91 if raIP.To16() != nil && raIP.To4() == nil { 92 if laIP.IsUnspecified() { 93 laIP = net.ParseIP("::1") 94 } 95 copy(nl.Saddr[:], raIP) 96 copy(nl.Daddr[:], laIP) 97 nl.Af = syscall.AF_INET6 98 } 99 nl.setPort(raPort, laPort) 100 ioc := uintptr(sysDIOCNATLOOK) 101 for _, dir := range []byte{sysPFOUT, sysPFIN} { 102 nl.Direction = dir 103 err = ioctl(fd, int(ioc), b) 104 if err == nil || err != syscall.ENOENT { 105 break 106 } 107 } 108 if err != nil { 109 return net.IP{}, -1, os.NewSyscallError("ioctl", err) 110 } 111 112 odPort := nl.rdPort() 113 var odIP net.IP 114 switch nl.Af { 115 case syscall.AF_INET: 116 odIP = make(net.IP, net.IPv4len) 117 copy(odIP, nl.Rdaddr[:net.IPv4len]) 118 case syscall.AF_INET6: 119 odIP = make(net.IP, net.IPv6len) 120 copy(odIP, nl.Rdaddr[:]) 121 } 122 return odIP, odPort, nil 123 } 124 125 func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error { 126 if config.Mark != 0 { 127 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil { 128 return newError("failed to set SO_USER_COOKIE").Base(err) 129 } 130 } 131 132 if isTCPSocket(network) { 133 switch config.Tfo { 134 case SocketConfig_Enable: 135 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil { 136 return newError("failed to set TCP_FASTOPEN_CONNECT=1").Base(err) 137 } 138 case SocketConfig_Disable: 139 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil { 140 return newError("failed to set TCP_FASTOPEN_CONNECT=0").Base(err) 141 } 142 } 143 } 144 145 if config.Tproxy.IsEnabled() { 146 ip, _, _ := net.SplitHostPort(address) 147 if net.ParseIP(ip).To4() != nil { 148 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil { 149 return newError("failed to set outbound IP_BINDANY").Base(err) 150 } 151 } else { 152 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil { 153 return newError("failed to set outbound IPV6_BINDANY").Base(err) 154 } 155 } 156 } 157 return nil 158 } 159 160 func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { 161 if config.Mark != 0 { 162 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil { 163 return newError("failed to set SO_USER_COOKIE").Base(err) 164 } 165 } 166 if isTCPSocket(network) { 167 switch config.Tfo { 168 case SocketConfig_Enable: 169 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil { 170 return newError("failed to set TCP_FASTOPEN=1").Base(err) 171 } 172 case SocketConfig_Disable: 173 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil { 174 return newError("failed to set TCP_FASTOPEN=0").Base(err) 175 } 176 } 177 } 178 179 if config.Tproxy.IsEnabled() { 180 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil { 181 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil { 182 return newError("failed to set inbound IP_BINDANY").Base(err) 183 } 184 } 185 } 186 187 return nil 188 } 189 190 func bindAddr(fd uintptr, ip []byte, port uint32) error { 191 setReuseAddr(fd) 192 setReusePort(fd) 193 194 var sockaddr syscall.Sockaddr 195 196 switch len(ip) { 197 case net.IPv4len: 198 a4 := &syscall.SockaddrInet4{ 199 Port: int(port), 200 } 201 copy(a4.Addr[:], ip) 202 sockaddr = a4 203 case net.IPv6len: 204 a6 := &syscall.SockaddrInet6{ 205 Port: int(port), 206 } 207 copy(a6.Addr[:], ip) 208 sockaddr = a6 209 default: 210 return newError("unexpected length of ip") 211 } 212 213 return syscall.Bind(int(fd), sockaddr) 214 } 215 216 func setReuseAddr(fd uintptr) error { 217 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { 218 return newError("failed to set SO_REUSEADDR").Base(err).AtWarning() 219 } 220 return nil 221 } 222 223 func setReusePort(fd uintptr) error { 224 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil { 225 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePort, 1); err != nil { 226 return newError("failed to set SO_REUSEPORT").Base(err).AtWarning() 227 } 228 } 229 return nil 230 }