u_roller.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package tls
  2. import (
  3. "net"
  4. "sync"
  5. "time"
  6. )
  7. type Roller struct {
  8. HelloIDs []ClientHelloID
  9. HelloIDMu sync.Mutex
  10. WorkingHelloID *ClientHelloID
  11. TcpDialTimeout time.Duration
  12. TlsHandshakeTimeout time.Duration
  13. r *prng
  14. }
  15. // NewRoller creates Roller object with default range of HelloIDs to cycle through until a
  16. // working/unblocked one is found.
  17. func NewRoller() (*Roller, error) {
  18. r, err := newPRNG()
  19. if err != nil {
  20. return nil, err
  21. }
  22. tcpDialTimeoutInc := r.Intn(14)
  23. tcpDialTimeoutInc = 7 + tcpDialTimeoutInc
  24. tlsHandshakeTimeoutInc := r.Intn(20)
  25. tlsHandshakeTimeoutInc = 11 + tlsHandshakeTimeoutInc
  26. return &Roller{
  27. HelloIDs: []ClientHelloID{
  28. HelloChrome_Auto,
  29. HelloFirefox_Auto,
  30. HelloIOS_Auto,
  31. HelloRandomized,
  32. },
  33. TcpDialTimeout: time.Second * time.Duration(tcpDialTimeoutInc),
  34. TlsHandshakeTimeout: time.Second * time.Duration(tlsHandshakeTimeoutInc),
  35. r: r,
  36. }, nil
  37. }
  38. // Dial attempts to establish connection to given address using different HelloIDs.
  39. // If a working HelloID is found, it is used again for subsequent Dials.
  40. // If tcp connection fails or all HelloIDs are tried, returns with last error.
  41. //
  42. // Usage examples:
  43. // Dial("tcp4", "google.com:443", "google.com")
  44. // Dial("tcp", "10.23.144.22:443", "mywebserver.org")
  45. func (c *Roller) Dial(network, addr, serverName string) (*UConn, error) {
  46. helloIDs := make([]ClientHelloID, len(c.HelloIDs))
  47. copy(helloIDs, c.HelloIDs)
  48. c.r.rand.Shuffle(len(c.HelloIDs), func(i, j int) {
  49. helloIDs[i], helloIDs[j] = helloIDs[j], helloIDs[i]
  50. })
  51. c.HelloIDMu.Lock()
  52. workingHelloId := c.WorkingHelloID // keep using same helloID, if it works
  53. c.HelloIDMu.Unlock()
  54. if workingHelloId != nil {
  55. helloIDFound := false
  56. for i, ID := range helloIDs {
  57. if ID == *workingHelloId {
  58. helloIDs[i] = helloIDs[0]
  59. helloIDs[0] = *workingHelloId // push working hello ID first
  60. helloIDFound = true
  61. break
  62. }
  63. }
  64. if !helloIDFound {
  65. helloIDs = append([]ClientHelloID{*workingHelloId}, helloIDs...)
  66. }
  67. }
  68. var tcpConn net.Conn
  69. var err error
  70. for _, helloID := range helloIDs {
  71. tcpConn, err = net.DialTimeout(network, addr, c.TcpDialTimeout)
  72. if err != nil {
  73. return nil, err // on tcp Dial failure return with error right away
  74. }
  75. client := UClient(tcpConn, nil, helloID)
  76. client.SetSNI(serverName)
  77. client.SetDeadline(time.Now().Add(c.TlsHandshakeTimeout))
  78. err = client.Handshake()
  79. client.SetDeadline(time.Time{}) // unset timeout
  80. if err != nil {
  81. continue // on tls Dial error keep trying HelloIDs
  82. }
  83. c.HelloIDMu.Lock()
  84. c.WorkingHelloID = &client.ClientHelloID
  85. c.HelloIDMu.Unlock()
  86. return client, err
  87. }
  88. return nil, err
  89. }