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
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.go 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package fake
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "github.com/9seconds/mtg/v2/mtglib/internal/tls"
  9. )
  10. const (
  11. maxFragmentsCount = 10
  12. )
  13. var ErrTooManyFragments = errors.New("too many fragments")
  14. // https://datatracker.ietf.org/doc/html/rfc5246#section-6.2.1
  15. // client hello can be fragmented in a series of packets:
  16. //
  17. // Bytes on the wire:
  18. //
  19. // 16 03 01 00 F8 01 00 00 F4 03 03 [32 bytes random] [session_id] [ciphers] [SNI...]
  20. // ├─────────────┤├──────────────────────────────────────────────────────────────────┤
  21. //
  22. // TLS record Payload (248 bytes)
  23. // header (5B)
  24. //
  25. // 16 = Handshake
  26. // 03 01 = TLS 1.0 (record layer version)
  27. // 00 F8 = 248 bytes follow
  28. //
  29. // 01 = ClientHello (handshake type)
  30. // 00 00 F4 = 244 bytes of handshake body
  31. // 03 03 = TLS 1.2 (actual protocol version)
  32. // ...rest of ClientHello...
  33. //
  34. // Fragmented record look like:
  35. //
  36. // Record 1:
  37. //
  38. // 16 03 01 00 03 01 00 00
  39. // ├─────────────┤├──────┤
  40. //
  41. // TLS header 3 bytes of payload
  42. //
  43. // 16 = Handshake
  44. // 03 01 = TLS 1.0
  45. // 00 03 = only 3 bytes follow
  46. //
  47. // 01 = ClientHello type
  48. // 00 00 = first 2 bytes of the uint24 length (INCOMPLETE!)
  49. //
  50. // Record 2:
  51. // 16 03 01 00 F5 F4 03 03 [32 bytes random] [session_id] [ciphers] [SNI...]
  52. // ├─────────────┤├────────────────────────────────────────────────────────────┤
  53. //
  54. // TLS header remaining 245 bytes of payload
  55. //
  56. // 16 = Handshake
  57. // 03 01 = TLS 1.0
  58. // 00 F5 = 245 bytes follow
  59. //
  60. // F4 = last byte of uint24 length (now complete: 00 00 F4 = 244)
  61. // 03 03 = TLS 1.2
  62. // ...rest of ClientHello continues...
  63. //
  64. // So it means that there could be a series of handshake packets of different
  65. // lengths. The goal of this function is to concatenate these fragments.
  66. type fragmentedHandshakeReader struct {
  67. r io.Reader
  68. buf bytes.Buffer
  69. readFragments int
  70. }
  71. func (f *fragmentedHandshakeReader) Read(p []byte) (int, error) {
  72. if n, err := f.buf.Read(p); err == nil {
  73. return n, nil
  74. }
  75. f.buf.Reset()
  76. for f.buf.Len() == 0 {
  77. if f.readFragments > maxFragmentsCount {
  78. return 0, ErrTooManyFragments
  79. }
  80. if err := f.parseNextFragment(); err != nil {
  81. return 0, err
  82. }
  83. f.readFragments++
  84. }
  85. return f.buf.Read(p)
  86. }
  87. func (f *fragmentedHandshakeReader) parseNextFragment() error {
  88. // record_type(1) + version(2) + size(2)
  89. // 16 - type is 0x16 (handshake record)
  90. // 03 01 - protocol version is "3,1" (also known as TLS 1.0)
  91. // 00 f8 - 0xF8 (248) bytes of handshake message follows
  92. header := [1 + 2 + 2]byte{}
  93. if _, err := io.ReadFull(f.r, header[:]); err != nil {
  94. return fmt.Errorf("cannot read record header: %w", err)
  95. }
  96. if header[0] != tls.TypeHandshake {
  97. return fmt.Errorf("unexpected record type %#x", header[0])
  98. }
  99. if header[1] != 3 || header[2] != 1 {
  100. return fmt.Errorf("unexpected protocol version %#x %#x", header[1], header[2])
  101. }
  102. length := int64(binary.BigEndian.Uint16(header[3:]))
  103. _, err := io.CopyN(&f.buf, f.r, length)
  104. return err
  105. }
  106. func parseClientHello(r io.Reader) (*bytes.Buffer, *bytes.Buffer, error) {
  107. r = &fragmentedHandshakeReader{r: r}
  108. header := [1 + 3]byte{}
  109. if _, err := io.ReadFull(r, header[:]); err != nil {
  110. return nil, nil, fmt.Errorf("cannot read handshake header: %w", err)
  111. }
  112. if header[0] != TypeHandshakeClient {
  113. return nil, nil, fmt.Errorf("incorrect handshake type: %#x", header[0])
  114. }
  115. // unfortunately there is not uint24 in golang, so we just reuse header
  116. header[0] = 0
  117. length := int64(binary.BigEndian.Uint32(header[:]))
  118. clientHelloCopy := &bytes.Buffer{}
  119. clientHelloCopy.Write([]byte{tls.TypeHandshake, 3, 1})
  120. binary.Write( //nolint: errcheck
  121. clientHelloCopy,
  122. binary.BigEndian,
  123. // 1 for handshake type
  124. // 3 for handshake length
  125. uint16(1+3+length),
  126. )
  127. clientHelloCopy.WriteByte(TypeHandshakeClient)
  128. clientHelloCopy.Write(header[1:])
  129. handshakeCopy := &bytes.Buffer{}
  130. writer := io.MultiWriter(clientHelloCopy, handshakeCopy)
  131. _, err := io.CopyN(writer, r, length)
  132. return clientHelloCopy, handshakeCopy, err
  133. }