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
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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