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 }