github.com/xraypb/Xray-core@v1.8.1/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
    13  	// For out-going connections.
    14  	TCP_FASTOPEN_CONNECT = 30
    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 config.Interface != "" {
    51  		if err := syscall.BindToDevice(int(fd), config.Interface); err != nil {
    52  			return newError("failed to set Interface").Base(err)
    53  		}
    54  	}
    55  
    56  	if isTCPSocket(network) {
    57  		tfo := config.ParseTFOValue()
    58  		if tfo > 0 {
    59  			tfo = 1
    60  		}
    61  		if tfo >= 0 {
    62  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN_CONNECT, tfo); err != nil {
    63  				return newError("failed to set TCP_FASTOPEN_CONNECT=", tfo).Base(err)
    64  			}
    65  		}
    66  
    67  		if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 {
    68  			if config.TcpKeepAliveInterval > 0 {
    69  				if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
    70  					return newError("failed to set TCP_KEEPINTVL", err)
    71  				}
    72  			}
    73  			if config.TcpKeepAliveIdle > 0 {
    74  				if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
    75  					return newError("failed to set TCP_KEEPIDLE", err)
    76  				}
    77  			}
    78  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
    79  				return newError("failed to set SO_KEEPALIVE", err)
    80  			}
    81  		} else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 {
    82  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 0); err != nil {
    83  				return newError("failed to unset SO_KEEPALIVE", err)
    84  			}
    85  		}
    86  
    87  		if config.TcpCongestion != "" {
    88  			if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil {
    89  				return newError("failed to set TCP_CONGESTION", err)
    90  			}
    91  		}
    92  
    93  		if config.TcpWindowClamp > 0 {
    94  			if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil {
    95  				return newError("failed to set TCP_WINDOW_CLAMP", err)
    96  			}
    97  		}
    98  	}
    99  
   100  	if config.Tproxy.IsEnabled() {
   101  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
   102  			return newError("failed to set IP_TRANSPARENT").Base(err)
   103  		}
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
   110  	if config.Mark != 0 {
   111  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {
   112  			return newError("failed to set SO_MARK").Base(err)
   113  		}
   114  	}
   115  	if isTCPSocket(network) {
   116  		tfo := config.ParseTFOValue()
   117  		if tfo >= 0 {
   118  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN, tfo); err != nil {
   119  				return newError("failed to set TCP_FASTOPEN=", tfo).Base(err)
   120  			}
   121  		}
   122  
   123  		if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 {
   124  			if config.TcpKeepAliveInterval > 0 {
   125  				if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
   126  					return newError("failed to set TCP_KEEPINTVL", err)
   127  				}
   128  			}
   129  			if config.TcpKeepAliveIdle > 0 {
   130  				if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
   131  					return newError("failed to set TCP_KEEPIDLE", err)
   132  				}
   133  			}
   134  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
   135  				return newError("failed to set SO_KEEPALIVE", err)
   136  			}
   137  		} else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 {
   138  			if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 0); err != nil {
   139  				return newError("failed to unset SO_KEEPALIVE", err)
   140  			}
   141  		}
   142  
   143  		if config.TcpCongestion != "" {
   144  			if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil {
   145  				return newError("failed to set TCP_CONGESTION", err)
   146  			}
   147  		}
   148  
   149  		if config.TcpWindowClamp > 0 {
   150  			if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil {
   151  				return newError("failed to set TCP_WINDOW_CLAMP", err)
   152  			}
   153  		}
   154  	}
   155  
   156  	if config.Tproxy.IsEnabled() {
   157  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
   158  			return newError("failed to set IP_TRANSPARENT").Base(err)
   159  		}
   160  	}
   161  
   162  	if config.ReceiveOriginalDestAddress && isUDPSocket(network) {
   163  		err1 := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
   164  		err2 := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
   165  		if err1 != nil && err2 != nil {
   166  			return err1
   167  		}
   168  	}
   169  
   170  	if config.V6Only {
   171  		if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, syscall.IPV6_V6ONLY, 1); err != nil {
   172  			return newError("failed to set IPV6_V6ONLY", err)
   173  		}
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  func setReuseAddr(fd uintptr) error {
   180  	if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
   181  		return newError("failed to set SO_REUSEADDR").Base(err).AtWarning()
   182  	}
   183  	return nil
   184  }
   185  
   186  func setReusePort(fd uintptr) error {
   187  	if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
   188  		return newError("failed to set SO_REUSEPORT").Base(err).AtWarning()
   189  	}
   190  	return nil
   191  }