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.

proxy_request.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package rpc
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "encoding/binary"
  6. "fmt"
  7. "net"
  8. "github.com/juju/errors"
  9. "github.com/9seconds/mtg/mtproto"
  10. )
  11. // ProxyRequest is the data type for storing data required to compose
  12. // RPC_PROXY_REQ request.
  13. type ProxyRequest struct {
  14. Flags proxyRequestFlags
  15. ConnectionID []byte
  16. OurIPPort []byte
  17. ClientIPPort []byte
  18. ADTag []byte
  19. Options *mtproto.ConnectionOpts
  20. }
  21. // MakeHeader makes RPC_PROXY_REQ header. We need only to append the
  22. // data for it.
  23. func (r *ProxyRequest) MakeHeader(message []byte) (*bytes.Buffer, fmt.Stringer) {
  24. bufferLength := len(TagProxyRequest) +
  25. 4 + // len(flags)
  26. len(r.ConnectionID) +
  27. len(r.ClientIPPort) +
  28. len(r.OurIPPort) +
  29. len(ProxyRequestExtraSize) +
  30. len(ProxyRequestProxyTag) +
  31. 1 + // len(AdTag)
  32. len(r.ADTag)
  33. bufferLength += bufferLength % 4
  34. buf := &bytes.Buffer{}
  35. buf.Grow(bufferLength + len(message))
  36. flags := r.Flags
  37. if r.Options.ReadHacks.QuickAck {
  38. flags |= proxyRequestFlagsQuickAck
  39. }
  40. if bytes.HasPrefix(message, proxyRequestFlagsEncryptedPrefix[:]) {
  41. flags |= proxyRequestFlagsEncrypted
  42. }
  43. buf.Write(TagProxyRequest) // nolint: gosec
  44. buf.Write(flags.Bytes()) // nolint: gosec
  45. buf.Write(r.ConnectionID) // nolint: gosec
  46. buf.Write(r.ClientIPPort) // nolint: gosec
  47. buf.Write(r.OurIPPort) // nolint: gosec
  48. buf.Write(ProxyRequestExtraSize) // nolint: gosec
  49. buf.Write(ProxyRequestProxyTag) // nolint: gosec
  50. buf.WriteByte(byte(len(r.ADTag))) // nolint: gosec
  51. buf.Write(r.ADTag) // nolint: gosec
  52. buf.Write(make([]byte, (4-buf.Len()%4)%4)) // nolint: gosec
  53. return buf, flags
  54. }
  55. // NewProxyRequest build new ProxyRequest data structure.
  56. func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr,
  57. opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
  58. flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
  59. switch opts.ConnectionType {
  60. case mtproto.ConnectionTypeAbridged:
  61. flags |= proxyRequestFlagsAbdridged
  62. case mtproto.ConnectionTypeIntermediate:
  63. flags |= proxyRequestFlagsIntermediate
  64. case mtproto.ConnectionTypeSecure:
  65. flags |= proxyRequestFlagsIntermediate | proxyRequestFlagsPad
  66. default:
  67. panic("Unknown connection type")
  68. }
  69. request := &ProxyRequest{
  70. Flags: flags,
  71. ADTag: adTag,
  72. Options: opts,
  73. ConnectionID: make([]byte, 8),
  74. ClientIPPort: make([]byte, 16+4),
  75. OurIPPort: make([]byte, 16+4),
  76. }
  77. if _, err := rand.Read(request.ConnectionID); err != nil {
  78. return nil, errors.Annotate(err, "Cannot generate connection ID")
  79. }
  80. port := [4]byte{}
  81. copy(request.ClientIPPort[:16], clientAddr.IP.To16())
  82. binary.LittleEndian.PutUint32(port[:], uint32(clientAddr.Port))
  83. copy(request.ClientIPPort[16:], port[:])
  84. copy(request.OurIPPort[:16], ownAddr.IP.To16())
  85. binary.LittleEndian.PutUint32(port[:], uint32(ownAddr.Port))
  86. copy(request.OurIPPort[16:], port[:])
  87. return request, nil
  88. }