sockopt_linux.go 1.8 KB

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