github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/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  const (
    11  	// For incoming connections.
    12  	TCP_FASTOPEN = 23 // nolint: revive,stylecheck
    13  	// For out-going connections.
    14  	TCP_FASTOPEN_CONNECT = 30 // nolint: revive,stylecheck
    15  )
    16  
    17  func bindAddr(fd uintptr, ip []byte, port uint32) error {
    18  	setReuseAddr(fd)
    19  	setReusePort(fd)
    20  
    21  	var sockaddr syscall.Sockaddr
    22  
    23  	switch len(ip) {
    24  	case net.IPv4len:
    25  		a4 := &syscall.SockaddrInet4{
    26  			Port: int(port),
    27  		}
    28  		copy(a4.Addr[:], ip)
    29  		sockaddr = a4
    30  	case net.IPv6len:
    31  		a6 := &syscall.SockaddrInet6{
    32  			Port: int(port),
    33  		}
    34  		copy(a6.Addr[:], ip)
    35  		sockaddr = a6
    36  	default:
    37  		return newError("unexpected length of ip")
    38  	}
    39  
    40  	return syscall.Bind(int(fd), sockaddr)
    41  }
    42  
    43  func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
    44  	if config.Mark != 0 {
    45  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {
    46  			return newError("failed to set SO_MARK").Base(err)
    47  		}
    48  	}
    49  
    50  	if isTCPSocket(network) {
    51  		switch config.Tfo {
    52  		case SocketConfig_Enable:
    53  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN_CONNECT, 1); err != nil {
    54  				return newError("failed to set TCP_FASTOPEN_CONNECT=1").Base(err)
    55  			}
    56  		case SocketConfig_Disable:
    57  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN_CONNECT, 0); err != nil {
    58  				return newError("failed to set TCP_FASTOPEN_CONNECT=0").Base(err)
    59  			}
    60  		}
    61  
    62  		if config.TcpKeepAliveInterval > 0 {
    63  			if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
    64  				return newError("failed to set TCP_KEEPINTVL", err)
    65  			}
    66  		}
    67  		if config.TcpKeepAliveIdle > 0 {
    68  			if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
    69  				return newError("failed to set TCP_KEEPIDLE", err)
    70  			}
    71  		}
    72  		if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 {
    73  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
    74  				return newError("failed to set SO_KEEPALIVE").Base(err)
    75  			}
    76  		}
    77  	}
    78  
    79  	if config.Tproxy.IsEnabled() {
    80  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
    81  			return newError("failed to set IP_TRANSPARENT").Base(err)
    82  		}
    83  	}
    84  
    85  	if config.BindToDevice != "" {
    86  		if err := unix.BindToDevice(int(fd), config.BindToDevice); err != nil {
    87  			return newError("failed to set SO_BINDTODEVICE").Base(err)
    88  		}
    89  	}
    90  
    91  	if config.TxBufSize != 0 {
    92  		syscallTarget := unix.SO_SNDBUF
    93  		if config.ForceBufSize {
    94  			syscallTarget = unix.SO_SNDBUFFORCE
    95  		}
    96  		if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, syscallTarget, int(config.TxBufSize)); err != nil {
    97  			return newError("failed to set SO_SNDBUF/SO_SNDBUFFORCE").Base(err)
    98  		}
    99  	}
   100  
   101  	if config.RxBufSize != 0 {
   102  		syscallTarget := unix.SO_RCVBUF
   103  		if config.ForceBufSize {
   104  			syscallTarget = unix.SO_RCVBUFFORCE
   105  		}
   106  		if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, syscallTarget, int(config.RxBufSize)); err != nil {
   107  			return newError("failed to set SO_RCVBUF/SO_RCVBUFFORCE").Base(err)
   108  		}
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
   115  	if config.Mark != 0 {
   116  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {
   117  			return newError("failed to set SO_MARK").Base(err)
   118  		}
   119  	}
   120  	if isTCPSocket(network) {
   121  		switch config.Tfo {
   122  		case SocketConfig_Enable:
   123  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN, int(config.TfoQueueLength)); err != nil {
   124  				return newError("failed to set TCP_FASTOPEN=", config.TfoQueueLength).Base(err)
   125  			}
   126  		case SocketConfig_Disable:
   127  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN, 0); err != nil {
   128  				return newError("failed to set TCP_FASTOPEN=0").Base(err)
   129  			}
   130  		}
   131  
   132  		if config.TcpKeepAliveInterval > 0 {
   133  			if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
   134  				return newError("failed to set TCP_KEEPINTVL", err)
   135  			}
   136  		}
   137  		if config.TcpKeepAliveIdle > 0 {
   138  			if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
   139  				return newError("failed to set TCP_KEEPIDLE", err)
   140  			}
   141  		}
   142  		if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 {
   143  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
   144  				return newError("failed to set SO_KEEPALIVE", err)
   145  			}
   146  		}
   147  	}
   148  
   149  	if config.Tproxy.IsEnabled() {
   150  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
   151  			return newError("failed to set IP_TRANSPARENT").Base(err)
   152  		}
   153  	}
   154  
   155  	if config.ReceiveOriginalDestAddress && isUDPSocket(network) {
   156  		err1 := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
   157  		err2 := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
   158  		if err1 != nil && err2 != nil {
   159  			return err1
   160  		}
   161  	}
   162  
   163  	if config.BindToDevice != "" {
   164  		if err := unix.BindToDevice(int(fd), config.BindToDevice); err != nil {
   165  			return newError("failed to set SO_BINDTODEVICE").Base(err)
   166  		}
   167  	}
   168  
   169  	if config.TxBufSize != 0 {
   170  		syscallTarget := unix.SO_SNDBUF
   171  		if config.ForceBufSize {
   172  			syscallTarget = unix.SO_SNDBUFFORCE
   173  		}
   174  		if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, syscallTarget, int(config.TxBufSize)); err != nil {
   175  			return newError("failed to set SO_SNDBUF/SO_SNDBUFFORCE").Base(err)
   176  		}
   177  	}
   178  
   179  	if config.RxBufSize != 0 {
   180  		syscallTarget := unix.SO_RCVBUF
   181  		if config.ForceBufSize {
   182  			syscallTarget = unix.SO_RCVBUFFORCE
   183  		}
   184  		if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, syscallTarget, int(config.RxBufSize)); err != nil {
   185  			return newError("failed to set SO_RCVBUF/SO_RCVBUFFORCE").Base(err)
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  func setReuseAddr(fd uintptr) error {
   192  	if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
   193  		return newError("failed to set SO_REUSEADDR").Base(err).AtWarning()
   194  	}
   195  	return nil
   196  }
   197  
   198  func setReusePort(fd uintptr) error {
   199  	if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
   200  		return newError("failed to set SO_REUSEPORT").Base(err).AtWarning()
   201  	}
   202  	return nil
   203  }