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

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