redir_darwin.go 1.6 KB

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