diff --git a/README.md b/README.md index 8c5387d..16a4603 100644 --- a/README.md +++ b/README.md @@ -184,34 +184,45 @@ echo dd$(head -c 512 /dev/urandom | md5sum | cut -f 1 -d ' ') ``` +## Antireplay cache + +In order to prevent replay attacks, we have internal storage of first +frames messages for connected clients. These frames are generated +randomly by design and we have negligible possibility of duplication +(probability is 1/(2^64)) but it could be quite effective in order to +prevent replays. + + ## Environment variables It is possible to configure this tool using environment variables. You can configure any flag but not secret or adtag. Here is the list of supported environment variables: -| Environment variable | Corresponding flags | Default value | Description | -|--------------------------|------------------------|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `MTG_DEBUG` | `-d`, `--debug` | `false` | Run in debug mode. Usually, you need to run in this mode only if you develop this tool or its maintainer is asking you to provide logs with such verbosity. | -| `MTG_VERBOSE` | `-v`, `--verbose` | `false` | Run in verbose mode. This is way less chatty than debug mode. | -| `MTG_IP` | `-b`, `--bind-ip` | `127.0.0.1` | Which IP should we bind to. As usual, `0.0.0.0` means that we want to listen on all interfaces. Also, 4 zeroes will bind to both IPv4 and IPv6. | -| `MTG_PORT` | `-p`, `--bind-port` | `3128` | Which port should we bind to (listen on). | -| `MTG_IPV4` | `-4`, `--public-ipv4` | [Autodetect](https://ifconfig.co) | IPv4 address of this proxy. This is required if you NAT your proxy or run it in a docker container. In that case, you absolutely need to specify public IPv4 address of the proxy, otherwise either URLs will be broken or proxy could not access Telegram middle proxies. | -| `MTG_IPV4_PORT` | `--public-ipv4-port` | Value of `--bind-port` | Which port should be public of IPv4 interface. This affects only generated links and should be changed only if you NAT your proxy or run it in a docker container. | -| `MTG_IPV6` | `-6`, `--public-ipv6` | [Autodetect](https://ifconfig.co) | IPv6 address of this proxy. This is required if you NAT your proxy or run it in a docker container. In that case, you absolutely need to specify public IPv6 address of the proxy, otherwise either URLs will be broken or proxy could not access Telegram middle proxies. | -| `MTG_IPV6_PORT` | `--public-ipv6-port` | Value of `--bind-port` | Which port should be public of IPv6 interface. This affects only generated links and should be changed only if you NAT your proxy or run it in a docker container. | -| `MTG_STATS_IP` | `-t`, `--stats-ip` | `127.0.0.1` | Which IP should we bind the internal statistics HTTP server. | -| `MTG_STATS_PORT` | `-q`, `--stats-port` | `3129` | Which port should we bind the internal statistics HTTP server. | -| `MTG_STATSD_IP` | `--statsd-ip` | | IP/host addresses of statsd service. No defaults, by defaults we do not send anything there. | -| `MTG_STATSD_PORT` | `--statsd-port` | `8125` | Which port should we use to work with statsd. | -| `MTG_STATSD_NETWORK` | `--statsd-network` | `udp` | Which protocol should we use to work with statsd. Possible options are `udp` and `tcp`. | -| `MTG_STATSD_PREFIX` | `--statsd-prefix` | `mtg` | Which bucket prefix we should use. For example, if you set `mtg`, then metric `traffic.ingress` would be send as `mtg.traffic.ingress`. | -| `MTG_STATSD_TAGS_FORMAT` | `--statsd-tags-format` | | Which tags format we should use. By default, we are using default vanilla statsd tags format but if you want to send directly to InfluxDB or Datadog, please specify it there. Possible options are `influxdb` and `datadog`. | -| `MTG_STATSD_TAGS` | `--statsd-tags` | | Which tags should we send to statsd with our metrics. Please specify them as `key=value` pairs. | -| `MTG_PROMETHEUS_PREFIX` | `--prometheus-prefix` | `mtg` | Which namespace should be used for prometheus metrics. | -| `MTG_BUFFER_WRITE` | `-w`, `--write-buffer` | `65536` | The size of TCP write buffer in bytes. Write buffer is the buffer for messages which are going from client to Telegram. | -| `MTG_BUFFER_READ` | `-r`, `--read-buffer` | `131072` | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client. | -| `MTG_SECURE_ONLY` | `-s`, `--secure-only` | `false` | Support only clients with secure mode (i.e only clients with dd-secrets). | +| Environment variable | Corresponding flags | Default value | Description | +|-------------------------------|-----------------------------|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `MTG_DEBUG` | `-d`, `--debug` | `false` | Run in debug mode. Usually, you need to run in this mode only if you develop this tool or its maintainer is asking you to provide logs with such verbosity. | +| `MTG_VERBOSE` | `-v`, `--verbose` | `false` | Run in verbose mode. This is way less chatty than debug mode. | +| `MTG_IP` | `-b`, `--bind-ip` | `127.0.0.1` | Which IP should we bind to. As usual, `0.0.0.0` means that we want to listen on all interfaces. Also, 4 zeroes will bind to both IPv4 and IPv6. | +| `MTG_PORT` | `-p`, `--bind-port` | `3128` | Which port should we bind to (listen on). | +| `MTG_IPV4` | `-4`, `--public-ipv4` | [Autodetect](https://ifconfig.co) | IPv4 address of this proxy. This is required if you NAT your proxy or run it in a docker container. In that case, you absolutely need to specify public IPv4 address of the proxy, otherwise either URLs will be broken or proxy could not access Telegram middle proxies. | +| `MTG_IPV4_PORT` | `--public-ipv4-port` | Value of `--bind-port` | Which port should be public of IPv4 interface. This affects only generated links and should be changed only if you NAT your proxy or run it in a docker container. | +| `MTG_IPV6` | `-6`, `--public-ipv6` | [Autodetect](https://ifconfig.co) | IPv6 address of this proxy. This is required if you NAT your proxy or run it in a docker container. In that case, you absolutely need to specify public IPv6 address of the proxy, otherwise either URLs will be broken or proxy could not access Telegram middle proxies. | +| `MTG_IPV6_PORT` | `--public-ipv6-port` | Value of `--bind-port` | Which port should be public of IPv6 interface. This affects only generated links and should be changed only if you NAT your proxy or run it in a docker container. | +| `MTG_STATS_IP` | `-t`, `--stats-ip` | `127.0.0.1` | Which IP should we bind the internal statistics HTTP server. | +| `MTG_STATS_PORT` | `-q`, `--stats-port` | `3129` | Which port should we bind the internal statistics HTTP server. | +| `MTG_STATSD_IP` | `--statsd-ip` | | IP/host addresses of statsd service. No defaults, by defaults we do not send anything there. | +| `MTG_STATSD_PORT` | `--statsd-port` | `8125` | Which port should we use to work with statsd. | +| `MTG_STATSD_NETWORK` | `--statsd-network` | `udp` | Which protocol should we use to work with statsd. Possible options are `udp` and `tcp`. | +| `MTG_STATSD_PREFIX` | `--statsd-prefix` | `mtg` | Which bucket prefix we should use. For example, if you set `mtg`, then metric `traffic.ingress` would be send as `mtg.traffic.ingress`. | +| `MTG_STATSD_TAGS_FORMAT` | `--statsd-tags-format` | | Which tags format we should use. By default, we are using default vanilla statsd tags format but if you want to send directly to InfluxDB or Datadog, please specify it there. Possible options are `influxdb` and `datadog`. | +| `MTG_STATSD_TAGS` | `--statsd-tags` | | Which tags should we send to statsd with our metrics. Please specify them as `key=value` pairs. | +| `MTG_PROMETHEUS_PREFIX` | `--prometheus-prefix` | `mtg` | Which namespace should be used for prometheus metrics. | +| `MTG_BUFFER_WRITE` | `-w`, `--write-buffer` | `65536` | The size of TCP write buffer in bytes. Write buffer is the buffer for messages which are going from client to Telegram. | +| `MTG_BUFFER_READ` | `-r`, `--read-buffer` | `131072` | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client. | +| `MTG_SECURE_ONLY` | `-s`, `--secure-only` | `false` | Support only clients with secure mode (i.e only clients with dd-secrets). | +| `MTG_ANTIREPLAY_MAXSIZE` | `anti-replay-max-size` | `128` | Max size of antireplay cache in megabytes. | +| `MTG_ANTIREPLAY_EVICTIONTIME` | `anti-replay-eviction-time` | `168h` | Eviction time for antireplay cache entries. | Usually you want to modify only read/write buffer sizes. If you feel that proxy is slow, try to increase both sizes giving more priority to diff --git a/antireplay/cache.go b/antireplay/cache.go new file mode 100644 index 0000000..4923d52 --- /dev/null +++ b/antireplay/cache.go @@ -0,0 +1,37 @@ +package antireplay + +import ( + "github.com/allegro/bigcache" + "github.com/juju/errors" + + "github.com/9seconds/mtg/config" +) + +// Cache defines storage for obfuscated2 handshake frames. +type Cache struct { + cache *bigcache.BigCache +} + +func (a Cache) Add(frame []byte) { + a.cache.Set(string(frame), nil) // nolint: errcheck +} + +func (a Cache) Has(frame []byte) bool { + _, err := a.cache.Get(string(frame)) + + return err == nil +} + +func NewCache(config *config.Config) (Cache, error) { + cache, err := bigcache.NewBigCache(bigcache.Config{ + Shards: 1024, + LifeWindow: config.AntiReplayEvictionTime, + Hasher: hasher{}, + HardMaxCacheSize: config.AntiReplayMaxSize, + }) + if err != nil { + return Cache{}, errors.Annotate(err, "Cannot make cache") + } + + return Cache{cache}, nil +} diff --git a/antireplay/hasher.go b/antireplay/hasher.go new file mode 100644 index 0000000..acaf9b6 --- /dev/null +++ b/antireplay/hasher.go @@ -0,0 +1,9 @@ +package antireplay + +import "github.com/cespare/xxhash" + +type hasher struct{} + +func (h hasher) Sum64(value string) uint64 { + return xxhash.Sum64String(value) +} diff --git a/client/client.go b/client/client.go index 792ae4a..b8f1b93 100644 --- a/client/client.go +++ b/client/client.go @@ -4,6 +4,7 @@ import ( "context" "net" + "github.com/9seconds/mtg/antireplay" "github.com/9seconds/mtg/config" "github.com/9seconds/mtg/mtproto" "github.com/9seconds/mtg/wrappers" @@ -11,4 +12,4 @@ import ( // Init defines common method for initializing client connections. type Init func(context.Context, context.CancelFunc, net.Conn, string, - *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) + antireplay.Cache, *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) diff --git a/client/direct.go b/client/direct.go index dc71dce..81a5e16 100644 --- a/client/direct.go +++ b/client/direct.go @@ -7,6 +7,7 @@ import ( "github.com/juju/errors" + "github.com/9seconds/mtg/antireplay" "github.com/9seconds/mtg/config" "github.com/9seconds/mtg/mtproto" "github.com/9seconds/mtg/obfuscated2" @@ -18,7 +19,8 @@ const handshakeTimeout = 10 * time.Second // DirectInit initializes client connection for proxy which connects to // Telegram directly. func DirectInit(ctx context.Context, cancel context.CancelFunc, socket net.Conn, - connID string, conf *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) { + connID string, antiReplayCache antireplay.Cache, + conf *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) { tcpSocket := socket.(*net.TCPConn) if err := tcpSocket.SetNoDelay(false); err != nil { return nil, nil, errors.Annotate(err, "Cannot disable NO_DELAY to client socket") @@ -42,6 +44,12 @@ func DirectInit(ctx context.Context, cancel context.CancelFunc, socket net.Conn, if err != nil { return nil, nil, errors.Annotate(err, "Cannot parse obfuscated frame") } + + if antiReplayCache.Has([]byte(frame)) { + return nil, nil, errors.New("Replay attack is detected") + } + antiReplayCache.Add([]byte(frame)) + connOpts.ConnectionProto = mtproto.ConnectionProtocolAny connOpts.ClientAddr = conn.RemoteAddr() diff --git a/client/middle.go b/client/middle.go index 4c41306..ecacd8e 100644 --- a/client/middle.go +++ b/client/middle.go @@ -4,6 +4,7 @@ import ( "context" "net" + "github.com/9seconds/mtg/antireplay" "github.com/9seconds/mtg/config" "github.com/9seconds/mtg/mtproto" "github.com/9seconds/mtg/wrappers" @@ -12,8 +13,9 @@ import ( // MiddleInit initializes client connection for proxy which has to // support promoted channels, connect to Telegram middle proxies etc. func MiddleInit(ctx context.Context, cancel context.CancelFunc, socket net.Conn, - connID string, conf *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) { - conn, opts, err := DirectInit(ctx, cancel, socket, connID, conf) + connID string, antiReplayCache antireplay.Cache, + conf *config.Config) (wrappers.Wrap, *mtproto.ConnectionOpts, error) { + conn, opts, err := DirectInit(ctx, cancel, socket, connID, antiReplayCache, conf) if err != nil { return nil, nil, err } diff --git a/config/config.go b/config/config.go index 27f5ad8..dc43864 100644 --- a/config/config.go +++ b/config/config.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "strconv" + "time" "github.com/juju/errors" statsd "gopkg.in/alexcesaro/statsd.v2" @@ -31,6 +32,9 @@ type Config struct { PublicIPv6 net.IP StatsIP net.IP + AntiReplayMaxSize int + AntiReplayEvictionTime time.Duration + StatsD struct { Addr net.Addr Prefix string @@ -121,6 +125,7 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo statsdIP, statsdNetwork, statsdPrefix, statsdTagsFormat string, statsdTags map[string]string, prometheusPrefix string, secureOnly bool, + antiReplayMaxSize int, antiReplayEvictionTime time.Duration, secret, adtag []byte) (*Config, error) { secureMode := secureOnly if bytes.HasPrefix(secret, []byte{0xdd}) && len(secret) == 17 { @@ -160,22 +165,24 @@ func NewConfig(debug, verbose bool, // nolint: gocyclo } conf := &Config{ - Debug: debug, - Verbose: verbose, - SecureOnly: secureOnly, - BindIP: bindIP, - BindPort: bindPort, - PublicIPv4: publicIPv4, - PublicIPv4Port: publicIPv4Port, - PublicIPv6: publicIPv6, - PublicIPv6Port: publicIPv6Port, - StatsIP: statsIP, - StatsPort: statsPort, - Secret: secret, - AdTag: adtag, - SecureMode: secureMode, - ReadBufferSize: int(readBufferSize), - WriteBufferSize: int(writeBufferSize), + Debug: debug, + Verbose: verbose, + SecureOnly: secureOnly, + BindIP: bindIP, + BindPort: bindPort, + PublicIPv4: publicIPv4, + PublicIPv4Port: publicIPv4Port, + PublicIPv6: publicIPv6, + PublicIPv6Port: publicIPv6Port, + StatsIP: statsIP, + StatsPort: statsPort, + Secret: secret, + AdTag: adtag, + SecureMode: secureMode, + ReadBufferSize: int(readBufferSize), + WriteBufferSize: int(writeBufferSize), + AntiReplayMaxSize: antiReplayMaxSize, + AntiReplayEvictionTime: antiReplayEvictionTime, } conf.Prometheus.Prefix = prometheusPrefix diff --git a/go.mod b/go.mod index c5e449c..fae7189 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,29 @@ module github.com/9seconds/mtg replace github.com/golang/lint => github.com/golang/lint v0.0.0-20190227174305-8f45f776aaf1 require ( + github.com/OneOfOne/xxhash v1.2.5 // indirect + github.com/allegro/bigcache v1.2.0 github.com/beevik/ntp v0.2.0 + github.com/beorn7/perks v1.0.0 // indirect + github.com/cespare/xxhash v1.1.0 github.com/dustin/go-humanize v1.0.0 github.com/gofrs/uuid v3.2.0+incompatible - github.com/golang/protobuf v1.3.0 // indirect + github.com/golang/protobuf v1.3.1 // indirect github.com/juju/errors v0.0.0-20190207033735-e65537c515d7 github.com/juju/loggo v0.0.0-20190212223446-d976af380377 // indirect - github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 // indirect + github.com/juju/testing v0.0.0-20190418112600-6570bd8f8541 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/pkg/errors v0.8.1 // indirect - github.com/prometheus/client_golang v0.9.2 + github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect - github.com/prometheus/common v0.2.0 // indirect - github.com/prometheus/procfs v0.0.0-20190227231451-bbced9601137 // indirect + github.com/prometheus/common v0.3.0 // indirect + github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/stretchr/testify v1.3.0 go.uber.org/atomic v1.3.2 // indirect go.uber.org/multierr v1.1.0 // indirect go.uber.org/zap v1.9.1 - golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7 // indirect - golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect + golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alexcesaro/statsd.v2 v2.0.0 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect diff --git a/go.sum b/go.sum index bc83ce2..18d05e0 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,20 @@ +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= +github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.0 h1:qDaE0QoF29wKBb3+pXFrJFy1ihe5OT9OiXhg1t85SxM= +github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,14 +29,14 @@ github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= -github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/juju/errors v0.0.0-20190207033735-e65537c515d7 h1:dMIPRDg6gi7CUp0Kj2+HxqJ5kTr1iAdzsXYIrLCNSmU= github.com/juju/errors v0.0.0-20190207033735-e65537c515d7/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20190212223446-d976af380377 h1:n6QjW3g5JNY3xPmIjFt6z1H6tFQA6BhwOC2bvTAm1YU= github.com/juju/loggo v0.0.0-20190212223446-d976af380377/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/juju/testing v0.0.0-20190418112600-6570bd8f8541 h1:291RYTdi1UqkKeBr9UC0ArNVSIAzsh5CQDkIXEp/iTg= +github.com/juju/testing v0.0.0-20190418112600-6570bd8f8541/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -46,21 +55,26 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.3.0 h1:taZ4h8Tkxv2kNyoSctBvfXEHmBmxrwmIidZTIaHons4= +github.com/prometheus/common v0.3.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190227231451-bbced9601137 h1:3l8oligPtjd4JuM+OZ+U8sjtwFGJs98cdWsqs6QZRWs= -github.com/prometheus/procfs v0.0.0-20190227231451-bbced9601137/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0 h1:c8R11WC8m7KNMkTv/0+Be8vvwo4I3/Ut9AC2FW8fX3U= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= @@ -74,20 +88,18 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7 h1:Qe/u+eY379X4He4GBMFZYu3pmh1ML5yT1aL1ndNM1zQ= -golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 h1:FP8hkuE6yUEaJnK7O2eTuejKWwW+Rhfj80dQ2JcKxCU= +golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= diff --git a/main.go b/main.go index 3303e3f..cf644ac 100644 --- a/main.go +++ b/main.go @@ -134,6 +134,17 @@ var ( Envar("MTG_SECURE_ONLY"). Bool() + antiReplayMaxSize = app.Flag("anti-replay-max-size", + "Max size of antireplay cache in megabytes."). + Envar("MTG_ANTIREPLAY_MAXSIZE"). + Default("128"). + Int() + antiReplayEvictionTime = app.Flag("anti-replay-eviction-time", + "Eviction time period for obfuscated2 handshakes"). + Envar("MTG_ANTIREPLAY_EVICTIONTIME"). + Default("168h"). + Duration() + secret = app.Arg("secret", "Secret of this proxy.").Required().HexBytes() adtag = app.Arg("adtag", "ADTag of the proxy.").HexBytes() ) @@ -156,6 +167,7 @@ func main() { // nolint: gocyclo *bindPort, *publicIPv4Port, *publicIPv6Port, *statsPort, *statsdPort, *statsdIP, *statsdNetwork, *statsdPrefix, *statsdTagsFormat, *statsdTags, *prometheusPrefix, *secureOnly, + *antiReplayMaxSize, *antiReplayEvictionTime, *secret, *adtag, ) if err != nil { @@ -202,7 +214,10 @@ func main() { // nolint: gocyclo panic(err) } - server := proxy.NewProxy(conf) + server, err := proxy.NewProxy(conf) + if err != nil { + panic(err) + } if err := server.Serve(); err != nil { zap.S().Fatalw("Server stopped", "error", err) } diff --git a/proxy/proxy.go b/proxy/proxy.go index 4a7c43c..ecda26a 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -10,6 +10,7 @@ import ( "github.com/juju/errors" "go.uber.org/zap" + "github.com/9seconds/mtg/antireplay" "github.com/9seconds/mtg/client" "github.com/9seconds/mtg/config" "github.com/9seconds/mtg/mtproto" @@ -20,9 +21,10 @@ import ( // Proxy is a core of this program. type Proxy struct { - clientInit client.Init - tg telegram.Telegram - conf *config.Config + antiReplayCache antireplay.Cache + clientInit client.Init + tg telegram.Telegram + conf *config.Config } // Serve runs TCP proxy server. @@ -58,7 +60,7 @@ func (p *Proxy) accept(conn net.Conn) { log.Infow("Client connected", "addr", conn.RemoteAddr()) - clientConn, opts, err := p.clientInit(ctx, cancel, conn, connID, p.conf) + clientConn, opts, err := p.clientInit(ctx, cancel, conn, connID, p.antiReplayCache, p.conf) if err != nil { log.Errorw("Cannot initialize client connection", "error", err) return @@ -150,10 +152,15 @@ func (p *Proxy) directPipe(src wrappers.StreamReadCloser, dst io.Writer, wait *s } // NewProxy returns new proxy instance. -func NewProxy(conf *config.Config) *Proxy { +func NewProxy(conf *config.Config) (*Proxy, error) { var clientInit client.Init var tg telegram.Telegram + cache, err := antireplay.NewCache(conf) + if err != nil { + return nil, errors.Annotate(err, "Cannot make proxy") + } + if conf.UseMiddleProxy() { clientInit = client.MiddleInit tg = telegram.NewMiddleTelegram(conf) @@ -163,8 +170,9 @@ func NewProxy(conf *config.Config) *Proxy { } return &Proxy{ - conf: conf, - clientInit: clientInit, - tg: tg, - } + antiReplayCache: cache, + conf: conf, + clientInit: clientInit, + tg: tg, + }, nil }