github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/transport/internet/sockopt_linux.go (about) 1 package internet 2 3 import ( 4 "net" 5 "syscall" 6 7 "golang.org/x/sys/unix" 8 ) 9 10 func bindAddr(fd uintptr, ip []byte, port uint32) error { 11 setReuseAddr(fd) 12 setReusePort(fd) 13 14 var sockaddr syscall.Sockaddr 15 16 switch len(ip) { 17 case net.IPv4len: 18 a4 := &syscall.SockaddrInet4{ 19 Port: int(port), 20 } 21 copy(a4.Addr[:], ip) 22 sockaddr = a4 23 case net.IPv6len: 24 a6 := &syscall.SockaddrInet6{ 25 Port: int(port), 26 } 27 copy(a6.Addr[:], ip) 28 sockaddr = a6 29 default: 30 return newError("unexpected length of ip") 31 } 32 33 return syscall.Bind(int(fd), sockaddr) 34 } 35 36 func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error { 37 if config.Mark != 0 { 38 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil { 39 return newError("failed to set SO_MARK").Base(err) 40 } 41 } 42 43 if config.Interface != "" { 44 if err := syscall.BindToDevice(int(fd), config.Interface); err != nil { 45 return newError("failed to set Interface").Base(err) 46 } 47 } 48 49 if isTCPSocket(network) { 50 tfo := config.ParseTFOValue() 51 if tfo > 0 { 52 tfo = 1 53 } 54 if tfo >= 0 { 55 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, unix.TCP_FASTOPEN_CONNECT, tfo); err != nil { 56 return newError("failed to set TCP_FASTOPEN_CONNECT", tfo).Base(err) 57 } 58 } 59 60 if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 { 61 if config.TcpKeepAliveInterval > 0 { 62 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil { 63 return newError("failed to set TCP_KEEPINTVL", err) 64 } 65 } 66 if config.TcpKeepAliveIdle > 0 { 67 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil { 68 return newError("failed to set TCP_KEEPIDLE", err) 69 } 70 } 71 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { 72 return newError("failed to set SO_KEEPALIVE", err) 73 } 74 } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 { 75 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 0); err != nil { 76 return newError("failed to unset SO_KEEPALIVE", err) 77 } 78 } 79 80 if config.TcpCongestion != "" { 81 if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil { 82 return newError("failed to set TCP_CONGESTION", err) 83 } 84 } 85 86 if config.TcpWindowClamp > 0 { 87 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil { 88 return newError("failed to set TCP_WINDOW_CLAMP", err) 89 } 90 } 91 92 if config.TcpUserTimeout > 0 { 93 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(config.TcpUserTimeout)); err != nil { 94 return newError("failed to set TCP_USER_TIMEOUT", err) 95 } 96 } 97 98 if config.TcpMaxSeg > 0 { 99 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_MAXSEG, int(config.TcpMaxSeg)); err != nil { 100 return newError("failed to set TCP_MAXSEG", err) 101 } 102 } 103 104 if config.TcpNoDelay { 105 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_NODELAY, 1); err != nil { 106 return newError("failed to set TCP_NODELAY", err) 107 } 108 } 109 110 } 111 112 if config.Tproxy.IsEnabled() { 113 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil { 114 return newError("failed to set IP_TRANSPARENT").Base(err) 115 } 116 } 117 118 return nil 119 } 120 121 func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error { 122 if config.Mark != 0 { 123 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil { 124 return newError("failed to set SO_MARK").Base(err) 125 } 126 } 127 if isTCPSocket(network) { 128 tfo := config.ParseTFOValue() 129 if tfo >= 0 { 130 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, unix.TCP_FASTOPEN, tfo); err != nil { 131 return newError("failed to set TCP_FASTOPEN", tfo).Base(err) 132 } 133 } 134 135 if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 { 136 if config.TcpKeepAliveInterval > 0 { 137 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil { 138 return newError("failed to set TCP_KEEPINTVL", err) 139 } 140 } 141 if config.TcpKeepAliveIdle > 0 { 142 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil { 143 return newError("failed to set TCP_KEEPIDLE", err) 144 } 145 } 146 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { 147 return newError("failed to set SO_KEEPALIVE", err) 148 } 149 } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 { 150 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 0); err != nil { 151 return newError("failed to unset SO_KEEPALIVE", err) 152 } 153 } 154 155 if config.TcpCongestion != "" { 156 if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil { 157 return newError("failed to set TCP_CONGESTION", err) 158 } 159 } 160 161 if config.TcpWindowClamp > 0 { 162 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil { 163 return newError("failed to set TCP_WINDOW_CLAMP", err) 164 } 165 } 166 167 if config.TcpUserTimeout > 0 { 168 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(config.TcpUserTimeout)); err != nil { 169 return newError("failed to set TCP_USER_TIMEOUT", err) 170 } 171 } 172 173 if config.TcpMaxSeg > 0 { 174 if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_MAXSEG, int(config.TcpMaxSeg)); err != nil { 175 return newError("failed to set TCP_MAXSEG", err) 176 } 177 } 178 } 179 180 if config.Tproxy.IsEnabled() { 181 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil { 182 return newError("failed to set IP_TRANSPARENT").Base(err) 183 } 184 } 185 186 if config.ReceiveOriginalDestAddress && isUDPSocket(network) { 187 err1 := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1) 188 err2 := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1) 189 if err1 != nil && err2 != nil { 190 return err1 191 } 192 } 193 194 if config.V6Only { 195 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, syscall.IPV6_V6ONLY, 1); err != nil { 196 return newError("failed to set IPV6_V6ONLY", err) 197 } 198 } 199 200 return nil 201 } 202 203 func setReuseAddr(fd uintptr) error { 204 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { 205 return newError("failed to set SO_REUSEADDR").Base(err).AtWarning() 206 } 207 return nil 208 } 209 210 func setReusePort(fd uintptr) error { 211 if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { 212 return newError("failed to set SO_REUSEPORT").Base(err).AtWarning() 213 } 214 return nil 215 }