github.com/yaling888/clash@v1.53.0/listener/redir/tcp_darwin.go (about) 1 package redir 2 3 import ( 4 "net" 5 "syscall" 6 "unsafe" 7 8 "github.com/yaling888/clash/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 }