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文字以内のものにしてください。

main.go 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "math/rand"
  7. "os"
  8. "time"
  9. "go.uber.org/zap"
  10. "go.uber.org/zap/zapcore"
  11. "gopkg.in/alecthomas/kingpin.v2"
  12. "github.com/9seconds/mtg/config"
  13. "github.com/9seconds/mtg/ntp"
  14. "github.com/9seconds/mtg/proxy"
  15. "github.com/9seconds/mtg/rlimit"
  16. "github.com/9seconds/mtg/stats"
  17. )
  18. var version = "dev" // this has to be set by build ld flags
  19. var (
  20. app = kingpin.New("mtg", "Simple MTPROTO proxy.")
  21. debug = app.Flag("debug",
  22. "Run in debug mode.").
  23. Short('d').
  24. Envar("MTG_DEBUG").
  25. Bool()
  26. verbose = app.Flag("verbose",
  27. "Run in verbose mode.").
  28. Short('v').
  29. Envar("MTG_VERBOSE").
  30. Bool()
  31. bindIP = app.Flag("bind-ip",
  32. "Which IP to bind to.").
  33. Short('b').
  34. Envar("MTG_IP").
  35. Default("127.0.0.1").
  36. IP()
  37. bindPort = app.Flag("bind-port",
  38. "Which port to bind to.").
  39. Short('p').
  40. Envar("MTG_PORT").
  41. Default("3128").
  42. Uint16()
  43. publicIPv4 = app.Flag("public-ipv4",
  44. "Which IPv4 address is public.").
  45. Short('4').
  46. Envar("MTG_IPV4").
  47. IP()
  48. publicIPv4Port = app.Flag("public-ipv4-port",
  49. "Which IPv4 port is public. Default is 'bind-port' value.").
  50. Envar("MTG_IPV4_PORT").
  51. Uint16()
  52. publicIPv6 = app.Flag("public-ipv6",
  53. "Which IPv6 address is public.").
  54. Short('6').
  55. Envar("MTG_IPV6").
  56. IP()
  57. publicIPv6Port = app.Flag("public-ipv6-port",
  58. "Which IPv6 port is public. Default is 'bind-port' value.").
  59. Envar("MTG_IPV6_PORT").
  60. Uint16()
  61. statsIP = app.Flag("stats-ip",
  62. "Which IP bind stats server to.").
  63. Short('t').
  64. Envar("MTG_STATS_IP").
  65. Default("127.0.0.1").
  66. IP()
  67. statsPort = app.Flag("stats-port",
  68. "Which port bind stats to.").
  69. Short('q').
  70. Envar("MTG_STATS_PORT").
  71. Default("3129").
  72. Uint16()
  73. statsdIP = app.Flag("statsd-ip",
  74. "Which IP should we use for working with statsd.").
  75. Envar("MTG_STATSD_IP").
  76. String()
  77. statsdPort = app.Flag("statsd-port",
  78. "Which port should we use for working with statsd.").
  79. Envar("MTG_STATSD_PORT").
  80. Default("8125").
  81. Uint16()
  82. statsdNetwork = app.Flag("statsd-network",
  83. "Which network is used to work with statsd. Only 'tcp' and 'udp' are supported.").
  84. Envar("MTG_STATSD_NETWORK").
  85. Default("udp").
  86. String()
  87. statsdPrefix = app.Flag("statsd-prefix",
  88. "Which bucket prefix should we use for sending stats to statsd.").
  89. Envar("MTG_STATSD_PREFIX").
  90. Default("mtg").
  91. String()
  92. statsdTagsFormat = app.Flag("statsd-tags-format",
  93. "Which tag format should we use to send stats metrics. Valid options are 'datadog' and 'influxdb'.").
  94. Envar("MTG_STATSD_TAGS_FORMAT").
  95. String()
  96. statsdTags = app.Flag("statsd-tags",
  97. "Tags to use for working with statsd (specified as 'key=value').").
  98. Envar("MTG_STATSD_TAGS").
  99. StringMap()
  100. prometheusPrefix = app.Flag("prometheus-prefix",
  101. "Which namespace to use to send stats to Prometheus.").
  102. Envar("MTG_PROMETHEUS_PREFIX").
  103. Default("mtg").
  104. String()
  105. writeBufferSize = app.Flag("write-buffer",
  106. "Write buffer size in bytes. You can think about it as a buffer from client to Telegram.").
  107. Short('w').
  108. Envar("MTG_BUFFER_WRITE").
  109. Default("65536").
  110. Uint32()
  111. readBufferSize = app.Flag("read-buffer",
  112. "Read buffer size in bytes. You can think about it as a buffer from Telegram to client.").
  113. Short('r').
  114. Envar("MTG_BUFFER_READ").
  115. Default("131072").
  116. Uint32()
  117. secureOnly = app.Flag("secure-only",
  118. "Support clients with dd-secrets only.").
  119. Short('s').
  120. Envar("MTG_SECURE_ONLY").
  121. Bool()
  122. antiReplayMaxSize = app.Flag("anti-replay-max-size",
  123. "Max size of antireplay cache in megabytes.").
  124. Envar("MTG_ANTIREPLAY_MAXSIZE").
  125. Default("128").
  126. Int()
  127. antiReplayEvictionTime = app.Flag("anti-replay-eviction-time",
  128. "Eviction time period for obfuscated2 handshakes").
  129. Envar("MTG_ANTIREPLAY_EVICTIONTIME").
  130. Default("168h").
  131. Duration()
  132. secret = app.Arg("secret", "Secret of this proxy.").Required().HexBytes()
  133. adtag = app.Arg("adtag", "ADTag of the proxy.").HexBytes()
  134. )
  135. func main() { // nolint: gocyclo
  136. rand.Seed(time.Now().UTC().UnixNano())
  137. app.Version(version)
  138. app.HelpFlag.Short('h')
  139. kingpin.MustParse(app.Parse(os.Args[1:]))
  140. err := rlimit.Set()
  141. if err != nil {
  142. usage(err.Error())
  143. }
  144. conf, err := config.NewConfig(*debug, *verbose,
  145. *writeBufferSize, *readBufferSize,
  146. *bindIP, *publicIPv4, *publicIPv6, *statsIP,
  147. *bindPort, *publicIPv4Port, *publicIPv6Port, *statsPort, *statsdPort,
  148. *statsdIP, *statsdNetwork, *statsdPrefix, *statsdTagsFormat,
  149. *statsdTags, *prometheusPrefix, *secureOnly,
  150. *antiReplayMaxSize, *antiReplayEvictionTime,
  151. *secret, *adtag,
  152. )
  153. if err != nil {
  154. usage(err.Error())
  155. }
  156. atom := zap.NewAtomicLevel()
  157. switch {
  158. case conf.Debug:
  159. atom.SetLevel(zapcore.DebugLevel)
  160. case conf.Verbose:
  161. atom.SetLevel(zapcore.InfoLevel)
  162. default:
  163. atom.SetLevel(zapcore.ErrorLevel)
  164. }
  165. encoderCfg := zap.NewProductionEncoderConfig()
  166. logger := zap.New(zapcore.NewCore(
  167. zapcore.NewJSONEncoder(encoderCfg),
  168. zapcore.Lock(os.Stderr),
  169. atom,
  170. ))
  171. zap.ReplaceGlobals(logger)
  172. defer logger.Sync() // nolint: errcheck
  173. printURLs(conf.GetURLs())
  174. zap.S().Debugw("Configuration", "config", conf)
  175. if conf.UseMiddleProxy() {
  176. zap.S().Infow("Use middle proxy connection to Telegram")
  177. if diff, err := ntp.Fetch(); err != nil {
  178. zap.S().Warnw("Could not fetch time data from NTP")
  179. } else {
  180. if diff >= time.Second {
  181. usage(fmt.Sprintf("You choose to use middle proxy but your clock drift (%s) "+
  182. "is bigger than 1 second. Please, sync your time", diff))
  183. }
  184. go ntp.AutoUpdate()
  185. }
  186. } else {
  187. zap.S().Infow("Use direct connection to Telegram")
  188. }
  189. if err := stats.Init(conf); err != nil {
  190. panic(err)
  191. }
  192. server, err := proxy.NewProxy(conf)
  193. if err != nil {
  194. panic(err)
  195. }
  196. if err := server.Serve(); err != nil {
  197. zap.S().Fatalw("Server stopped", "error", err)
  198. }
  199. }
  200. func printURLs(data interface{}) {
  201. encoder := json.NewEncoder(os.Stdout)
  202. encoder.SetEscapeHTML(false)
  203. encoder.SetIndent("", " ")
  204. err := encoder.Encode(data)
  205. if err != nil {
  206. panic(err)
  207. }
  208. }
  209. func usage(msg string) {
  210. io.WriteString(os.Stderr, msg+"\n") // nolint: errcheck, gosec
  211. os.Exit(1)
  212. }