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.

mtproto_intermediate.go 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package wrappers
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "io"
  6. "net"
  7. "github.com/juju/errors"
  8. "go.uber.org/zap"
  9. "github.com/9seconds/mtg/mtproto"
  10. )
  11. const mtprotoIntermediateQuickAckLength = 0x80000000
  12. type MTProtoIntermediate struct {
  13. conn StreamReadWriteCloser
  14. opts *mtproto.ConnectionOpts
  15. logger *zap.SugaredLogger
  16. readCounter uint32
  17. writeCounter uint32
  18. }
  19. func (m *MTProtoIntermediate) Read() ([]byte, error) {
  20. defer func() {
  21. m.readCounter++
  22. }()
  23. m.logger.Debugw("Read packet",
  24. "simple_ack", m.opts.ReadHacks.SimpleAck,
  25. "quick_ack", m.opts.ReadHacks.QuickAck,
  26. "counter", m.readCounter,
  27. )
  28. buf := &bytes.Buffer{}
  29. buf.Grow(4)
  30. if _, err := io.CopyN(buf, m.conn, 4); err != nil {
  31. return nil, errors.Annotate(err, "Cannot read message length")
  32. }
  33. length := binary.LittleEndian.Uint32(buf.Bytes())
  34. m.logger.Debugw("Packet message length",
  35. "simple_ack", m.opts.ReadHacks.SimpleAck,
  36. "quick_ack", m.opts.ReadHacks.QuickAck,
  37. "counter", m.readCounter,
  38. "length", length,
  39. )
  40. if length > mtprotoIntermediateQuickAckLength {
  41. m.opts.ReadHacks.QuickAck = true
  42. length -= mtprotoIntermediateQuickAckLength
  43. }
  44. buf.Reset()
  45. buf.Grow(int(length))
  46. if _, err := io.CopyN(buf, m.conn, int64(length)); err != nil {
  47. return nil, errors.Annotate(err, "Cannot read the message")
  48. }
  49. if length%4 != 0 {
  50. length -= length % 4
  51. }
  52. return buf.Bytes()[:length], nil
  53. }
  54. func (m *MTProtoIntermediate) Write(p []byte) (int, error) {
  55. defer func() {
  56. m.writeCounter++
  57. }()
  58. m.logger.Debugw("Write packet",
  59. "simple_ack", m.opts.WriteHacks.SimpleAck,
  60. "quick_ack", m.opts.WriteHacks.QuickAck,
  61. "counter", m.writeCounter,
  62. )
  63. if m.opts.ReadHacks.SimpleAck {
  64. return m.conn.Write(p)
  65. }
  66. var length [4]byte
  67. binary.LittleEndian.PutUint32(length[:], uint32(len(p)))
  68. return m.conn.Write(append(length[:], p...))
  69. }
  70. func (m *MTProtoIntermediate) Logger() *zap.SugaredLogger {
  71. return m.logger
  72. }
  73. func (m *MTProtoIntermediate) LocalAddr() *net.TCPAddr {
  74. return m.conn.LocalAddr()
  75. }
  76. func (m *MTProtoIntermediate) RemoteAddr() *net.TCPAddr {
  77. return m.conn.RemoteAddr()
  78. }
  79. func (m *MTProtoIntermediate) Close() error {
  80. return m.conn.Close()
  81. }
  82. func NewMTProtoIntermediate(conn StreamReadWriteCloser, opts *mtproto.ConnectionOpts) PacketReadWriteCloser {
  83. return &MTProtoIntermediate{
  84. conn: conn,
  85. logger: conn.Logger().Named("mtproto-intermediate"),
  86. opts: opts,
  87. }
  88. }