sockopt_linux.go 1.3 KB

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