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 2.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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. type ProxyRequest struct {
  12. Flags proxyRequestFlags
  13. ConnectionID []byte
  14. OurIPPort []byte
  15. ClientIPPort []byte
  16. ADTag []byte
  17. Options *mtproto.ConnectionOpts
  18. }
  19. func (r *ProxyRequest) MakeHeader(message []byte) (*bytes.Buffer, fmt.Stringer) {
  20. bufferLength := len(TagProxyRequest) +
  21. 4 + // len(flags)
  22. len(r.ConnectionID) +
  23. len(r.ClientIPPort) +
  24. len(r.OurIPPort) +
  25. len(ProxyRequestExtraSize) +
  26. len(ProxyRequestProxyTag) +
  27. 1 + // len(AdTag)
  28. len(r.ADTag)
  29. bufferLength += bufferLength % 4
  30. buf := &bytes.Buffer{}
  31. buf.Grow(bufferLength + len(message))
  32. flags := r.Flags
  33. if r.Options.ReadHacks.QuickAck {
  34. flags |= proxyRequestFlagsQuickAck
  35. }
  36. if bytes.HasPrefix(message, proxyRequestFlagsEncryptedPrefix[:]) {
  37. flags |= proxyRequestFlagsEncrypted
  38. }
  39. buf.Write(TagProxyRequest)
  40. buf.Write(flags.Bytes())
  41. buf.Write(r.ConnectionID)
  42. buf.Write(r.ClientIPPort)
  43. buf.Write(r.OurIPPort)
  44. buf.Write(ProxyRequestExtraSize)
  45. buf.Write(ProxyRequestProxyTag)
  46. buf.WriteByte(byte(len(r.ADTag)))
  47. buf.Write(r.ADTag)
  48. buf.Write(make([]byte, (4-buf.Len()%4)%4))
  49. return buf, flags
  50. }
  51. func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
  52. flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
  53. switch opts.ConnectionType {
  54. case mtproto.ConnectionTypeAbridged:
  55. flags |= proxyRequestFlagsAbdridged
  56. case mtproto.ConnectionTypeIntermediate:
  57. flags |= proxyRequestFlagsIntermediate
  58. }
  59. request := &ProxyRequest{
  60. Flags: flags,
  61. ADTag: adTag,
  62. Options: opts,
  63. ConnectionID: make([]byte, 8),
  64. ClientIPPort: make([]byte, 16+4),
  65. OurIPPort: make([]byte, 16+4),
  66. }
  67. if _, err := rand.Read(request.ConnectionID); err != nil {
  68. return nil, errors.Annotate(err, "Cannot generate connection ID")
  69. }
  70. port := [4]byte{}
  71. copy(request.ClientIPPort[:16], clientAddr.IP.To16())
  72. binary.LittleEndian.PutUint32(port[:], uint32(clientAddr.Port))
  73. copy(request.ClientIPPort[16:], port[:])
  74. copy(request.OurIPPort[:16], ownAddr.IP.To16())
  75. binary.LittleEndian.PutUint32(port[:], uint32(ownAddr.Port))
  76. copy(request.OurIPPort[16:], port[:])
  77. return request, nil
  78. }