sockopt_linux.go 1.3 KB

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