Hunter0x7c7
2022-08-11 b8230139fb40edea387617b6accd8371e37eda58
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package tls
 
import (
    "crypto/tls"
    "crypto/x509"
    "encoding/base64"
    "fmt"
    "net"
 
    "github.com/v2fly/v2ray-core/v5/main/commands/base"
    v2tls "github.com/v2fly/v2ray-core/v5/transport/internet/tls"
)
 
// cmdPing is the tls ping command
var cmdPing = &base.Command{
    UsageLine: "{{.Exec}} tls ping [-ip <ip>] <domain>",
    Short:     "ping the domain with TLS handshake",
    Long: `
Ping the domain with TLS handshake.
 
Arguments:
 
    -ip <ip>
        The IP address of the domain.
`,
}
 
func init() {
    cmdPing.Run = executePing // break init loop
}
 
var pingIPStr = cmdPing.Flag.String("ip", "", "")
 
func executePing(cmd *base.Command, args []string) {
    if cmdPing.Flag.NArg() < 1 {
        base.Fatalf("domain not specified")
    }
 
    domain := cmdPing.Flag.Arg(0)
    fmt.Println("Tls ping: ", domain)
 
    var ip net.IP
    if len(*pingIPStr) > 0 {
        v := net.ParseIP(*pingIPStr)
        if v == nil {
            base.Fatalf("invalid IP: %s", *pingIPStr)
        }
        ip = v
    } else {
        v, err := net.ResolveIPAddr("ip", domain)
        if err != nil {
            base.Fatalf("Failed to resolve IP: %s", err)
        }
        ip = v.IP
    }
    fmt.Println("Using IP: ", ip.String())
 
    fmt.Println("-------------------")
    fmt.Println("Pinging without SNI")
    {
        tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
        if err != nil {
            base.Fatalf("Failed to dial tcp: %s", err)
        }
        tlsConn := tls.Client(tcpConn, &tls.Config{
            InsecureSkipVerify: true,
            NextProtos:         []string{"http/1.1"},
            MaxVersion:         tls.VersionTLS12,
            MinVersion:         tls.VersionTLS12,
            // Do not release tool before v5's refactor
            // VerifyPeerCertificate: showCert(),
        })
        err = tlsConn.Handshake()
        if err != nil {
            fmt.Println("Handshake failure: ", err)
        } else {
            fmt.Println("Handshake succeeded")
            printCertificates(tlsConn.ConnectionState().PeerCertificates)
        }
        tlsConn.Close()
    }
 
    fmt.Println("-------------------")
    fmt.Println("Pinging with SNI")
    {
        tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
        if err != nil {
            base.Fatalf("Failed to dial tcp: %s", err)
        }
        tlsConn := tls.Client(tcpConn, &tls.Config{
            ServerName: domain,
            NextProtos: []string{"http/1.1"},
            MaxVersion: tls.VersionTLS12,
            MinVersion: tls.VersionTLS12,
            // Do not release tool before v5's refactor
            // VerifyPeerCertificate: showCert(),
        })
        err = tlsConn.Handshake()
        if err != nil {
            fmt.Println("handshake failure: ", err)
        } else {
            fmt.Println("handshake succeeded")
            printCertificates(tlsConn.ConnectionState().PeerCertificates)
        }
        tlsConn.Close()
    }
 
    fmt.Println("Tls ping finished")
}
 
func printCertificates(certs []*x509.Certificate) {
    for _, cert := range certs {
        if len(cert.DNSNames) == 0 {
            continue
        }
        fmt.Println("Allowed domains: ", cert.DNSNames)
    }
}
 
func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
    return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
        hash := v2tls.GenerateCertChainHash(rawCerts)
        fmt.Println("Certificate Chain Hash: ", base64.StdEncoding.EncodeToString(hash))
        return nil
    }
}