tlsping.go 3.1 KB

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