tproxy_linux.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. package redir
  2. import (
  3. "encoding/binary"
  4. "net/netip"
  5. "syscall"
  6. "github.com/sagernet/sing/common/control"
  7. E "github.com/sagernet/sing/common/exceptions"
  8. M "github.com/sagernet/sing/common/metadata"
  9. "golang.org/x/sys/unix"
  10. )
  11. func TProxy(fd uintptr, isIPv6 bool) error {
  12. err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
  13. if err == nil {
  14. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
  15. }
  16. if err == nil && isIPv6 {
  17. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
  18. }
  19. if err == nil {
  20. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
  21. }
  22. if err == nil && isIPv6 {
  23. err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
  24. }
  25. return err
  26. }
  27. func TProxyWriteBack() control.Func {
  28. return func(network, address string, conn syscall.RawConn) error {
  29. return control.Raw(conn, func(fd uintptr) error {
  30. if M.ParseSocksaddr(address).Addr.Is6() {
  31. return syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
  32. } else {
  33. return syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
  34. }
  35. })
  36. }
  37. }
  38. func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
  39. controlMessages, err := unix.ParseSocketControlMessage(oob)
  40. if err != nil {
  41. return netip.AddrPort{}, err
  42. }
  43. for _, message := range controlMessages {
  44. if message.Header.Level == unix.SOL_IP && message.Header.Type == unix.IP_RECVORIGDSTADDR {
  45. return netip.AddrPortFrom(M.AddrFromIP(message.Data[4:8]), binary.BigEndian.Uint16(message.Data[2:4])), nil
  46. } else if message.Header.Level == unix.SOL_IPV6 && message.Header.Type == unix.IPV6_RECVORIGDSTADDR {
  47. return netip.AddrPortFrom(M.AddrFromIP(message.Data[8:24]), binary.BigEndian.Uint16(message.Data[2:4])), nil
  48. }
  49. }
  50. return netip.AddrPort{}, E.New("not found")
  51. }