github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/redir/pfutil/pf_darwin.go (about)

     1  package pfutil
     2  
     3  import (
     4  	"net"
     5  	"syscall"
     6  	"unsafe"
     7  )
     8  
     9  func NatLookup(c *net.TCPConn) (*net.TCPAddr, error) {
    10  	const (
    11  		PF_INOUT     = 0
    12  		PF_IN        = 1
    13  		PF_OUT       = 2
    14  		IOC_OUT      = 0x40000000
    15  		IOC_IN       = 0x80000000
    16  		IOC_INOUT    = IOC_IN | IOC_OUT
    17  		IOCPARM_MASK = 0x1FFF
    18  		LEN          = 4*16 + 4*4 + 4*1
    19  		// #define	_IOC(inout,group,num,len) (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
    20  		// #define	_IOWR(g,n,t)	_IOC(IOC_INOUT,	(g), (n), sizeof(t))
    21  		// #define DIOCNATLOOK		_IOWR('D', 23, struct pfioc_natlook)
    22  		DIOCNATLOOK = IOC_INOUT | ((LEN & IOCPARM_MASK) << 16) | ('D' << 8) | 23
    23  	)
    24  	fd, err := syscall.Open("/dev/pf", 0, syscall.O_RDONLY)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	defer syscall.Close(fd)
    29  	nl := struct { // struct pfioc_natlook
    30  		saddr, daddr, rsaddr, rdaddr       [16]byte
    31  		sxport, dxport, rsxport, rdxport   [4]byte
    32  		af, proto, protoVariant, direction uint8
    33  	}{
    34  		af:        syscall.AF_INET,
    35  		proto:     syscall.IPPROTO_TCP,
    36  		direction: PF_OUT,
    37  	}
    38  	saddr := c.RemoteAddr().(*net.TCPAddr)
    39  	daddr := c.LocalAddr().(*net.TCPAddr)
    40  	copy(nl.saddr[:], saddr.IP)
    41  	copy(nl.daddr[:], daddr.IP)
    42  	nl.sxport[0], nl.sxport[1] = byte(saddr.Port>>8), byte(saddr.Port)
    43  	nl.dxport[0], nl.dxport[1] = byte(daddr.Port>>8), byte(daddr.Port)
    44  	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 {
    45  		return nil, errno
    46  	}
    47  	var addr net.TCPAddr
    48  	addr.IP = nl.rdaddr[:4]
    49  	addr.Port = int(nl.rdxport[0])<<8 | int(nl.rdxport[1])
    50  	return &addr, nil
    51  }