tproxy_linux.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package redir
  2. import (
  3. "encoding/binary"
  4. "net"
  5. "net/netip"
  6. "os"
  7. "strconv"
  8. "syscall"
  9. E "github.com/sagernet/sing/common/exceptions"
  10. F "github.com/sagernet/sing/common/format"
  11. M "github.com/sagernet/sing/common/metadata"
  12. "golang.org/x/sys/unix"
  13. )
  14. func TProxy(fd uintptr, isIPv6 bool) error {
  15. err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
  16. if err == nil {
  17. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
  18. }
  19. if err == nil && isIPv6 {
  20. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
  21. }
  22. if err == nil {
  23. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
  24. }
  25. if err == nil && isIPv6 {
  26. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
  27. }
  28. return err
  29. }
  30. func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
  31. controlMessages, err := unix.ParseSocketControlMessage(oob)
  32. if err != nil {
  33. return netip.AddrPort{}, err
  34. }
  35. for _, message := range controlMessages {
  36. if message.Header.Level == unix.SOL_IP && message.Header.Type == unix.IP_RECVORIGDSTADDR {
  37. return netip.AddrPortFrom(M.AddrFromIP(message.Data[4:8]), binary.BigEndian.Uint16(message.Data[2:4])), nil
  38. } else if message.Header.Level == unix.SOL_IPV6 && message.Header.Type == unix.IPV6_RECVORIGDSTADDR {
  39. return netip.AddrPortFrom(M.AddrFromIP(message.Data[8:24]), binary.BigEndian.Uint16(message.Data[2:4])), nil
  40. }
  41. }
  42. return netip.AddrPort{}, E.New("not found")
  43. }
  44. func DialUDP(lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
  45. rSockAddr, err := udpAddrToSockAddr(rAddr)
  46. if err != nil {
  47. return nil, err
  48. }
  49. lSockAddr, err := udpAddrToSockAddr(lAddr)
  50. if err != nil {
  51. return nil, err
  52. }
  53. fd, err := syscall.Socket(udpAddrFamily(lAddr, rAddr), syscall.SOCK_DGRAM, 0)
  54. if err != nil {
  55. return nil, err
  56. }
  57. if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
  58. syscall.Close(fd)
  59. return nil, err
  60. }
  61. if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
  62. syscall.Close(fd)
  63. return nil, err
  64. }
  65. if err = syscall.Bind(fd, lSockAddr); err != nil {
  66. syscall.Close(fd)
  67. return nil, err
  68. }
  69. if err = syscall.Connect(fd, rSockAddr); err != nil {
  70. syscall.Close(fd)
  71. return nil, err
  72. }
  73. fdFile := os.NewFile(uintptr(fd), F.ToString("net-udp-dial-", rAddr))
  74. defer fdFile.Close()
  75. c, err := net.FileConn(fdFile)
  76. if err != nil {
  77. syscall.Close(fd)
  78. return nil, err
  79. }
  80. return c.(*net.UDPConn), nil
  81. }
  82. func udpAddrToSockAddr(addr *net.UDPAddr) (syscall.Sockaddr, error) {
  83. switch {
  84. case addr.IP.To4() != nil:
  85. ip := [4]byte{}
  86. copy(ip[:], addr.IP.To4())
  87. return &syscall.SockaddrInet4{Addr: ip, Port: addr.Port}, nil
  88. default:
  89. ip := [16]byte{}
  90. copy(ip[:], addr.IP.To16())
  91. zoneID, err := strconv.ParseUint(addr.Zone, 10, 32)
  92. if err != nil {
  93. zoneID = 0
  94. }
  95. return &syscall.SockaddrInet6{Addr: ip, Port: addr.Port, ZoneId: uint32(zoneID)}, nil
  96. }
  97. }
  98. func udpAddrFamily(lAddr, rAddr *net.UDPAddr) int {
  99. if (lAddr == nil || lAddr.IP.To4() != nil) && (rAddr == nil || lAddr.IP.To4() != nil) {
  100. return syscall.AF_INET
  101. }
  102. return syscall.AF_INET6
  103. }