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

     1  package redir
     2  
     3  import (
     4  	"net"
     5  	"net/netip"
     6  	"syscall"
     7  	"unsafe"
     8  
     9  	M "github.com/sagernet/sing/common/metadata"
    10  )
    11  
    12  const (
    13  	PF_OUT      = 0x2
    14  	DIOCNATLOOK = 0xc0544417
    15  )
    16  
    17  func GetOriginalDestination(conn net.Conn) (destination netip.AddrPort, err error) {
    18  	fd, err := syscall.Open("/dev/pf", 0, syscall.O_RDONLY)
    19  	if err != nil {
    20  		return netip.AddrPort{}, err
    21  	}
    22  	defer syscall.Close(fd)
    23  	nl := struct {
    24  		saddr, daddr, rsaddr, rdaddr       [16]byte
    25  		sxport, dxport, rsxport, rdxport   [4]byte
    26  		af, proto, protoVariant, direction uint8
    27  	}{
    28  		af:        syscall.AF_INET,
    29  		proto:     syscall.IPPROTO_TCP,
    30  		direction: PF_OUT,
    31  	}
    32  	la := conn.LocalAddr().(*net.TCPAddr)
    33  	ra := conn.RemoteAddr().(*net.TCPAddr)
    34  	raIP, laIP := ra.IP, la.IP
    35  	raPort, laPort := ra.Port, la.Port
    36  	switch {
    37  	case raIP.To4() != nil:
    38  		copy(nl.saddr[:net.IPv4len], raIP.To4())
    39  		copy(nl.daddr[:net.IPv4len], laIP.To4())
    40  		nl.af = syscall.AF_INET
    41  	default:
    42  		copy(nl.saddr[:], raIP.To16())
    43  		copy(nl.daddr[:], laIP.To16())
    44  		nl.af = syscall.AF_INET6
    45  	}
    46  	nl.sxport[0], nl.sxport[1] = byte(raPort>>8), byte(raPort)
    47  	nl.dxport[0], nl.dxport[1] = byte(laPort>>8), byte(laPort)
    48  	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 {
    49  		return netip.AddrPort{}, errno
    50  	}
    51  
    52  	var ip net.IP
    53  	switch nl.af {
    54  	case syscall.AF_INET:
    55  		ip = make(net.IP, net.IPv4len)
    56  		copy(ip, nl.rdaddr[:net.IPv4len])
    57  	case syscall.AF_INET6:
    58  		ip = make(net.IP, net.IPv6len)
    59  		copy(ip, nl.rdaddr[:])
    60  	}
    61  	port := uint16(nl.rdxport[0])<<8 | uint16(nl.rdxport[1])
    62  	destination = netip.AddrPortFrom(M.AddrFromIP(ip), port)
    63  	return
    64  }