sockopt_linux.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. //go:build linux
  2. // +build linux
  3. package tcp
  4. import (
  5. "context"
  6. "syscall"
  7. "unsafe"
  8. "github.com/xtls/xray-core/common/errors"
  9. "github.com/xtls/xray-core/common/net"
  10. "github.com/xtls/xray-core/transport/internet/stat"
  11. )
  12. const SO_ORIGINAL_DST = 80
  13. func GetOriginalDestination(conn stat.Connection) (net.Destination, error) {
  14. sysrawconn, f := conn.(syscall.Conn)
  15. if !f {
  16. return net.Destination{}, errors.New("unable to get syscall.Conn")
  17. }
  18. rawConn, err := sysrawconn.SyscallConn()
  19. if err != nil {
  20. return net.Destination{}, errors.New("failed to get sys fd").Base(err)
  21. }
  22. var dest net.Destination
  23. err = rawConn.Control(func(fd uintptr) {
  24. level := syscall.IPPROTO_IP
  25. if conn.RemoteAddr().String()[0] == '[' {
  26. level = syscall.IPPROTO_IPV6
  27. }
  28. addr, err := syscall.GetsockoptIPv6MTUInfo(int(fd), level, SO_ORIGINAL_DST)
  29. if err != nil {
  30. errors.LogInfoInner(context.Background(), err, "failed to call getsockopt")
  31. return
  32. }
  33. ip := (*[4]byte)(unsafe.Pointer(&addr.Addr.Flowinfo))[:4]
  34. if level == syscall.IPPROTO_IPV6 {
  35. ip = addr.Addr.Addr[:]
  36. }
  37. port := (*[2]byte)(unsafe.Pointer(&addr.Addr.Port))[:2]
  38. dest = net.TCPDestination(net.IPAddress(ip), net.PortFromBytes(port))
  39. })
  40. if err != nil {
  41. return net.Destination{}, errors.New("failed to control connection").Base(err)
  42. }
  43. if !dest.IsValid() {
  44. return net.Destination{}, errors.New("failed to call getsockopt")
  45. }
  46. return dest, nil
  47. }