Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

client_hello.go 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package faketls
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "crypto/subtle"
  6. "encoding/binary"
  7. "fmt"
  8. "time"
  9. "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
  10. )
  11. type ClientHello struct {
  12. Time time.Time
  13. Random [RandomLen]byte
  14. SessionID []byte
  15. Host string
  16. CipherSuite uint16
  17. }
  18. func (c ClientHello) Valid(hostname string, tolerateTimeSkewness time.Duration) error {
  19. if c.Host != "" && c.Host != hostname {
  20. return fmt.Errorf("incorrect hostname %s", hostname)
  21. }
  22. now := time.Now()
  23. timeDiff := now.Sub(c.Time)
  24. if timeDiff < 0 {
  25. timeDiff = -timeDiff
  26. }
  27. if timeDiff > tolerateTimeSkewness {
  28. return fmt.Errorf("incorrect timestamp. got=%d, now=%d, diff=%s",
  29. c.Time.Unix(), now.Unix(), timeDiff.String())
  30. }
  31. return nil
  32. }
  33. func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
  34. hello := ClientHello{}
  35. if len(handshake) < ClientHelloMinLen {
  36. return hello, fmt.Errorf("lengh of handshake is too small: %d", len(handshake))
  37. }
  38. if handshake[0] != HandshakeTypeClient {
  39. return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
  40. }
  41. handshakeSizeBytes := [4]byte{0, handshake[1], handshake[2], handshake[3]}
  42. handshakeLength := binary.BigEndian.Uint32(handshakeSizeBytes[:])
  43. if len(handshake)-4 != int(handshakeLength) {
  44. return hello,
  45. fmt.Errorf("incorrect handshake size. manifested=%d, real=%d",
  46. handshakeLength, len(handshake)-4)
  47. }
  48. copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
  49. copy(handshake[ClientHelloRandomOffset:], clientHelloEmptyRandom)
  50. rec := record.AcquireRecord()
  51. defer record.ReleaseRecord(rec)
  52. rec.Type = record.TypeHandshake
  53. rec.Version = record.Version10
  54. rec.Payload.Write(handshake)
  55. // mac is calculated for the whole record, not only
  56. // for the payload part
  57. mac := hmac.New(sha256.New, secret)
  58. rec.Dump(mac) //nolint: errcheck
  59. computedRandom := mac.Sum(nil)
  60. for i := range RandomLen {
  61. computedRandom[i] ^= hello.Random[i]
  62. }
  63. if subtle.ConstantTimeCompare(clientHelloEmptyRandom[:RandomLen-4], computedRandom[:RandomLen-4]) != 1 {
  64. return hello, ErrBadDigest
  65. }
  66. timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
  67. hello.Time = time.Unix(timestamp, 0)
  68. parseSessionID(&hello, handshake)
  69. parseCipherSuite(&hello, handshake)
  70. parseSNI(&hello, handshake)
  71. return hello, nil
  72. }
  73. func parseSessionID(hello *ClientHello, handshake []byte) {
  74. hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
  75. copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
  76. }
  77. func parseCipherSuite(hello *ClientHello, handshake []byte) {
  78. cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3
  79. hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
  80. }
  81. func parseSNI(hello *ClientHello, handshake []byte) {
  82. cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 1
  83. handshake = handshake[cipherSuiteOffset:]
  84. cipherSuiteLength := binary.BigEndian.Uint16(handshake[:2])
  85. handshake = handshake[2+cipherSuiteLength:]
  86. compressionMethodsLength := int(handshake[0])
  87. handshake = handshake[1+compressionMethodsLength:]
  88. extensionsLength := binary.BigEndian.Uint16(handshake[:2])
  89. handshake = handshake[2 : 2+extensionsLength]
  90. for len(handshake) > 0 {
  91. if binary.BigEndian.Uint16(handshake[:2]) != ExtensionSNI {
  92. extensionsLength := binary.BigEndian.Uint16(handshake[2:4])
  93. handshake = handshake[4+extensionsLength:]
  94. continue
  95. }
  96. hostnameLength := binary.BigEndian.Uint16(handshake[7:9])
  97. handshake = handshake[9:]
  98. hello.Host = string(handshake[:int(hostnameLength)])
  99. return
  100. }
  101. }