ping.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package tls
  2. import (
  3. gotls "crypto/tls"
  4. "crypto/x509"
  5. "encoding/hex"
  6. "fmt"
  7. "net"
  8. "strconv"
  9. "github.com/xtls/xray-core/main/commands/base"
  10. . "github.com/xtls/xray-core/transport/internet/tls"
  11. )
  12. // cmdPing is the tls ping command
  13. var cmdPing = &base.Command{
  14. UsageLine: "{{.Exec}} tls ping [-ip <ip>] <domain>",
  15. Short: "Ping the domain with TLS handshake",
  16. Long: `
  17. Ping the domain with TLS handshake.
  18. Arguments:
  19. -ip
  20. The IP address of the domain.
  21. `,
  22. }
  23. func init() {
  24. cmdPing.Run = executePing // break init loop
  25. }
  26. var pingIPStr = cmdPing.Flag.String("ip", "", "")
  27. func executePing(cmd *base.Command, args []string) {
  28. if cmdPing.Flag.NArg() < 1 {
  29. base.Fatalf("domain not specified")
  30. }
  31. domainWithPort := cmdPing.Flag.Arg(0)
  32. fmt.Println("TLS ping: ", domainWithPort)
  33. TargetPort := 443
  34. domain, port, err := net.SplitHostPort(domainWithPort)
  35. if err != nil {
  36. domain = domainWithPort
  37. } else {
  38. TargetPort, _ = strconv.Atoi(port)
  39. }
  40. var ip net.IP
  41. if len(*pingIPStr) > 0 {
  42. v := net.ParseIP(*pingIPStr)
  43. if v == nil {
  44. base.Fatalf("invalid IP: %s", *pingIPStr)
  45. }
  46. ip = v
  47. } else {
  48. v, err := net.ResolveIPAddr("ip", domain)
  49. if err != nil {
  50. base.Fatalf("Failed to resolve IP: %s", err)
  51. }
  52. ip = v.IP
  53. }
  54. fmt.Println("Using IP: ", ip.String()+":"+strconv.Itoa(TargetPort))
  55. fmt.Println("-------------------")
  56. fmt.Println("Pinging without SNI")
  57. {
  58. tcpConn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: TargetPort})
  59. if err != nil {
  60. base.Fatalf("Failed to dial tcp: %s", err)
  61. }
  62. tlsConn := gotls.Client(tcpConn, &gotls.Config{
  63. InsecureSkipVerify: true,
  64. NextProtos: []string{"h2", "http/1.1"},
  65. MaxVersion: gotls.VersionTLS13,
  66. MinVersion: gotls.VersionTLS12,
  67. // Do not release tool before v5's refactor
  68. // VerifyPeerCertificate: showCert(),
  69. })
  70. err = tlsConn.Handshake()
  71. if err != nil {
  72. fmt.Println("Handshake failure: ", err)
  73. } else {
  74. fmt.Println("Handshake succeeded")
  75. printTLSConnDetail(tlsConn)
  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: TargetPort})
  84. if err != nil {
  85. base.Fatalf("Failed to dial tcp: %s", err)
  86. }
  87. tlsConn := gotls.Client(tcpConn, &gotls.Config{
  88. ServerName: domain,
  89. NextProtos: []string{"h2", "http/1.1"},
  90. MaxVersion: gotls.VersionTLS13,
  91. MinVersion: gotls.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. printTLSConnDetail(tlsConn)
  101. printCertificates(tlsConn.ConnectionState().PeerCertificates)
  102. }
  103. tlsConn.Close()
  104. }
  105. fmt.Println("-------------------")
  106. fmt.Println("TLS ping finished")
  107. }
  108. func printCertificates(certs []*x509.Certificate) {
  109. var leaf *x509.Certificate
  110. var length int
  111. for _, cert := range certs {
  112. length += len(cert.Raw)
  113. if len(cert.DNSNames) != 0 {
  114. leaf = cert
  115. }
  116. }
  117. fmt.Println("Certificate chain's total length: ", length, "(certs count: "+strconv.Itoa(len(certs))+")")
  118. if leaf != nil {
  119. fmt.Println("Cert's signature algorithm: ", leaf.SignatureAlgorithm.String())
  120. fmt.Println("Cert's publicKey algorithm: ", leaf.PublicKeyAlgorithm.String())
  121. fmt.Println("Cert's allowed domains: ", leaf.DNSNames)
  122. }
  123. }
  124. func printTLSConnDetail(tlsConn *gotls.Conn) {
  125. connectionState := tlsConn.ConnectionState()
  126. var tlsVersion string
  127. if connectionState.Version == gotls.VersionTLS13 {
  128. tlsVersion = "TLS 1.3"
  129. } else if connectionState.Version == gotls.VersionTLS12 {
  130. tlsVersion = "TLS 1.2"
  131. }
  132. fmt.Println("TLS Version: ", tlsVersion)
  133. curveID := connectionState.CurveID
  134. if curveID != 0 {
  135. PostQuantum := (curveID == gotls.X25519MLKEM768)
  136. fmt.Println("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")
  137. } else {
  138. fmt.Println("TLS Post-Quantum key exchange: false (RSA Exchange)")
  139. }
  140. }
  141. func showCert() func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
  142. return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
  143. var hash []byte
  144. for _, asn1Data := range rawCerts {
  145. cert, _ := x509.ParseCertificate(asn1Data)
  146. if cert.IsCA {
  147. hash = GenerateCertHash(cert)
  148. }
  149. }
  150. fmt.Println("Certificate Leaf Hash: ", hex.EncodeToString(hash))
  151. return nil
  152. }
  153. }