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.go 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package packetack
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "net"
  7. "sync"
  8. "github.com/9seconds/mtg/config"
  9. "github.com/9seconds/mtg/conntypes"
  10. "github.com/9seconds/mtg/hub"
  11. "github.com/9seconds/mtg/mtproto/rpc"
  12. "github.com/9seconds/mtg/protocol"
  13. )
  14. type wrapperProxy struct {
  15. request *protocol.TelegramRequest
  16. clientIPPort []byte
  17. ourIPPort []byte
  18. channelRead hub.ChannelReadCloser
  19. closeOnce sync.Once
  20. flags rpc.ProxyRequestFlags
  21. }
  22. func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.ConnectionAcks) error {
  23. buf := bytes.Buffer{}
  24. flags := w.flags
  25. if acks.Quick {
  26. flags |= rpc.ProxyRequestFlagsQuickAck
  27. }
  28. if bytes.HasPrefix(packet, rpc.ProxyRequestFlagsEncryptedPrefix[:]) {
  29. flags |= rpc.ProxyRequestFlagsEncrypted
  30. }
  31. buf.Write(rpc.TagProxyRequest)
  32. buf.Write(flags.Bytes())
  33. buf.Write(w.request.ConnID[:])
  34. buf.Write(w.clientIPPort)
  35. buf.Write(w.ourIPPort)
  36. buf.Write(rpc.ProxyRequestExtraSize)
  37. buf.Write(rpc.ProxyRequestProxyTag)
  38. buf.WriteByte(byte(len(config.C.AdTag)))
  39. buf.Write(config.C.AdTag)
  40. buf.Write(make([]byte, (4-buf.Len()%4)%4))
  41. buf.Write(packet)
  42. return hub.Hub.Write(buf.Bytes(), w.request)
  43. }
  44. func (w *wrapperProxy) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, error) {
  45. resp, err := w.channelRead.Read()
  46. if err != nil {
  47. return nil, fmt.Errorf("cannot read a response: %w", err)
  48. }
  49. if resp.Type == rpc.ProxyResponseTypeSimpleAck {
  50. acks.Simple = true
  51. }
  52. return resp.Payload, nil
  53. }
  54. func (w *wrapperProxy) Close() error {
  55. w.closeOnce.Do(func() {
  56. w.channelRead.Close()
  57. hub.Registry.Unregister(w.request.ConnID)
  58. })
  59. return nil
  60. }
  61. func NewProxy(request *protocol.TelegramRequest) conntypes.PacketAckReadWriteCloser {
  62. flags := rpc.ProxyRequestFlagsHasAdTag | rpc.ProxyRequestFlagsMagic | rpc.ProxyRequestFlagsExtMode2
  63. switch request.ClientProtocol.ConnectionType() {
  64. case conntypes.ConnectionTypeAbridged:
  65. flags |= rpc.ProxyRequestFlagsAbdridged
  66. case conntypes.ConnectionTypeIntermediate:
  67. flags |= rpc.ProxyRequestFlagsIntermediate
  68. case conntypes.ConnectionTypeSecure:
  69. flags |= rpc.ProxyRequestFlagsIntermediate | rpc.ProxyRequestFlagsPad
  70. default:
  71. panic("unknown connection type")
  72. }
  73. return &wrapperProxy{
  74. flags: flags,
  75. request: request,
  76. channelRead: hub.Registry.Register(request.ConnID),
  77. clientIPPort: proxyGetIPPort(request.ClientConn.RemoteAddr()),
  78. ourIPPort: proxyGetIPPort(request.ClientConn.LocalAddr()),
  79. }
  80. }
  81. func proxyGetIPPort(addr *net.TCPAddr) []byte {
  82. rv := [16 + 4]byte{}
  83. port := [4]byte{}
  84. copy(rv[:16], addr.IP.To16())
  85. binary.LittleEndian.PutUint32(port[:], uint32(addr.Port))
  86. copy(rv[16:], port[:])
  87. return rv[:]
  88. }