github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/transport/internet/tcp/sockopt_linux.go (about)

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