github.com/EagleQL/Xray-core@v1.4.3/transport/internet/tcp/sockopt_linux.go (about)

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