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
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

server.go 4.4KB

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