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
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

server.go 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package proxy
  2. import (
  3. "context"
  4. "io"
  5. "net"
  6. "sync"
  7. "github.com/juju/errors"
  8. uuid "github.com/satori/go.uuid"
  9. "go.uber.org/zap"
  10. "github.com/9seconds/mtg/config"
  11. "github.com/9seconds/mtg/obfuscated2"
  12. "github.com/9seconds/mtg/wrappers"
  13. )
  14. // Server is an insgtance of MTPROTO proxy.
  15. type Server struct {
  16. conf *config.Config
  17. logger *zap.SugaredLogger
  18. stats *Stats
  19. }
  20. // Serve does MTPROTO proxying.
  21. func (s *Server) Serve() error {
  22. lsock, err := net.Listen("tcp", s.conf.BindAddr())
  23. if err != nil {
  24. return errors.Annotate(err, "Cannot create listen socket")
  25. }
  26. for {
  27. if conn, err := lsock.Accept(); err != nil {
  28. s.logger.Warn("Cannot allocate incoming connection", "error", err)
  29. } else {
  30. go s.accept(conn)
  31. }
  32. }
  33. }
  34. func (s *Server) accept(conn net.Conn) {
  35. defer func() {
  36. s.stats.closeConnection()
  37. conn.Close() // nolint: errcheck
  38. if r := recover(); r != nil {
  39. s.logger.Errorw("Crash of accept handler", "error", r)
  40. }
  41. }()
  42. s.stats.newConnection()
  43. ctx, cancel := context.WithCancel(context.Background())
  44. socketID := uuid.NewV4().String()
  45. s.logger.Debugw("Client connected",
  46. "addr", conn.RemoteAddr().String(),
  47. "socketid", socketID,
  48. )
  49. clientConn, dc, err := s.getClientStream(ctx, cancel, conn, socketID)
  50. if err != nil {
  51. s.logger.Warnw("Cannot initialize client connection",
  52. "addr", conn.RemoteAddr().String(),
  53. "socketid", socketID,
  54. "error", err,
  55. )
  56. return
  57. }
  58. defer clientConn.Close() // nolint: errcheck
  59. tgConn, err := s.getTelegramStream(ctx, cancel, dc, socketID)
  60. if err != nil {
  61. s.logger.Warnw("Cannot initialize Telegram connection",
  62. "socketid", socketID,
  63. "error", err,
  64. )
  65. return
  66. }
  67. defer tgConn.Close() // nolint: errcheck
  68. wait := &sync.WaitGroup{}
  69. wait.Add(2)
  70. go func() {
  71. defer wait.Done()
  72. io.Copy(clientConn, tgConn) // nolint: errcheck
  73. }()
  74. go func() {
  75. defer wait.Done()
  76. io.Copy(tgConn, clientConn) // nolint: errcheck
  77. }()
  78. <-ctx.Done()
  79. wait.Wait()
  80. s.logger.Debugw("Client disconnected",
  81. "addr", conn.RemoteAddr().String(),
  82. "socketid", socketID,
  83. )
  84. }
  85. func (s *Server) getClientStream(ctx context.Context, cancel context.CancelFunc, conn net.Conn, socketID string) (io.ReadWriteCloser, int16, error) {
  86. wConn := wrappers.NewTimeoutRWC(conn, s.conf.TimeoutRead, s.conf.TimeoutWrite)
  87. wConn = wrappers.NewTrafficRWC(wConn, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
  88. frame, err := obfuscated2.ExtractFrame(wConn)
  89. if err != nil {
  90. return nil, 0, errors.Annotate(err, "Cannot create client stream")
  91. }
  92. obfs2, dc, err := obfuscated2.ParseObfuscated2ClientFrame(s.conf.Secret, frame)
  93. if err != nil {
  94. return nil, 0, errors.Annotate(err, "Cannot create client stream")
  95. }
  96. wConn = wrappers.NewLogRWC(wConn, s.logger, socketID, "client")
  97. wConn = wrappers.NewStreamCipherRWC(wConn, obfs2.Encryptor, obfs2.Decryptor)
  98. wConn = wrappers.NewCtxRWC(ctx, cancel, wConn)
  99. return wConn, dc, nil
  100. }
  101. func (s *Server) getTelegramStream(ctx context.Context, cancel context.CancelFunc, dc int16, socketID string) (io.ReadWriteCloser, error) {
  102. socket, err := dialToTelegram(dc, s.conf.TimeoutRead)
  103. if err != nil {
  104. return nil, errors.Annotate(err, "Cannot dial")
  105. }
  106. wConn := wrappers.NewTimeoutRWC(socket, s.conf.TimeoutRead, s.conf.TimeoutWrite)
  107. wConn = wrappers.NewTrafficRWC(wConn, s.stats.addIncomingTraffic, s.stats.addOutgoingTraffic)
  108. obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame()
  109. if n, err := socket.Write(frame); err != nil || n != len(frame) {
  110. return nil, errors.Annotate(err, "Cannot write hadnshake frame")
  111. }
  112. wConn = wrappers.NewLogRWC(wConn, s.logger, socketID, "telegram")
  113. wConn = wrappers.NewStreamCipherRWC(wConn, obfs2.Encryptor, obfs2.Decryptor)
  114. wConn = wrappers.NewCtxRWC(ctx, cancel, wConn)
  115. return wConn, nil
  116. }
  117. // NewServer creates new instance of MTPROTO proxy.
  118. func NewServer(conf *config.Config, logger *zap.SugaredLogger, stat *Stats) *Server {
  119. return &Server{
  120. conf: conf,
  121. logger: logger,
  122. stats: stat,
  123. }
  124. }