utls.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package tls
  2. import (
  3. "crypto/tls"
  4. "net"
  5. "github.com/metacubex/mihomo/log"
  6. utls "github.com/metacubex/utls"
  7. "github.com/mroth/weightedrand/v2"
  8. )
  9. type UConn struct {
  10. *utls.UConn
  11. }
  12. type UClientHelloID struct {
  13. *utls.ClientHelloID
  14. }
  15. var initRandomFingerprint UClientHelloID
  16. var initUtlsClient string
  17. func UClient(c net.Conn, config *tls.Config, fingerprint UClientHelloID) *UConn {
  18. utlsConn := utls.UClient(c, copyConfig(config), utls.ClientHelloID{
  19. Client: fingerprint.Client,
  20. Version: fingerprint.Version,
  21. Seed: fingerprint.Seed,
  22. })
  23. return &UConn{UConn: utlsConn}
  24. }
  25. func GetFingerprint(ClientFingerprint string) (UClientHelloID, bool) {
  26. if ClientFingerprint == "none" {
  27. return UClientHelloID{}, false
  28. }
  29. if initRandomFingerprint.ClientHelloID == nil {
  30. initRandomFingerprint, _ = RollFingerprint()
  31. }
  32. if ClientFingerprint == "random" {
  33. log.Debugln("use initial random HelloID:%s", initRandomFingerprint.Client)
  34. return initRandomFingerprint, true
  35. }
  36. fingerprint, ok := Fingerprints[ClientFingerprint]
  37. if ok {
  38. log.Debugln("use specified fingerprint:%s", fingerprint.Client)
  39. return fingerprint, ok
  40. } else {
  41. log.Warnln("wrong ClientFingerprint:%s", ClientFingerprint)
  42. return UClientHelloID{}, false
  43. }
  44. }
  45. func RollFingerprint() (UClientHelloID, bool) {
  46. chooser, _ := weightedrand.NewChooser(
  47. weightedrand.NewChoice("chrome", 6),
  48. weightedrand.NewChoice("safari", 3),
  49. weightedrand.NewChoice("ios", 2),
  50. weightedrand.NewChoice("firefox", 1),
  51. )
  52. initClient := chooser.Pick()
  53. log.Debugln("initial random HelloID:%s", initClient)
  54. fingerprint, ok := Fingerprints[initClient]
  55. return fingerprint, ok
  56. }
  57. var Fingerprints = map[string]UClientHelloID{
  58. "chrome": {&utls.HelloChrome_Auto},
  59. "chrome_psk": {&utls.HelloChrome_100_PSK},
  60. "chrome_psk_shuffle": {&utls.HelloChrome_106_Shuffle},
  61. "chrome_padding_psk_shuffle": {&utls.HelloChrome_114_Padding_PSK_Shuf},
  62. "chrome_pq": {&utls.HelloChrome_115_PQ},
  63. "chrome_pq_psk": {&utls.HelloChrome_115_PQ_PSK},
  64. "firefox": {&utls.HelloFirefox_Auto},
  65. "safari": {&utls.HelloSafari_Auto},
  66. "ios": {&utls.HelloIOS_Auto},
  67. "android": {&utls.HelloAndroid_11_OkHttp},
  68. "edge": {&utls.HelloEdge_Auto},
  69. "360": {&utls.Hello360_Auto},
  70. "qq": {&utls.HelloQQ_Auto},
  71. "random": {nil},
  72. "randomized": {nil},
  73. }
  74. func init() {
  75. weights := utls.DefaultWeights
  76. weights.TLSVersMax_Set_VersionTLS13 = 1
  77. weights.FirstKeyShare_Set_CurveP256 = 0
  78. randomized := utls.HelloRandomized
  79. randomized.Seed, _ = utls.NewPRNGSeed()
  80. randomized.Weights = &weights
  81. Fingerprints["randomized"] = UClientHelloID{&randomized}
  82. }
  83. func copyConfig(c *tls.Config) *utls.Config {
  84. return &utls.Config{
  85. RootCAs: c.RootCAs,
  86. ServerName: c.ServerName,
  87. InsecureSkipVerify: c.InsecureSkipVerify,
  88. VerifyPeerCertificate: c.VerifyPeerCertificate,
  89. }
  90. }
  91. // BuildWebsocketHandshakeState it will only send http/1.1 in its ALPN.
  92. // Copy from https://github.com/XTLS/Xray-core/blob/main/transport/internet/tls/tls.go
  93. func (c *UConn) BuildWebsocketHandshakeState() error {
  94. // Build the handshake state. This will apply every variable of the TLS of the
  95. // fingerprint in the UConn
  96. if err := c.BuildHandshakeState(); err != nil {
  97. return err
  98. }
  99. // Iterate over extensions and check for utls.ALPNExtension
  100. hasALPNExtension := false
  101. for _, extension := range c.Extensions {
  102. if alpn, ok := extension.(*utls.ALPNExtension); ok {
  103. hasALPNExtension = true
  104. alpn.AlpnProtocols = []string{"http/1.1"}
  105. break
  106. }
  107. }
  108. if !hasALPNExtension { // Append extension if doesn't exists
  109. c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}})
  110. }
  111. // Rebuild the client hello
  112. if err := c.BuildHandshakeState(); err != nil {
  113. return err
  114. }
  115. return nil
  116. }
  117. func SetGlobalUtlsClient(Client string) {
  118. initUtlsClient = Client
  119. }
  120. func HaveGlobalFingerprint() bool {
  121. return len(initUtlsClient) != 0 && initUtlsClient != "none"
  122. }
  123. func GetGlobalFingerprint() string {
  124. return initUtlsClient
  125. }