sockopt_linux.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // +build linux
  2. // +build !confonly
  3. package tcp
  4. import (
  5. "syscall"
  6. "github.com/v2fly/v2ray-core/v4/common/net"
  7. "github.com/v2fly/v2ray-core/v4/transport/internet"
  8. )
  9. const SO_ORIGINAL_DST = 80 // nolint: golint,stylecheck
  10. func GetOriginalDestination(conn internet.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. var remoteIP net.IP
  22. switch addr := conn.RemoteAddr().(type) {
  23. case *net.TCPAddr:
  24. remoteIP = addr.IP
  25. case *net.UDPAddr:
  26. remoteIP = addr.IP
  27. default:
  28. newError("failed to call getsockopt").WriteToLog()
  29. return
  30. }
  31. if remoteIP.To4() != nil {
  32. // ipv4
  33. addr, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
  34. if err != nil {
  35. newError("failed to call getsockopt").Base(err).WriteToLog()
  36. return
  37. }
  38. ip := net.IPAddress(addr.Multiaddr[4:8])
  39. port := uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
  40. dest = net.TCPDestination(ip, net.Port(port))
  41. } else {
  42. // ipv6
  43. addr, err := syscall.GetsockoptIPv6MTUInfo(int(fd), syscall.IPPROTO_IPV6, SO_ORIGINAL_DST)
  44. if err != nil {
  45. newError("failed to call getsockopt").Base(err).WriteToLog()
  46. return
  47. }
  48. ip := net.IPAddress(addr.Addr.Addr[:])
  49. port := net.PortFromBytes([]byte{byte(addr.Addr.Port), byte(addr.Addr.Port >> 8)})
  50. dest = net.TCPDestination(ip, port)
  51. }
  52. })
  53. if err != nil {
  54. return net.Destination{}, newError("failed to control connection").Base(err)
  55. }
  56. if !dest.IsValid() {
  57. return net.Destination{}, newError("failed to call getsockopt")
  58. }
  59. return dest, nil
  60. }