| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- package main
-
- //go:generate scripts/generate_version.sh
-
- import (
- "encoding/json"
- "fmt"
- "io"
- "math/rand"
- "os"
- "syscall"
- "time"
-
- "github.com/juju/errors"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- kingpin "gopkg.in/alecthomas/kingpin.v2"
-
- "github.com/9seconds/mtg/config"
- "github.com/9seconds/mtg/ntp"
- "github.com/9seconds/mtg/proxy"
- "github.com/9seconds/mtg/stats"
- )
-
- var (
- app = kingpin.New("mtg", "Simple MTPROTO proxy.")
-
- debug = app.Flag("debug",
- "Run in debug mode.").
- Short('d').
- Envar("MTG_DEBUG").
- Bool()
- verbose = app.Flag("verbose",
- "Run in verbose mode.").
- Short('v').
- Envar("MTG_VERBOSE").
- Bool()
-
- bindIP = app.Flag("bind-ip",
- "Which IP to bind to.").
- Short('b').
- Envar("MTG_IP").
- Default("127.0.0.1").
- IP()
- bindPort = app.Flag("bind-port",
- "Which port to bind to.").
- Short('p').
- Envar("MTG_PORT").
- Default("3128").
- Uint16()
-
- publicIPv4 = app.Flag("public-ipv4",
- "Which IPv4 address is public.").
- Short('4').
- Envar("MTG_IPV4").
- IP()
- publicIPv4Port = app.Flag("public-ipv4-port",
- "Which IPv4 port is public. Default is 'bind-port' value.").
- Envar("MTG_IPV4_PORT").
- Uint16()
-
- publicIPv6 = app.Flag("public-ipv6",
- "Which IPv6 address is public.").
- Short('6').
- Envar("MTG_IPV6").
- IP()
- publicIPv6Port = app.Flag("public-ipv6-port",
- "Which IPv6 port is public. Default is 'bind-port' value.").
- Envar("MTG_IPV6_PORT").
- Uint16()
-
- statsIP = app.Flag("stats-ip",
- "Which IP bind stats server to.").
- Short('t').
- Envar("MTG_STATS_IP").
- Default("127.0.0.1").
- IP()
- statsPort = app.Flag("stats-port",
- "Which port bind stats to.").
- Short('q').
- Envar("MTG_STATS_PORT").
- Default("3129").
- Uint16()
-
- statsdIP = app.Flag("statsd-ip",
- "Which IP should we use for working with statsd.").
- Envar("MTG_STATSD_IP").
- String()
- statsdPort = app.Flag("statsd-port",
- "Which port should we use for working with statsd.").
- Envar("MTG_STATSD_PORT").
- Default("8125").
- Uint16()
- statsdNetwork = app.Flag("statsd-network",
- "Which network is used to work with statsd. Only 'tcp' and 'udp' are supported.").
- Envar("MTG_STATSD_NETWORK").
- Default("udp").
- String()
- statsdPrefix = app.Flag("statsd-prefix",
- "Which bucket prefix should we use for sending stats to statsd.").
- Envar("MTG_STATSD_PREFIX").
- Default("mtg").
- String()
- statsdTagsFormat = app.Flag("statsd-tags-format",
- "Which tag format should we use to send stats metrics. Valid options are 'datadog' and 'influxdb'.").
- Envar("MTG_STATSD_TAGS_FORMAT").
- String()
- statsdTags = app.Flag("statsd-tags",
- "Tags to use for working with statsd (specified as 'key=value').").
- Envar("MTG_STATSD_TAGS").
- StringMap()
-
- writeBufferSize = app.Flag("write-buffer",
- "Write buffer size in bytes. You can think about it as a buffer from client to Telegram.").
- Short('w').
- Envar("MTG_BUFFER_WRITE").
- Default("65536").
- Uint32()
- readBufferSize = app.Flag("read-buffer",
- "Read buffer size in bytes. You can think about it as a buffer from Telegram to client.").
- Short('r').
- Envar("MTG_BUFFER_READ").
- Default("131072").
- Uint32()
-
- secret = app.Arg("secret", "Secret of this proxy.").Required().HexBytes()
- adtag = app.Arg("adtag", "ADTag of the proxy.").HexBytes()
- )
-
- func init() {
- rand.Seed(time.Now().UTC().UnixNano())
- app.Version(version)
- app.HelpFlag.Short('h')
- }
-
- func main() { // nolint: gocyclo
- kingpin.MustParse(app.Parse(os.Args[1:]))
-
- err := setRLimit()
- if err != nil {
- usage(err.Error())
- }
-
- conf, err := config.NewConfig(*debug, *verbose,
- *writeBufferSize, *readBufferSize,
- *bindIP, *publicIPv4, *publicIPv6, *statsIP,
- *bindPort, *publicIPv4Port, *publicIPv6Port, *statsPort, *statsdPort,
- *statsdIP, *statsdNetwork, *statsdPrefix, *statsdTagsFormat,
- *statsdTags,
- *secret, *adtag,
- )
- if err != nil {
- usage(err.Error())
- }
-
- atom := zap.NewAtomicLevel()
- switch {
- case conf.Debug:
- atom.SetLevel(zapcore.DebugLevel)
- case conf.Verbose:
- atom.SetLevel(zapcore.InfoLevel)
- default:
- atom.SetLevel(zapcore.ErrorLevel)
- }
- encoderCfg := zap.NewProductionEncoderConfig()
- logger := zap.New(zapcore.NewCore(
- zapcore.NewJSONEncoder(encoderCfg),
- zapcore.Lock(os.Stderr),
- atom,
- ))
- zap.ReplaceGlobals(logger)
- defer logger.Sync() // nolint: errcheck
-
- printURLs(conf.GetURLs())
-
- if conf.UseMiddleProxy() {
- zap.S().Infow("Use middle proxy connection to Telegram")
- if diff, err := ntp.Fetch(); err != nil {
- zap.S().Warnw("Could not fetch time data from NTP")
- } else {
- if diff >= time.Second {
- usage(fmt.Sprintf("You choose to use middle proxy but your clock drift (%s) "+
- "is bigger than 1 second. Please, sync your time", diff))
- }
- go ntp.AutoUpdate()
- }
- } else {
- zap.S().Infow("Use direct connection to Telegram")
- }
-
- if err := stats.Start(conf); err != nil {
- panic(err)
- }
-
- server := proxy.NewProxy(conf)
- if err := server.Serve(); err != nil {
- zap.S().Fatalw("Server stopped", "error", err)
- }
- }
-
- func setRLimit() (err error) {
- rLimit := syscall.Rlimit{}
- err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
- if err != nil {
- err = errors.Annotate(err, "Cannot get rlimit")
- return
- }
- rLimit.Cur = rLimit.Max
-
- err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
- if err != nil {
- err = errors.Annotate(err, "Cannot set rlimit")
- }
-
- return
- }
-
- func printURLs(data interface{}) {
- encoder := json.NewEncoder(os.Stdout)
- encoder.SetEscapeHTML(false)
- encoder.SetIndent("", " ")
-
- err := encoder.Encode(data)
- if err != nil {
- panic(err)
- }
- }
-
- func usage(msg string) {
- io.WriteString(os.Stderr, msg+"\n") // nolint: errcheck, gosec
- os.Exit(1)
- }
|