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.0KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package rpc
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "encoding/binary"
  6. "net"
  7. "github.com/juju/errors"
  8. "github.com/9seconds/mtg/mtproto"
  9. )
  10. type ProxyRequest struct {
  11. Flags proxyRequestFlags
  12. ConnectionID []byte
  13. OurIPPort []byte
  14. ClientIPPort []byte
  15. ADTag []byte
  16. Options *mtproto.ConnectionOpts
  17. }
  18. func (r *ProxyRequest) Bytes(message []byte) []byte {
  19. buf := &bytes.Buffer{}
  20. flags := r.Flags
  21. if r.Options.QuickAck {
  22. flags |= proxyRequestFlagsQuickAck
  23. }
  24. if bytes.HasPrefix(message, proxyRequestFlagsEncryptedPrefix[:]) {
  25. flags |= proxyRequestFlagsEncrypted
  26. }
  27. buf.Write(TagProxyRequest)
  28. buf.Write(flags.Bytes())
  29. buf.Write(r.ConnectionID)
  30. buf.Write(r.ClientIPPort)
  31. buf.Write(r.OurIPPort)
  32. buf.Write(ProxyRequestExtraSize)
  33. buf.Write(ProxyRequestProxyTag)
  34. buf.WriteByte(byte(len(r.ADTag)))
  35. buf.Write(r.ADTag)
  36. buf.Write(make([]byte, (4-buf.Len()%4)%4))
  37. buf.Write(message)
  38. return buf.Bytes()
  39. }
  40. func NewProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*ProxyRequest, error) {
  41. flags := proxyRequestFlagsHasAdTag | proxyRequestFlagsMagic | proxyRequestFlagsExtMode2
  42. switch opts.ConnectionType {
  43. case mtproto.ConnectionTypeAbridged:
  44. flags |= proxyRequestFlagsAbdridged
  45. case mtproto.ConnectionTypeIntermediate:
  46. flags |= proxyRequestFlagsIntermediate
  47. }
  48. request := &ProxyRequest{
  49. Flags: flags,
  50. ADTag: adTag,
  51. Options: opts,
  52. ConnectionID: make([]byte, 8),
  53. ClientIPPort: make([]byte, 16+4),
  54. OurIPPort: make([]byte, 16+4),
  55. }
  56. if _, err := rand.Read(request.ConnectionID); err != nil {
  57. return nil, errors.Annotate(err, "Cannot generate connection ID")
  58. }
  59. port := [4]byte{}
  60. copy(request.ClientIPPort[:16], clientAddr.IP.To16())
  61. binary.LittleEndian.PutUint32(port[:], uint32(clientAddr.Port))
  62. copy(request.ClientIPPort[16:], port[:])
  63. copy(request.OurIPPort[:16], ownAddr.IP.To16())
  64. binary.LittleEndian.PutUint32(port[:], uint32(ownAddr.Port))
  65. copy(request.OurIPPort[16:], port[:])
  66. return request, nil
  67. }