github.com/chwjbn/xclash@v0.2.0/listener/redir/tcp_darwin.go (about)

     1  package redir
     2  
     3  import (
     4  	"net"
     5  	"syscall"
     6  	"unsafe"
     7  
     8  	"github.com/chwjbn/xclash/transport/socks5"
     9  )
    10  
    11  func parserPacket(c net.Conn) (socks5.Addr, error) {
    12  	const (
    13  		PfInout     = 0
    14  		PfIn        = 1
    15  		PfOut       = 2
    16  		IOCOut      = 0x40000000
    17  		IOCIn       = 0x80000000
    18  		IOCInOut    = IOCIn | IOCOut
    19  		IOCPARMMask = 0x1FFF
    20  		LEN         = 4*16 + 4*4 + 4*1
    21  		// #define	_IOC(inout,group,num,len) (inout | ((len & IOCPARMMask) << 16) | ((group) << 8) | (num))
    22  		// #define	_IOWR(g,n,t)	_IOC(IOCInOut,	(g), (n), sizeof(t))
    23  		// #define DIOCNATLOOK		_IOWR('D', 23, struct pfioc_natlook)
    24  		DIOCNATLOOK = IOCInOut | ((LEN & IOCPARMMask) << 16) | ('D' << 8) | 23
    25  	)
    26  
    27  	fd, err := syscall.Open("/dev/pf", 0, syscall.O_RDONLY)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	defer syscall.Close(fd)
    32  
    33  	nl := struct { // struct pfioc_natlook
    34  		saddr, daddr, rsaddr, rdaddr       [16]byte
    35  		sxport, dxport, rsxport, rdxport   [4]byte
    36  		af, proto, protoVariant, direction uint8
    37  	}{
    38  		af:        syscall.AF_INET,
    39  		proto:     syscall.IPPROTO_TCP,
    40  		direction: PfOut,
    41  	}
    42  	saddr := c.RemoteAddr().(*net.TCPAddr)
    43  	daddr := c.LocalAddr().(*net.TCPAddr)
    44  	copy(nl.saddr[:], saddr.IP)
    45  	copy(nl.daddr[:], daddr.IP)
    46  	nl.sxport[0], nl.sxport[1] = byte(saddr.Port>>8), byte(saddr.Port)
    47  	nl.dxport[0], nl.dxport[1] = byte(daddr.Port>>8), byte(daddr.Port)
    48  
    49  	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 {
    50  		return nil, errno
    51  	}
    52  
    53  	addr := make([]byte, 1+net.IPv4len+2)
    54  	addr[0] = socks5.AtypIPv4
    55  	copy(addr[1:1+net.IPv4len], nl.rdaddr[:4])
    56  	copy(addr[1+net.IPv4len:], nl.rdxport[:2])
    57  	return addr, nil
    58  }