github.com/v2fly/v2ray-core/v4@v4.45.2/infra/control/tlsping.go (about)

     1  package control
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"encoding/base64"
     7  	"flag"
     8  	"fmt"
     9  	"net"
    10  
    11  	"github.com/v2fly/v2ray-core/v4/common"
    12  	v2tls "github.com/v2fly/v2ray-core/v4/transport/internet/tls"
    13  )
    14  
    15  type TLSPingCommand struct{}
    16  
    17  func (c *TLSPingCommand) Name() string {
    18  	return "tlsping"
    19  }
    20  
    21  func (c *TLSPingCommand) Description() Description {
    22  	return Description{
    23  		Short: "Ping the domain with TLS handshake",
    24  		Usage: []string{"v2ctl tlsping <domain> --ip <ip>"},
    25  	}
    26  }
    27  
    28  func printCertificates(certs []*x509.Certificate) {
    29  	for _, cert := range certs {
    30  		if len(cert.DNSNames) == 0 {
    31  			continue
    32  		}
    33  		fmt.Println("Allowed domains: ", cert.DNSNames)
    34  	}
    35  }
    36  
    37  func (c *TLSPingCommand) Execute(args []string) error {
    38  	fs := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
    39  	ipStr := fs.String("ip", "", "IP address of the domain")
    40  
    41  	if err := fs.Parse(args); err != nil {
    42  		return newError("flag parsing").Base(err)
    43  	}
    44  
    45  	if fs.NArg() < 1 {
    46  		return newError("domain not specified")
    47  	}
    48  
    49  	domain := fs.Arg(0)
    50  	fmt.Println("Tls ping: ", domain)
    51  
    52  	var ip net.IP
    53  	if len(*ipStr) > 0 {
    54  		v := net.ParseIP(*ipStr)
    55  		if v == nil {
    56  			return newError("invalid IP: ", *ipStr)
    57  		}
    58  		ip = v
    59  	} else {
    60  		v, err := net.ResolveIPAddr("ip", domain)
    61  		if err != nil {
    62  			return newError("resolve IP").Base(err)
    63  		}
    64  		ip = v.IP
    65  	}
    66  	fmt.Println("Using IP: ", ip.String())
    67  
    68  	fmt.Println("-------------------")
    69  	fmt.Println("Pinging without SNI")
    70  	{
    71  		tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
    72  		if err != nil {
    73  			return newError("dial tcp").Base(err)
    74  		}
    75  		tlsConn := tls.Client(tcpConn, &tls.Config{
    76  			InsecureSkipVerify: true,
    77  			NextProtos:         []string{"http/1.1"},
    78  			MaxVersion:         tls.VersionTLS12,
    79  			MinVersion:         tls.VersionTLS12,
    80  			// Do not release tool before v5's refactor
    81  			// VerifyPeerCertificate: showCert(),
    82  		})
    83  		err = tlsConn.Handshake()
    84  		if err != nil {
    85  			fmt.Println("Handshake failure: ", err)
    86  		} else {
    87  			fmt.Println("Handshake succeeded")
    88  			printCertificates(tlsConn.ConnectionState().PeerCertificates)
    89  		}
    90  		tlsConn.Close()
    91  	}
    92  
    93  	fmt.Println("-------------------")
    94  	fmt.Println("Pinging with SNI")
    95  	{
    96  		tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: 443})
    97  		if err != nil {
    98  			return newError("dial tcp").Base(err)
    99  		}
   100  		tlsConn := tls.Client(tcpConn, &tls.Config{
   101  			ServerName: domain,
   102  			NextProtos: []string{"http/1.1"},
   103  			MaxVersion: tls.VersionTLS12,
   104  			MinVersion: tls.VersionTLS12,
   105  			// Do not release tool before v5's refactor
   106  			// VerifyPeerCertificate: showCert(),
   107  		})
   108  		err = tlsConn.Handshake()
   109  		if err != nil {
   110  			fmt.Println("handshake failure: ", err)
   111  		} else {
   112  			fmt.Println("handshake succeeded")
   113  			printCertificates(tlsConn.ConnectionState().PeerCertificates)
   114  		}
   115  		tlsConn.Close()
   116  	}
   117  
   118  	fmt.Println("Tls ping finished")
   119  
   120  	return nil
   121  }
   122  
   123  func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
   124  	return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
   125  		hash := v2tls.GenerateCertChainHash(rawCerts)
   126  		fmt.Println("Certificate Chain Hash: ", base64.StdEncoding.EncodeToString(hash))
   127  		return nil
   128  	}
   129  }
   130  
   131  func init() {
   132  	common.Must(RegisterCommand(&TLSPingCommand{}))
   133  }