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