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 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package config
  2. import (
  3. "bytes"
  4. "encoding/hex"
  5. "fmt"
  6. "net"
  7. "strconv"
  8. "github.com/juju/errors"
  9. statsd "gopkg.in/alexcesaro/statsd.v2"
  10. )
  11. // Config represents common configuration of mtg.
  12. type Config struct {
  13. Debug bool
  14. Verbose bool
  15. SecureMode bool
  16. ReadBufferSize int
  17. WriteBufferSize int
  18. BindPort uint16
  19. PublicIPv4Port uint16
  20. PublicIPv6Port uint16
  21. StatsPort uint16
  22. BindIP net.IP
  23. PublicIPv4 net.IP
  24. PublicIPv6 net.IP
  25. StatsIP net.IP
  26. StatsD struct {
  27. Addr net.Addr
  28. Prefix string
  29. Tags map[string]string
  30. TagsFormat statsd.TagFormat
  31. Enabled bool
  32. }
  33. Secret []byte
  34. AdTag []byte
  35. }
  36. // URLs contains links to the proxy (tg://, t.me) and their QR codes.
  37. type URLs struct {
  38. TG string `json:"tg_url"`
  39. TMe string `json:"tme_url"`
  40. TGQRCode string `json:"tg_qrcode"`
  41. TMeQRCode string `json:"tme_qrcode"`
  42. }
  43. // IPURLs contains links to both ipv4 and ipv6 of the proxy.
  44. type IPURLs struct {
  45. IPv4 URLs `json:"ipv4"`
  46. IPv6 URLs `json:"ipv6"`
  47. BotSecret string `json:"secret_for_mtproxybot"`
  48. }
  49. // BindAddr returns connection for this server to bind to.
  50. func (c *Config) BindAddr() string {
  51. return getAddr(c.BindIP, c.BindPort)
  52. }
  53. // StatAddr returns connection string to the stats API.
  54. func (c *Config) StatAddr() string {
  55. return getAddr(c.StatsIP, c.StatsPort)
  56. }
  57. // UseMiddleProxy defines if this proxy has to connect middle proxies
  58. // which supports promoted channels or directly access Telegram.
  59. func (c *Config) UseMiddleProxy() bool {
  60. return len(c.AdTag) > 0
  61. }
  62. // BotSecretString returns secret string which should work with MTProxybot.
  63. func (c *Config) BotSecretString() string {
  64. return hex.EncodeToString(c.Secret)
  65. }
  66. // SecretString returns a secret in a form entered on the start of the
  67. // application.
  68. func (c *Config) SecretString() string {
  69. secret := c.BotSecretString()
  70. if c.SecureMode {
  71. return "dd" + secret
  72. }
  73. return secret
  74. }
  75. // GetURLs returns configured IPURLs instance with links to this server.
  76. func (c *Config) GetURLs() IPURLs {
  77. urls := IPURLs{}
  78. secret := c.SecretString()
  79. if c.PublicIPv4 != nil {
  80. urls.IPv4 = getURLs(c.PublicIPv4, c.PublicIPv4Port, secret)
  81. }
  82. if c.PublicIPv6 != nil {
  83. urls.IPv6 = getURLs(c.PublicIPv6, c.PublicIPv6Port, secret)
  84. }
  85. urls.BotSecret = c.BotSecretString()
  86. return urls
  87. }
  88. func getAddr(host fmt.Stringer, port uint16) string {
  89. return net.JoinHostPort(host.String(), strconv.Itoa(int(port)))
  90. }
  91. // NewConfig returns new configuration. If required, it manages and
  92. // fetches data from external sources. Parameters passed to this
  93. // function, should come from command line arguments.
  94. func NewConfig(debug, verbose bool, // nolint: gocyclo
  95. writeBufferSize, readBufferSize uint32,
  96. bindIP, publicIPv4, publicIPv6, statsIP net.IP,
  97. bindPort, publicIPv4Port, publicIPv6Port, statsPort, statsdPort uint16,
  98. statsdIP, statsdNetwork, statsdPrefix, statsdTagsFormat string,
  99. statsdTags map[string]string,
  100. secret, adtag []byte) (*Config, error) {
  101. secureMode := false
  102. if bytes.HasPrefix(secret, []byte{0xdd}) && len(secret) == 17 {
  103. secureMode = true
  104. secret = bytes.TrimPrefix(secret, []byte{0xdd})
  105. } else if len(secret) != 16 {
  106. return nil, errors.New("Telegram demands secret of length 32")
  107. }
  108. var err error
  109. if publicIPv4 == nil {
  110. publicIPv4, err = getGlobalIPv4()
  111. if err != nil {
  112. publicIPv4 = nil
  113. } else if publicIPv4.To4() == nil {
  114. return nil, errors.Errorf("IP %s is not IPv4", publicIPv4.String())
  115. }
  116. }
  117. if publicIPv4Port == 0 {
  118. publicIPv4Port = bindPort
  119. }
  120. if publicIPv6 == nil {
  121. publicIPv6, err = getGlobalIPv6()
  122. if err != nil {
  123. publicIPv6 = nil
  124. } else if publicIPv6.To4() != nil {
  125. return nil, errors.Errorf("IP %s is not IPv6", publicIPv6.String())
  126. }
  127. }
  128. if publicIPv6Port == 0 {
  129. publicIPv6Port = bindPort
  130. }
  131. if statsIP == nil {
  132. statsIP = publicIPv4
  133. }
  134. conf := &Config{
  135. Debug: debug,
  136. Verbose: verbose,
  137. BindIP: bindIP,
  138. BindPort: bindPort,
  139. PublicIPv4: publicIPv4,
  140. PublicIPv4Port: publicIPv4Port,
  141. PublicIPv6: publicIPv6,
  142. PublicIPv6Port: publicIPv6Port,
  143. StatsIP: statsIP,
  144. StatsPort: statsPort,
  145. Secret: secret,
  146. AdTag: adtag,
  147. SecureMode: secureMode,
  148. ReadBufferSize: int(readBufferSize),
  149. WriteBufferSize: int(writeBufferSize),
  150. }
  151. if statsdIP != "" {
  152. conf.StatsD.Enabled = true
  153. conf.StatsD.Prefix = statsdPrefix
  154. conf.StatsD.Tags = statsdTags
  155. var (
  156. addr net.Addr
  157. err error
  158. )
  159. hostPort := net.JoinHostPort(statsdIP, strconv.Itoa(int(statsdPort)))
  160. switch statsdNetwork {
  161. case "tcp":
  162. addr, err = net.ResolveTCPAddr("tcp", hostPort)
  163. case "udp":
  164. addr, err = net.ResolveUDPAddr("udp", hostPort)
  165. default:
  166. err = errors.Errorf("Unknown network %s", statsdNetwork)
  167. }
  168. if err != nil {
  169. return nil, errors.Annotate(err, "Cannot resolve statsd address")
  170. }
  171. conf.StatsD.Addr = addr
  172. switch statsdTagsFormat {
  173. case "datadog":
  174. conf.StatsD.TagsFormat = statsd.Datadog
  175. case "influxdb":
  176. conf.StatsD.TagsFormat = statsd.InfluxDB
  177. case "":
  178. default:
  179. return nil, errors.Errorf("Unknown tags format %s", statsdTagsFormat)
  180. }
  181. }
  182. return conf, nil
  183. }