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