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.

rpc_proxy_request.go 2.3KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. const (
  11. rpcProxyRequestConnectionIDLength = 8
  12. rpcProxyRequestIPPortLength = 16 + 4
  13. )
  14. var (
  15. rpcProxyRequestTag = []byte{0xee, 0xf1, 0xce, 0x36}
  16. rpcProxyRequestExtraSize = []byte{0x18, 0x00, 0x00, 0x00}
  17. rpcProxyRequestProxyTag = []byte{0xae, 0x26, 0x1e, 0xdb}
  18. )
  19. type RPCProxyRequest struct {
  20. Flags RPCProxyRequestFlags
  21. ConnectionID [rpcProxyRequestConnectionIDLength]byte
  22. OurIPPort [rpcProxyRequestIPPortLength]byte
  23. ClientIPPort [rpcProxyRequestIPPortLength]byte
  24. ADTag []byte
  25. Options *mtproto.ConnectionOpts
  26. }
  27. func (r *RPCProxyRequest) Bytes(message []byte) []byte {
  28. buf := &bytes.Buffer{}
  29. flags := r.Flags
  30. if r.Options.QuickAck {
  31. flags |= RPCProxyRequestFlagsQuickAck
  32. }
  33. if bytes.HasPrefix(message, rpcProxyRequestFlagsEncryptedPrefix[:]) {
  34. flags |= RPCProxyRequestFlagsEncrypted
  35. }
  36. buf.Write(rpcProxyRequestTag)
  37. buf.Write(flags.Bytes())
  38. buf.Write(r.ConnectionID[:])
  39. buf.Write(r.ClientIPPort[:])
  40. buf.Write(r.OurIPPort[:])
  41. buf.Write(rpcProxyRequestExtraSize)
  42. buf.Write(rpcProxyRequestProxyTag)
  43. buf.WriteByte(byte(len(r.ADTag)))
  44. buf.Write(r.ADTag)
  45. buf.Write(bytes.Repeat([]byte{0x00}, buf.Len()%4))
  46. buf.Write(message)
  47. return buf.Bytes()
  48. }
  49. func NewRPCProxyRequest(clientAddr, ownAddr *net.TCPAddr, opts *mtproto.ConnectionOpts, adTag []byte) (*RPCProxyRequest, error) {
  50. flags := RPCProxyRequestFlagsHasAdTag | RPCProxyRequestFlagsMagic | RPCProxyRequestFlagsExtMode2
  51. switch opts.ConnectionType {
  52. case mtproto.ConnectionTypeAbridged:
  53. flags |= RPCProxyRequestFlagsAbdridged
  54. case mtproto.ConnectionTypeIntermediate:
  55. flags |= RPCProxyRequestFlagsIntermediate
  56. }
  57. request := RPCProxyRequest{
  58. Flags: flags,
  59. ADTag: adTag,
  60. Options: opts,
  61. }
  62. if _, err := rand.Read(request.ConnectionID[:]); err != nil {
  63. return nil, errors.Annotate(err, "Cannot generate connection ID")
  64. }
  65. port := make([]byte, 4)
  66. copy(request.ClientIPPort[:16], clientAddr.IP.To16())
  67. binary.LittleEndian.PutUint32(port, uint32(clientAddr.Port))
  68. copy(request.ClientIPPort[16:], port)
  69. copy(request.OurIPPort[:16], ownAddr.IP.To16())
  70. binary.LittleEndian.PutUint32(port, uint32(ownAddr.Port))
  71. copy(request.OurIPPort[16:], port)
  72. return &request, nil
  73. }