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 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package main
  2. import (
  3. "math/rand"
  4. "os"
  5. "syscall"
  6. "time"
  7. "github.com/juju/errors"
  8. kingpin "gopkg.in/alecthomas/kingpin.v2"
  9. "github.com/9seconds/mtg/cli"
  10. "github.com/9seconds/mtg/config"
  11. )
  12. var version = "dev" // this has to be set by build ld flags
  13. var (
  14. app = kingpin.New("mtg", "Simple MTPROTO proxy.")
  15. generateSecretCommand = app.Command("generate-secret",
  16. "Generate new secret")
  17. generateSecretType = generateSecretCommand.Arg("type",
  18. "A type of secret to generate. Valid options are 'simple', 'secured' and 'tls'").
  19. Required().
  20. Enum("simple", "secured", "tls")
  21. proxyCommand = app.Command("proxy",
  22. "Run new proxy instance")
  23. proxyDebug = proxyCommand.Flag("debug",
  24. "Run in debug mode.").
  25. Short('d').
  26. Envar("MTG_DEBUG").
  27. Bool()
  28. proxyVerbose = proxyCommand.Flag("verbose",
  29. "Run in verbose mode.").
  30. Short('v').
  31. Envar("MTG_VERBOSE").
  32. Bool()
  33. proxyBindIP = proxyCommand.Flag("bind-ip",
  34. "Which IP to bind to.").
  35. Short('b').
  36. Envar("MTG_IP").
  37. Default("127.0.0.1").
  38. IP()
  39. proxyBindPort = proxyCommand.Flag("bind-port",
  40. "Which port to bind to.").
  41. Short('p').
  42. Envar("MTG_PORT").
  43. Default("3128").
  44. Uint16()
  45. proxyPublicIPv4 = proxyCommand.Flag("public-ipv4",
  46. "Which IPv4 address is public.").
  47. Short('4').
  48. Envar("MTG_IPV4").
  49. IP()
  50. proxyPublicIPv4Port = proxyCommand.Flag("public-ipv4-port",
  51. "Which IPv4 port is public. Default is 'bind-port' value.").
  52. Envar("MTG_IPV4_PORT").
  53. Uint16()
  54. proxyPublicIPv6 = proxyCommand.Flag("public-ipv6",
  55. "Which IPv6 address is public.").
  56. Short('6').
  57. Envar("MTG_IPV6").
  58. IP()
  59. proxyPublicIPv6Port = proxyCommand.Flag("public-ipv6-port",
  60. "Which IPv6 port is public. Default is 'bind-port' value.").
  61. Envar("MTG_IPV6_PORT").
  62. Uint16()
  63. proxyStatsIP = proxyCommand.Flag("stats-ip",
  64. "Which IP bind stats server to.").
  65. Short('t').
  66. Envar("MTG_STATS_IP").
  67. Default("127.0.0.1").
  68. IP()
  69. proxyStatsPort = proxyCommand.Flag("stats-port",
  70. "Which port bind stats to.").
  71. Short('q').
  72. Envar("MTG_STATS_PORT").
  73. Default("3129").
  74. Uint16()
  75. proxyStatsdIP = proxyCommand.Flag("statsd-ip",
  76. "Which IP should we use for working with statsd.").
  77. Envar("MTG_STATSD_IP").
  78. IP()
  79. proxyStatsdPort = proxyCommand.Flag("statsd-port",
  80. "Which port should we use for working with statsd.").
  81. Envar("MTG_STATSD_PORT").
  82. Default("8125").
  83. Uint16()
  84. proxyStatsdNetwork = proxyCommand.Flag("statsd-network",
  85. "Which network is used to work with statsd. Only 'tcp' and 'udp' are supported.").
  86. Envar("MTG_STATSD_NETWORK").
  87. Default("udp").
  88. Enum("udp", "tcp")
  89. proxyStatsdPrefix = proxyCommand.Flag("statsd-prefix",
  90. "Which bucket prefix should we use for sending stats to statsd.").
  91. Envar("MTG_STATSD_PREFIX").
  92. Default("mtg").
  93. String()
  94. proxyStatsdTagsFormat = proxyCommand.Flag("statsd-tags-format",
  95. "Which tag format should we use to send stats metrics. Valid options are 'datadog' and 'influxdb'.").
  96. Envar("MTG_STATSD_TAGS_FORMAT").
  97. Default("influxdb").
  98. Enum("datadog", "influxdb")
  99. proxyStatsdTags = proxyCommand.Flag("statsd-tags",
  100. "Tags to use for working with statsd (specified as 'key=value').").
  101. Envar("MTG_STATSD_TAGS").
  102. StringMap()
  103. proxyPrometheusPrefix = proxyCommand.Flag("prometheus-prefix",
  104. "Which namespace to use to send stats to Prometheus.").
  105. Envar("MTG_PROMETHEUS_PREFIX").
  106. Default("mtg").
  107. String()
  108. proxyWriteBufferSize = proxyCommand.Flag("write-buffer",
  109. "Write buffer size in bytes. You can think about it as a buffer from client to Telegram.").
  110. Short('w').
  111. Envar("MTG_BUFFER_WRITE").
  112. Default("65536").
  113. Uint32()
  114. proxyReadBufferSize = proxyCommand.Flag("read-buffer",
  115. "Read buffer size in bytes. You can think about it as a buffer from Telegram to client.").
  116. Short('r').
  117. Envar("MTG_BUFFER_READ").
  118. Default("131072").
  119. Uint32()
  120. proxyAntiReplayMaxSize = proxyCommand.Flag("anti-replay-max-size",
  121. "Max size of antireplay cache in megabytes.").
  122. Envar("MTG_ANTIREPLAY_MAXSIZE").
  123. Default("128").
  124. Int()
  125. proxyAntiReplayEvictionTime = proxyCommand.Flag("anti-replay-eviction-time",
  126. "Eviction time period for obfuscated2 handshakes").
  127. Envar("MTG_ANTIREPLAY_EVICTIONTIME").
  128. Default("168h").
  129. Duration()
  130. proxySecret = proxyCommand.Arg("secret", "Secret of this proxy.").Required().HexBytes()
  131. proxyAdtag = proxyCommand.Arg("adtag", "ADTag of the proxy.").HexBytes()
  132. )
  133. func main() {
  134. rand.Seed(time.Now().UTC().UnixNano())
  135. app.Version(version)
  136. app.HelpFlag.Short('h')
  137. if err := setRLimit(); err != nil {
  138. cli.Fatal(err.Error())
  139. }
  140. switch kingpin.MustParse(app.Parse(os.Args[1:])) {
  141. case generateSecretCommand.FullCommand():
  142. cli.Generate(*generateSecretType)
  143. case proxyCommand.FullCommand():
  144. err := config.Init(
  145. config.ConfigOpt{Option: config.OptionTypeDebug, Value: *proxyDebug},
  146. config.ConfigOpt{Option: config.OptionTypeVerbose, Value: *proxyVerbose},
  147. config.ConfigOpt{Option: config.OptionTypeBindIP, Value: *proxyBindIP},
  148. config.ConfigOpt{Option: config.OptionTypeBindPort, Value: *proxyBindPort},
  149. config.ConfigOpt{Option: config.OptionTypePublicIPv4, Value: *proxyPublicIPv4},
  150. config.ConfigOpt{Option: config.OptionTypePublicIPv4Port, Value: *proxyPublicIPv4Port},
  151. config.ConfigOpt{Option: config.OptionTypePublicIPv6, Value: *proxyPublicIPv6},
  152. config.ConfigOpt{Option: config.OptionTypePublicIPv6Port, Value: *proxyPublicIPv6Port},
  153. config.ConfigOpt{Option: config.OptionTypeStatsIP, Value: *proxyStatsIP},
  154. config.ConfigOpt{Option: config.OptionTypeStatsPort, Value: *proxyStatsPort},
  155. config.ConfigOpt{Option: config.OptionTypeStatsdIP, Value: *proxyStatsdIP},
  156. config.ConfigOpt{Option: config.OptionTypeStatsdPort, Value: *proxyStatsdPort},
  157. config.ConfigOpt{Option: config.OptionTypeStatsdNetwork, Value: *proxyStatsdNetwork},
  158. config.ConfigOpt{Option: config.OptionTypeStatsdPrefix, Value: *proxyStatsdPrefix},
  159. config.ConfigOpt{Option: config.OptionTypeStatsdTagsFormat, Value: *proxyStatsdTagsFormat},
  160. config.ConfigOpt{Option: config.OptionTypeStatsdTags, Value: *proxyStatsdTags},
  161. config.ConfigOpt{Option: config.OptionTypePrometheusPrefix, Value: *proxyPrometheusPrefix},
  162. config.ConfigOpt{Option: config.OptionTypeWriteBufferSize, Value: *proxyWriteBufferSize},
  163. config.ConfigOpt{Option: config.OptionTypeReadBufferSize, Value: *proxyReadBufferSize},
  164. config.ConfigOpt{Option: config.OptionTypeAntiReplayMaxSize, Value: *proxyAntiReplayMaxSize},
  165. config.ConfigOpt{Option: config.OptionTypeAntiReplayEvictionTime, Value: *proxyAntiReplayEvictionTime},
  166. config.ConfigOpt{Option: config.OptionTypeSecret, Value: *proxySecret},
  167. config.ConfigOpt{Option: config.OptionTypeAdtag, Value: *proxyAdtag},
  168. )
  169. if err != nil {
  170. cli.Fatal(err.Error())
  171. }
  172. if err := cli.Proxy(); err != nil {
  173. cli.Fatal(err.Error())
  174. }
  175. }
  176. }
  177. func setRLimit() (err error) {
  178. rLimit := syscall.Rlimit{}
  179. err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  180. if err != nil {
  181. err = errors.Annotate(err, "Cannot get rlimit")
  182. return
  183. }
  184. rLimit.Cur = rLimit.Max
  185. err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  186. if err != nil {
  187. err = errors.Annotate(err, "Cannot set rlimit")
  188. }
  189. return
  190. }