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