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  }