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 kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

middle_caller.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package telegram
  2. import (
  3. "bufio"
  4. "context"
  5. "io/ioutil"
  6. "net"
  7. "net/http"
  8. "regexp"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "time"
  13. "github.com/juju/errors"
  14. "go.uber.org/zap"
  15. "github.com/9seconds/mtg/mtproto"
  16. "github.com/9seconds/mtg/wrappers"
  17. )
  18. const (
  19. middleTelegramAutoUpdateInterval = 6 * time.Hour
  20. middleTelegramHTTPClientTimeout = 30 * time.Second
  21. tgAddrProxySecret = "https://core.telegram.org/getProxySecret" // nolint: gas
  22. tgAddrProxyV4 = "https://core.telegram.org/getProxyConfig" // nolint: gas
  23. tgAddrProxyV6 = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
  24. tgUserAgent = "mtg"
  25. )
  26. var middleTelegramProxyConfigSplitter = regexp.MustCompile(`\s+`)
  27. type middleTelegramCaller struct {
  28. baseTelegram
  29. proxySecret []byte
  30. dialerMutex *sync.RWMutex
  31. httpClient *http.Client
  32. }
  33. func (t *middleTelegramCaller) Dial(ctx context.Context, cancel context.CancelFunc, connID string,
  34. connOpts *mtproto.ConnectionOpts) (wrappers.StreamReadWriteCloser, error) {
  35. dc := connOpts.DC
  36. if dc == 0 {
  37. dc = 1
  38. }
  39. t.dialerMutex.RLock()
  40. defer t.dialerMutex.RUnlock()
  41. return t.baseTelegram.dial(ctx, cancel, dc, connID, connOpts.ConnectionProto)
  42. }
  43. func (t *middleTelegramCaller) autoUpdate() {
  44. for range time.Tick(middleTelegramAutoUpdateInterval) {
  45. if err := t.update(); err != nil {
  46. zap.S().Warnw("Cannot update from Telegram", "error", err)
  47. }
  48. }
  49. }
  50. func (t *middleTelegramCaller) update() error {
  51. secret, err := t.getTelegramProxySecret()
  52. if err != nil {
  53. return errors.Annotate(err, "Cannot get proxy secret")
  54. }
  55. v4Addresses, v4DefaultIdx, err := t.getTelegramAddresses(tgAddrProxyV4)
  56. if err != nil {
  57. return errors.Annotate(err, "Cannot get ipv4 addresses")
  58. }
  59. v6Addresses, v6DefaultIdx, err := t.getTelegramAddresses(tgAddrProxyV6)
  60. if err != nil {
  61. return errors.Annotate(err, "Cannot get ipv6 addresses")
  62. }
  63. t.dialerMutex.Lock()
  64. t.proxySecret = secret
  65. t.v4DefaultIdx = v4DefaultIdx
  66. t.v6DefaultIdx = v6DefaultIdx
  67. t.v4Addresses = v4Addresses
  68. t.v6Addresses = v6Addresses
  69. t.dialerMutex.Unlock()
  70. zap.S().Infow("Telegram middle proxy data has been updated")
  71. return nil
  72. }
  73. func (t *middleTelegramCaller) getTelegramProxySecret() ([]byte, error) {
  74. resp, err := t.call(tgAddrProxySecret)
  75. if err != nil {
  76. return nil, errors.Annotate(err, "Cannot access telegram server")
  77. }
  78. defer resp.Body.Close() // nolint: errcheck
  79. secret, err := ioutil.ReadAll(resp.Body)
  80. if err != nil {
  81. return nil, errors.Annotate(err, "Cannot read response")
  82. }
  83. return secret, nil
  84. }
  85. func (t *middleTelegramCaller) getTelegramAddresses(url string) (map[int16][]string, int16, error) { // nolint: gocyclo
  86. resp, err := t.call(url)
  87. if err != nil {
  88. return nil, 0, errors.Annotate(err, "Cannot access telegram server")
  89. }
  90. defer resp.Body.Close() // nolint: errcheck
  91. scanner := bufio.NewScanner(resp.Body)
  92. data := map[int16][]string{}
  93. var defaultIdx int16 = 1
  94. for scanner.Scan() {
  95. text := strings.TrimSpace(scanner.Text())
  96. switch {
  97. case strings.HasPrefix(text, "#"):
  98. continue
  99. case strings.HasPrefix(text, "proxy_for"):
  100. addr, idx, err2 := t.parseProxyFor(text)
  101. if err2 != nil {
  102. return nil, 0, errors.Annotate(err2, "Cannot parse 'proxy_for' section")
  103. }
  104. if addresses, ok := data[idx]; ok {
  105. data[idx] = append(addresses, addr)
  106. } else {
  107. data[idx] = []string{addr}
  108. }
  109. case strings.HasPrefix(text, "default"):
  110. idx, err2 := t.parseDefault(text)
  111. if err2 != nil {
  112. return nil, 0, errors.Annotate(err2, "Cannot parse 'default' section")
  113. }
  114. defaultIdx = idx
  115. default:
  116. return nil, 0, errors.Errorf("Unknown config string '%s'", text)
  117. }
  118. }
  119. err = scanner.Err()
  120. if err != nil {
  121. return nil, 0, errors.Annotate(err, "Cannot read response from the telegram")
  122. }
  123. return data, defaultIdx, nil
  124. }
  125. func (t *middleTelegramCaller) parseProxyFor(text string) (string, int16, error) {
  126. chunks := middleTelegramProxyConfigSplitter.Split(text, 3)
  127. if len(chunks) != 3 || chunks[0] != "proxy_for" {
  128. return "", 0, errors.Errorf("Incorrect config '%s'", text)
  129. }
  130. dcIdx, err := strconv.ParseInt(chunks[1], 10, 16)
  131. if err != nil {
  132. return "", 0, errors.Annotatef(err, "Incorrect config '%s'", text)
  133. }
  134. addr := strings.TrimRight(chunks[2], ";")
  135. if _, _, err = net.SplitHostPort(addr); err != nil {
  136. return "", 0, errors.Annotatef(err, "Incorrect config '%s'", text)
  137. }
  138. return addr, int16(dcIdx), nil
  139. }
  140. func (t *middleTelegramCaller) parseDefault(text string) (int16, error) {
  141. chunks := middleTelegramProxyConfigSplitter.Split(text, 2)
  142. if len(chunks) != 2 || chunks[0] != "default" {
  143. return 0, errors.Errorf("Incorrect config '%s'", text)
  144. }
  145. dcIdxString := strings.TrimRight(chunks[1], ";")
  146. dcIdx, err := strconv.ParseInt(dcIdxString, 10, 16)
  147. if err != nil {
  148. return 0, errors.Annotatef(err, "Incorrect config '%s'", text)
  149. }
  150. return int16(dcIdx), nil
  151. }
  152. func (t *middleTelegramCaller) call(url string) (*http.Response, error) {
  153. req, _ := http.NewRequest("GET", url, nil) // nolint: gosec
  154. req.Header.Set("Accept", "text/plain")
  155. req.Header.Set("User-Agent", tgUserAgent)
  156. return t.httpClient.Do(req)
  157. }