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
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

config.go 5.3KB

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