redir_linux.go 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. package redir
  2. import (
  3. "encoding/binary"
  4. "net"
  5. "net/netip"
  6. "os"
  7. "syscall"
  8. "github.com/sagernet/sing/common"
  9. "github.com/sagernet/sing/common/control"
  10. M "github.com/sagernet/sing/common/metadata"
  11. )
  12. func GetOriginalDestination(conn net.Conn) (destination netip.AddrPort, err error) {
  13. syscallConn, ok := common.Cast[syscall.Conn](conn)
  14. if !ok {
  15. return netip.AddrPort{}, os.ErrInvalid
  16. }
  17. err = control.Conn(syscallConn, func(fd uintptr) error {
  18. const SO_ORIGINAL_DST = 80
  19. if conn.RemoteAddr().(*net.TCPAddr).IP.To4() != nil {
  20. raw, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
  21. if err != nil {
  22. return err
  23. }
  24. destination = netip.AddrPortFrom(M.AddrFromIP(raw.Multiaddr[4:8]), uint16(raw.Multiaddr[2])<<8+uint16(raw.Multiaddr[3]))
  25. } else {
  26. raw, err := syscall.GetsockoptIPv6MTUInfo(int(fd), syscall.IPPROTO_IPV6, SO_ORIGINAL_DST)
  27. if err != nil {
  28. return err
  29. }
  30. var port [2]byte
  31. binary.BigEndian.PutUint16(port[:], raw.Addr.Port)
  32. destination = netip.AddrPortFrom(M.AddrFromIP(raw.Addr.Addr[:]), binary.LittleEndian.Uint16(port[:]))
  33. }
  34. return nil
  35. })
  36. return
  37. }