github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/common/redir/tproxy_linux.go (about)

     1  package redir
     2  
     3  import (
     4  	"encoding/binary"
     5  	"net/netip"
     6  	"syscall"
     7  
     8  	"github.com/sagernet/sing/common/control"
     9  	E "github.com/sagernet/sing/common/exceptions"
    10  	M "github.com/sagernet/sing/common/metadata"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func TProxy(fd uintptr, isIPv6 bool) error {
    16  	err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
    17  	if err == nil {
    18  		err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
    19  	}
    20  	if err == nil && isIPv6 {
    21  		err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
    22  	}
    23  	if err == nil {
    24  		err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
    25  	}
    26  	if err == nil && isIPv6 {
    27  		err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
    28  	}
    29  	return err
    30  }
    31  
    32  func TProxyWriteBack() control.Func {
    33  	return func(network, address string, conn syscall.RawConn) error {
    34  		return control.Raw(conn, func(fd uintptr) error {
    35  			if M.ParseSocksaddr(address).Addr.Is6() {
    36  				return syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
    37  			} else {
    38  				return syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
    39  			}
    40  		})
    41  	}
    42  }
    43  
    44  func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
    45  	controlMessages, err := unix.ParseSocketControlMessage(oob)
    46  	if err != nil {
    47  		return netip.AddrPort{}, err
    48  	}
    49  	for _, message := range controlMessages {
    50  		if message.Header.Level == unix.SOL_IP && message.Header.Type == unix.IP_RECVORIGDSTADDR {
    51  			return netip.AddrPortFrom(M.AddrFromIP(message.Data[4:8]), binary.BigEndian.Uint16(message.Data[2:4])), nil
    52  		} else if message.Header.Level == unix.SOL_IPV6 && message.Header.Type == unix.IPV6_RECVORIGDSTADDR {
    53  			return netip.AddrPortFrom(M.AddrFromIP(message.Data[8:24]), binary.BigEndian.Uint16(message.Data[2:4])), nil
    54  		}
    55  	}
    56  	return netip.AddrPort{}, E.New("not found")
    57  }