REPOSITORY / ScuroNeko/mtg

Compare commits

DIFF REPOSITORY

Compare commits

...
34 Commits
Author SHA1 Message Date
9seconds cdd93bd25f Merge remote-tracking branch 'origin/master' into stable 2020-02-04 11:23:40 +03:00
9seconds 5a52418394 Update dependencies 2020-02-04 11:18:25 +03:00
Sergey ArkhipovandGitHub cf43ae780b Merge pull request #129 from 9seconds/disable-antireplay
Possibility to disable antireplay cache
2020-02-03 11:32:30 +03:00
9seconds 2407748ab0 Update README 2020-02-03 11:27:12 +03:00
9seconds a47edf08d0 Add possibility to disable antireplay cache 2020-02-03 11:26:37 +03:00
9seconds 566955b8b7 Update dependencies 2019-12-10 14:24:03 +03:00
Sergey ArkhipovandGitHub 5cc07a54a2 Merge pull request #127 from 9seconds/close-connections
Implement connection TTLs for multiplexing
2019-12-10 14:21:34 +03:00
Sergey ArkhipovandGitHub ba2143a6ae Merge pull request #126 from 9seconds/ipv4
Prefer ipv6 protocol on direct connections
2019-12-10 14:21:18 +03:00
9seconds acb02baa2e Implement connection TTLs for multiplexing 2019-12-10 14:13:26 +03:00
9seconds 422ed5b071 Prefer ipv6 protocol on direct connections 2019-12-10 13:59:27 +03:00
Sergey ArkhipovandGitHub 19efcc93fc Merge pull request #123 from 9seconds/panic-on-err
Crash if we can't allocate incoming connection
2019-12-04 10:37:20 +03:00
9seconds b4c47ff4e1 Crash if we can't allocate incoming connection 2019-12-04 10:22:35 +03:00
Sergey ArkhipovandGitHub 8a783d6b4e Merge pull request #122 from 9seconds/close-connections
Make cloaking more robust
2019-12-04 10:17:39 +03:00
9seconds c5029c706c Cap max time in cloak mode 2019-12-03 13:56:37 +03:00
9seconds d7e565e0f5 Update dependencies 2019-12-03 11:31:28 +03:00
9seconds 93686377d5 Rewrite cloaking 2019-12-03 11:22:01 +03:00
9seconds 87de28636a Add new metrics 2019-12-03 10:02:56 +03:00
Sergey ArkhipovandGitHub 7788b169b6 Merge pull request #121 from 9seconds/fix-run-sh
Make run.sh more robust
2019-11-25 10:37:46 +03:00
9seconds 6b9601fc2c Use stable version of mtg for run.sh 2019-11-25 10:31:40 +03:00
9seconds a65cb05d20 Make run.sh more robust 2019-11-25 10:31:19 +03:00
9seconds 31866d5f64 Update dependencies 2019-11-25 10:05:29 +03:00
Sergey ArkhipovandGitHub 0db83a0cc8 Merge pull request #117 from rlex/readme_fix
Fix units in readme
2019-11-20 10:13:17 +03:00
Lex Rivera 40bb59faf5 Fix units in readme 2019-11-19 18:38:30 +03:00
9seconds cac476901d Merge remote-tracking branch 'origin/master' into stable 2019-11-19 18:13:43 +03:00
9seconds 307910fe4a More reasonable version management 2019-11-19 18:13:35 +03:00
9seconds bb21bf814f Merge remote-tracking branch 'origin/master' into stable 2019-11-19 17:58:10 +03:00
9seconds 4c2c468289 Update dependencies 2019-11-19 15:28:53 +03:00
Sergey ArkhipovandGitHub f2f7c2a4de Merge pull request #115 from 9seconds/gogettable
Make mtg go-gettable
2019-11-19 11:55:33 +03:00
Sergey ArkhipovandGitHub 8fdd4292b1 Merge pull request #116 from 9seconds/gcoldconnections
Forcefully cleanup old connections
2019-11-19 11:55:07 +03:00
9seconds 44d339d777 Forcefully cleanup old connections 2019-11-19 11:49:27 +03:00
9seconds c6223e256d Fix prometheus namespace 2019-11-19 11:39:09 +03:00
9seconds 7928c2b323 Rename app from MTG to mtg 2019-11-19 11:37:30 +03:00
9seconds b2e7e1a225 Use buildinfo to get a version 2019-11-19 11:36:14 +03:00
9seconds 843fc4b70f Rename module from mtg to github.com/9seconds/mtg 2019-11-19 11:17:14 +03:00
62 changed files with 486 additions and 234 deletions
+1 -1
View File
@@ -10,4 +10,4 @@ format = "colored-line-number"
[linters] [linters]
enable-all = true enable-all = true
disable = ["gochecknoglobals"] disable = ["gochecknoglobals", "gomnd"]
+1 -1
View File
@@ -4,7 +4,7 @@ APP_NAME := $(IMAGE_NAME)
CC_BINARIES := $(shell bash -c "echo -n $(APP_NAME)-{linux,freebsd,openbsd}-{386,amd64} $(APP_NAME)-linux-{arm,arm64}") CC_BINARIES := $(shell bash -c "echo -n $(APP_NAME)-{linux,freebsd,openbsd}-{386,amd64} $(APP_NAME)-linux-{arm,arm64}")
GOLANGCI_LINT_VERSION := v1.21.0 GOLANGCI_LINT_VERSION := v1.23.3
VERSION_GO := $(shell go version) VERSION_GO := $(shell go version)
VERSION_DATE := $(shell date -Ru) VERSION_DATE := $(shell date -Ru)
+5 -2
View File
@@ -159,6 +159,9 @@ by design and we have the negligible possibility of duplication
(probability is 1/(2^64)) but it could be quite effective to prevent (probability is 1/(2^64)) but it could be quite effective to prevent
replays. replays.
It is possible to disable this cache. To do that, please explicitly set
its size to 0.
## FakeTLS ## FakeTLS
@@ -191,8 +194,8 @@ supported environment variables:
| `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_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_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_STATSD_TAGS` | `--statsd-tags` | | Which tags should we send to statsd with our metrics. Please specify them as `key=value` pairs. |
| `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_WRITE` | `-w`, `--write-buffer` | `64KB` | 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_BUFFER_READ` | `-r`, `--read-buffer` | `128KB` | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client. |
| `MTG_ANTIREPLAY_MAXSIZE` | `--anti-replay-max-size` | `128MB` | Max size of antireplay cache. | | `MTG_ANTIREPLAY_MAXSIZE` | `--anti-replay-max-size` | `128MB` | Max size of antireplay cache. |
| `MTG_CLOAK_PORT` | `--cloak-port` | `443` | Which port we should use to connect to cloaked host in FakeTLS mode. | | `MTG_CLOAK_PORT` | `--cloak-port` | `443` | Which port we should use to connect to cloaked host in FakeTLS mode. |
| `MTG_MULTIPLEX_PERCONNECTION` | `--multiplex-per-connection` | `50` | How many client connections can share a single Telegram connection in adtag mode | | `MTG_MULTIPLEX_PERCONNECTION` | `--multiplex-per-connection` | `50` | How many client connections can share a single Telegram connection in adtag mode |
+4 -4
View File
@@ -11,19 +11,19 @@ type cache struct {
data *fastcache.Cache data *fastcache.Cache
} }
func (c *cache) AddObfuscated2(data []byte) { func (c cache) AddObfuscated2(data []byte) {
c.data.Set(keyObfuscated2(data), nil) c.data.Set(keyObfuscated2(data), nil)
} }
func (c *cache) AddTLS(data []byte) { func (c cache) AddTLS(data []byte) {
c.data.Set(keyTLS(data), nil) c.data.Set(keyTLS(data), nil)
} }
func (c *cache) HasObfuscated2(data []byte) bool { func (c cache) HasObfuscated2(data []byte) bool {
return c.data.Has(keyObfuscated2(data)) return c.data.Has(keyObfuscated2(data))
} }
func (c *cache) HasTLS(data []byte) bool { func (c cache) HasTLS(data []byte) bool {
return c.data.Has(keyTLS(data)) return c.data.Has(keyTLS(data))
} }
+14 -3
View File
@@ -5,16 +5,27 @@ import (
"github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/fastcache"
"mtg/config" "github.com/9seconds/mtg/config"
) )
type CacheInterface interface {
AddObfuscated2([]byte)
AddTLS([]byte)
HasObfuscated2([]byte) bool
HasTLS([]byte) bool
}
var ( var (
Cache cache Cache CacheInterface
initOnce sync.Once initOnce sync.Once
) )
func Init() { func Init() {
initOnce.Do(func() { initOnce.Do(func() {
Cache.data = fastcache.New(config.C.AntiReplayMaxSize) if config.C.AntiReplayMaxSize == 0 {
Cache = nilCache{}
} else {
Cache = cache{fastcache.New(config.C.AntiReplayMaxSize)}
}
}) })
} }
+8
View File
@@ -0,0 +1,8 @@
package antireplay
type nilCache struct{}
func (n nilCache) AddObfuscated2(_ []byte) {}
func (n nilCache) AddTLS(_ []byte) {}
func (n nilCache) HasObfuscated2(_ []byte) bool { return false }
func (n nilCache) HasTLS(_ []byte) bool { return false }
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"mtg/config" "github.com/9seconds/mtg/config"
) )
func Generate(secretType, hostname string) { func Generate(secretType, hostname string) {
+10 -10
View File
@@ -8,16 +8,16 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"mtg/antireplay" "github.com/9seconds/mtg/antireplay"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/faketls" "github.com/9seconds/mtg/faketls"
"mtg/hub" "github.com/9seconds/mtg/hub"
"mtg/ntp" "github.com/9seconds/mtg/ntp"
"mtg/obfuscated2" "github.com/9seconds/mtg/obfuscated2"
"mtg/proxy" "github.com/9seconds/mtg/proxy"
"mtg/stats" "github.com/9seconds/mtg/stats"
"mtg/telegram" "github.com/9seconds/mtg/telegram"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
func Proxy() error { // nolint: funlen func Proxy() error { // nolint: funlen
+11 -28
View File
@@ -8,17 +8,16 @@ import (
"io" "io"
"net" "net"
"strconv" "strconv"
"sync"
"time" "time"
"mtg/antireplay" "github.com/9seconds/mtg/antireplay"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/obfuscated2" "github.com/9seconds/mtg/obfuscated2"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
"mtg/stats" "github.com/9seconds/mtg/stats"
"mtg/tlstypes" "github.com/9seconds/mtg/tlstypes"
"mtg/wrappers/stream" "github.com/9seconds/mtg/wrappers/stream"
) )
type ClientProtocol struct { type ClientProtocol struct {
@@ -101,6 +100,8 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
} }
func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) { func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) {
stats.Stats.CloakedRequest()
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort)) addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort))
hostConn, err := net.Dial("tcp", addr) hostConn, err := net.Dial("tcp", addr)
@@ -108,25 +109,7 @@ func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) {
return return
} }
defer hostConn.Close() cloak(clientConn, hostConn)
wg := &sync.WaitGroup{}
wg.Add(2)
go c.pipe(hostConn, clientConn, wg)
go c.pipe(clientConn, hostConn, wg)
wg.Wait()
}
func (c *ClientProtocol) pipe(dst io.WriteCloser, src io.Reader, wg *sync.WaitGroup) {
defer func() {
wg.Done()
dst.Close()
}()
io.Copy(dst, src) // nolint: errcheck
} }
func MakeClientProtocol() protocol.ClientProtocol { func MakeClientProtocol() protocol.ClientProtocol {
+71
View File
@@ -0,0 +1,71 @@
package faketls
import (
"context"
"io"
"sync"
"time"
"github.com/9seconds/mtg/wrappers/rwc"
)
const (
cloakLastActivityTimeout = 5 * time.Second
cloakMaxTimeout = 30 * time.Second
)
func cloak(one, another io.ReadWriteCloser) {
defer func() {
one.Close()
another.Close()
}()
channelPing := make(chan struct{}, 1)
ctx, cancel := context.WithCancel(context.Background())
one = rwc.NewPing(ctx, one, channelPing)
another = rwc.NewPing(ctx, another, channelPing)
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
io.Copy(one, another) // nolint: errcheck
}()
go func() {
defer wg.Done()
io.Copy(another, one) // nolint: errcheck
}()
go func() {
wg.Wait()
cancel()
}()
go func() {
lastActivityTimer := time.NewTimer(cloakLastActivityTimeout)
defer lastActivityTimer.Stop()
maxTimer := time.NewTimer(cloakMaxTimeout)
defer maxTimer.Stop()
for {
select {
case <-channelPing:
lastActivityTimer.Stop()
lastActivityTimer = time.NewTimer(cloakLastActivityTimeout)
case <-ctx.Done():
return
case <-lastActivityTimer.C:
cancel()
return
case <-maxTimer.C:
cancel()
return
}
}
}()
<-ctx.Done()
}
+10 -9
View File
@@ -1,20 +1,21 @@
module mtg module github.com/9seconds/mtg
go 1.13 go 1.13
require ( require (
github.com/VictoriaMetrics/fastcache v1.5.2 github.com/VictoriaMetrics/fastcache v1.5.7
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
github.com/beevik/ntp v0.2.0 github.com/beevik/ntp v0.2.0
github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/golang/protobuf v1.3.3 // indirect
github.com/prometheus/client_golang v1.2.1 github.com/prometheus/client_golang v1.4.0
github.com/prometheus/procfs v0.0.7 // indirect
github.com/smira/go-statsd v1.3.1 github.com/smira/go-statsd v1.3.1
go.uber.org/atomic v1.5.1 // indirect
go.uber.org/multierr v1.4.0 // indirect go.uber.org/multierr v1.4.0 // indirect
go.uber.org/zap v1.13.0 go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d
golang.org/x/net v0.0.0-20191116160921-f9c825593386 // indirect golang.org/x/lint v0.0.0-20200130185559-910be7a94367 // indirect
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6 golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3 // indirect golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
) )
+40 -34
View File
@@ -1,9 +1,7 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
github.com/VictoriaMetrics/fastcache v1.5.2 h1:Erd8iIuBAL9kke8JzM4+WxkKuFkHh3ktwLanJvDgR44=
github.com/VictoriaMetrics/fastcache v1.5.2/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= 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/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
@@ -24,11 +22,6 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM=
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -47,16 +40,18 @@ 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/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -81,33 +76,29 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI=
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 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-20180712105110-5c3871d89910/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 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= 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-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.0.7 h1:RS5GAlMbnkWkhs4+bPocMTmGjYkuCY5djjqEDdXOhcQ=
github.com/prometheus/procfs v0.0.7/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smira/go-statsd v1.3.1 h1:JalGiHNdK7GqVAPpg7j0Kwp2jZrz/fCg/B4ZuNuBY2w= github.com/smira/go-statsd v1.3.1 h1:JalGiHNdK7GqVAPpg7j0Kwp2jZrz/fCg/B4ZuNuBY2w=
github.com/smira/go-statsd v1.3.1/go.mod h1:1srXJ9/pbnN04G8f4F1jUzsGOnwkPKXciyqpewGlkC4= github.com/smira/go-statsd v1.3.1/go.mod h1:1srXJ9/pbnN04G8f4F1jUzsGOnwkPKXciyqpewGlkC4=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
@@ -118,6 +109,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
@@ -129,18 +122,23 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f h1:kz4KIr+xcPUsI3VMoqWfPMvtnJ6MGfiVwsWSVzphMO4= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191116160921-f9c825593386 h1:ktbWvQrW08Txdxno1PiDpSxPXG6ndGsfnJjRRtkM0LQ= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -151,28 +149,36 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6 h1:8mlr2HX+lfl0eaQcjiHfVeM2FHxWkuYQ5a2Wcy8mE1s= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3 h1:3gzOmNy3PLCZ+3Ru/n5Gh7pPjsieiytYSDxFj6QY/oI= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74 h1:KW20qMcLRWuIgjdCpHFJbVZA7zsDKtFXPNcm7/eI5ZA=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 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/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+13 -4
View File
@@ -4,15 +4,18 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"sync" "sync"
"time"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/mtproto" "github.com/9seconds/mtg/mtproto"
"mtg/mtproto/rpc" "github.com/9seconds/mtg/mtproto/rpc"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
) )
const connectionTTL = time.Hour
type connection struct { type connection struct {
conn conntypes.PacketReadWriteCloser conn conntypes.PacketReadWriteCloser
proxyConns map[string]*ProxyConn proxyConns map[string]*ProxyConn
@@ -31,6 +34,9 @@ type connection struct {
func (c *connection) run() { func (c *connection) run() {
defer c.Close() defer c.Close()
ttl := time.NewTimer(connectionTTL)
defer ttl.Stop()
for { for {
select { select {
case <-c.channelDone: case <-c.channelDone:
@@ -39,6 +45,9 @@ func (c *connection) run() {
} }
return return
case <-ttl.C:
c.logger.Debugw("Closing connection by TTL")
c.Close()
case resp := <-c.channelRead: case resp := <-c.channelRead:
if channel, ok := c.proxyConns[string(resp.ConnID[:])]; ok { if channel, ok := c.proxyConns[string(resp.ConnID[:])]; ok {
if resp.Type == rpc.ProxyResponseTypeCloseExt { if resp.Type == rpc.ProxyResponseTypeCloseExt {
+5 -6
View File
@@ -4,18 +4,14 @@ import (
"fmt" "fmt"
"sort" "sort"
"mtg/config" "github.com/9seconds/mtg/config"
) )
type connectionList struct { type connectionList struct {
connections []*connection connections []*connection
} }
func (c *connectionList) Get(conn *ProxyConn) (*connection, error) { func (c *connectionList) get(conn *ProxyConn) (*connection, error) {
if len(c.connections) > 0 {
c.gc()
}
if len(c.connections) > 0 && c.connections[0].Len() < config.C.MultiplexPerConnection { if len(c.connections) > 0 && c.connections[0].Len() < config.C.MultiplexPerConnection {
if err := c.connections[0].Attach(conn); err == nil { if err := c.connections[0].Attach(conn); err == nil {
return c.connections[0], nil return c.connections[0], nil
@@ -41,6 +37,9 @@ func (c *connectionList) Get(conn *ProxyConn) (*connection, error) {
func (c *connectionList) gc() { func (c *connectionList) gc() {
prevLen := len(c.connections) prevLen := len(c.connections)
if prevLen == 0 {
return
}
for i := len(c.connections) - 1; i >= 0; i-- { for i := len(c.connections) - 1; i >= 0; i-- {
lastIndex := len(c.connections) - 1 lastIndex := len(c.connections) - 1
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context" "context"
"sync" "sync"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
) )
type hub struct { type hub struct {
+1 -1
View File
@@ -1,6 +1,6 @@
package hub package hub
import "mtg/protocol" import "github.com/9seconds/mtg/protocol"
type Interface interface { type Interface interface {
Register(*protocol.TelegramRequest) (*ProxyConn, error) Register(*protocol.TelegramRequest) (*ProxyConn, error)
+12 -3
View File
@@ -2,11 +2,14 @@ package hub
import ( import (
"context" "context"
"time"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
) )
const muxGCEvery = time.Minute
type muxNewRequest struct { type muxNewRequest struct {
req *protocol.TelegramRequest req *protocol.TelegramRequest
resp chan<- muxNewResponse resp chan<- muxNewResponse
@@ -26,6 +29,9 @@ type mux struct {
} }
func (m *mux) run() { func (m *mux) run() {
gcTicker := time.NewTicker(muxGCEvery)
defer gcTicker.Stop()
for { for {
select { select {
case <-m.ctx.Done(): case <-m.ctx.Done():
@@ -34,9 +40,12 @@ func (m *mux) run() {
} }
return return
case <-gcTicker.C:
m.connections.gc()
case req := <-m.channelNew: case req := <-m.channelNew:
m.connections.gc()
proxyConn := newProxyConn(req.req, m.channelClosed) proxyConn := newProxyConn(req.req, m.channelClosed)
conn, err := m.connections.Get(proxyConn) conn, err := m.connections.get(proxyConn)
if err == nil { if err == nil {
m.clients[string(req.req.ConnID[:])] = conn m.clients[string(req.req.ConnID[:])] = conn
+3 -3
View File
@@ -4,9 +4,9 @@ import (
"sync" "sync"
"time" "time"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/mtproto/rpc" "github.com/9seconds/mtg/mtproto/rpc"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
) )
const ( const (
+29 -5
View File
@@ -3,16 +3,18 @@ package main
import ( import (
"math/rand" "math/rand"
"os" "os"
"runtime/debug"
"strings"
"time" "time"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
"mtg/cli" "github.com/9seconds/mtg/cli"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
var version = "dev" // this has to be set by build ld flags var version = "dev" // has to be set by ldflags
var ( var (
app = kingpin.New("mtg", "Simple MTPROTO proxy.") app = kingpin.New("mtg", "Simple MTPROTO proxy.")
@@ -114,7 +116,7 @@ var (
func main() { func main() {
rand.Seed(time.Now().UTC().UnixNano()) rand.Seed(time.Now().UTC().UnixNano())
app.Version(version) app.Version(getVersion())
app.HelpFlag.Short('h') app.HelpFlag.Short('h')
if err := utils.SetLimits(); err != nil { if err := utils.SetLimits(); err != nil {
@@ -153,3 +155,25 @@ func main() {
} }
} }
} }
func getVersion() string {
if version != "dev" {
return version
}
info, ok := debug.ReadBuildInfo()
if !ok {
return version
}
builder := strings.Builder{}
builder.WriteString(info.Main.Version)
if info.Main.Sum != "" {
builder.WriteString(" (checksum: ")
builder.WriteString(info.Main.Sum)
builder.WriteRune(')')
}
return builder.String()
}
+6 -6
View File
@@ -3,12 +3,12 @@ package mtproto
import ( import (
"fmt" "fmt"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/mtproto/rpc" "github.com/9seconds/mtg/mtproto/rpc"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
"mtg/telegram" "github.com/9seconds/mtg/telegram"
"mtg/wrappers/packet" "github.com/9seconds/mtg/wrappers/packet"
"mtg/wrappers/stream" "github.com/9seconds/mtg/wrappers/stream"
) )
func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.PacketReadWriteCloser, error) { func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.PacketReadWriteCloser, error) {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type ProxyResponseType uint8 type ProxyResponseType uint8
+7 -7
View File
@@ -9,13 +9,13 @@ import (
"io" "io"
"time" "time"
"mtg/antireplay" "github.com/9seconds/mtg/antireplay"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
"mtg/stats" "github.com/9seconds/mtg/stats"
"mtg/utils" "github.com/9seconds/mtg/utils"
"mtg/wrappers/stream" "github.com/9seconds/mtg/wrappers/stream"
) )
const clientProtocolHandshakeTimeout = 10 * time.Second const clientProtocolHandshakeTimeout = 10 * time.Second
+5 -5
View File
@@ -4,11 +4,11 @@ import (
"crypto/rand" "crypto/rand"
"fmt" "fmt"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
"mtg/telegram" "github.com/9seconds/mtg/telegram"
"mtg/utils" "github.com/9seconds/mtg/utils"
"mtg/wrappers/stream" "github.com/9seconds/mtg/wrappers/stream"
) )
func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.StreamReadWriteCloser, error) { func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.StreamReadWriteCloser, error) {
+1 -1
View File
@@ -1,6 +1,6 @@
package protocol package protocol
import "mtg/conntypes" import "github.com/9seconds/mtg/conntypes"
type ClientProtocol interface { type ClientProtocol interface {
Handshake(conntypes.StreamReadWriteCloser) (conntypes.StreamReadWriteCloser, error) Handshake(conntypes.StreamReadWriteCloser) (conntypes.StreamReadWriteCloser, error)
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type TelegramRequest struct { type TelegramRequest struct {
+3 -3
View File
@@ -6,9 +6,9 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/obfuscated2" "github.com/9seconds/mtg/obfuscated2"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
) )
const directPipeBufferSize = 1024 * 1024 const directPipeBufferSize = 1024 * 1024
+3 -3
View File
@@ -5,9 +5,9 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
"mtg/wrappers/packetack" "github.com/9seconds/mtg/wrappers/packetack"
) )
func middleConnection(request *protocol.TelegramRequest) { func middleConnection(request *protocol.TelegramRequest) {
+10 -8
View File
@@ -6,12 +6,12 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
"mtg/stats" "github.com/9seconds/mtg/stats"
"mtg/utils" "github.com/9seconds/mtg/utils"
"mtg/wrappers/stream" "github.com/9seconds/mtg/wrappers/stream"
) )
type Proxy struct { type Proxy struct {
@@ -30,8 +30,7 @@ func (p *Proxy) Serve(listener net.Listener) {
case <-doneChan: case <-doneChan:
return return
default: default:
p.Logger.Errorw("Cannot allocate incoming connection", "error", err) p.Logger.Fatalw("Cannot allocate incoming connection", "error", err)
continue
} }
} }
@@ -42,6 +41,7 @@ func (p *Proxy) Serve(listener net.Listener) {
func (p *Proxy) accept(conn net.Conn) { func (p *Proxy) accept(conn net.Conn) {
defer func() { defer func() {
conn.Close() conn.Close()
if err := recover(); err != nil { if err := recover(); err != nil {
stats.Stats.Crash() stats.Stats.Crash()
p.Logger.Errorw("Crash of accept handler", "error", err) p.Logger.Errorw("Crash of accept handler", "error", err)
@@ -69,7 +69,9 @@ func (p *Proxy) accept(conn net.Conn) {
clientConn, err := clientProtocol.Handshake(clientConn) clientConn, err := clientProtocol.Handshake(clientConn)
if err != nil { if err != nil {
stats.Stats.AuthenticationFailed()
logger.Warnw("Cannot perform client handshake", "error", err) logger.Warnw("Cannot perform client handshake", "error", err)
return return
} }
+22 -12
View File
@@ -11,48 +11,58 @@
# export MTG_IMAGENAME="nineseconds/mtg:latest" # export MTG_IMAGENAME="nineseconds/mtg:latest"
# curl -sfL --compressed https://raw.githubusercontent.com/9seconds/mtg/master/run.sh | bash # curl -sfL --compressed https://raw.githubusercontent.com/9seconds/mtg/master/run.sh | bash
set -eu -o pipefail set -eu
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export MTG_CONFIG="${MTG_CONFIG:-$XDG_CONFIG_HOME/mtg}" export MTG_CONFIG="${MTG_CONFIG:-$XDG_CONFIG_HOME/mtg}"
if ! [ -x "$(command -v docker)" ]; then
echo 'Error: docker is not installed.' >&2
exit 1
fi
id -Gn "$USER" | grep -qw 'docker' > /dev/null
if [ $? -eq 0 ] || [ "$(id -u)" -eq '0' ]; then
DOCKER_CMD="$(command -v docker)"
else
DOCKER_CMD="sudo $(command -v docker)"
fi
mkdir -p "$MTG_CONFIG" || true mkdir -p "$MTG_CONFIG" || true
MTG_SECRET="$MTG_CONFIG/secret" MTG_SECRET="$MTG_CONFIG/secret"
MTG_ENV="$MTG_CONFIG/env" MTG_ENV="$MTG_CONFIG/env"
if [ ! -f "$MTG_ENV" ]; then if [ ! -f "$MTG_ENV" ]; then
MTG_IMAGENAME="${MTG_IMAGENAME:-nineseconds/mtg:latest}" MTG_IMAGENAME="${MTG_IMAGENAME:-nineseconds/mtg:stable}"
MTG_PORT="${MTG_PORT:-3128}" MTG_PORT="${MTG_PORT:-3128}"
MTG_CONTAINER="${MTG_CONTAINER:-mtg}" MTG_CONTAINER="${MTG_CONTAINER:-mtg}"
echo "MTG_IMAGENAME=${MTG_IMAGENAME}" > "$MTG_ENV" echo "MTG_IMAGENAME=$MTG_IMAGENAME" > "$MTG_ENV"
echo "MTG_PORT=${MTG_PORT}" >> "$MTG_ENV" echo "MTG_PORT=$MTG_PORT" >> "$MTG_ENV"
echo "MTG_CONTAINER=${MTG_CONTAINER}" >> "$MTG_ENV" echo "MTG_CONTAINER=$MTG_CONTAINER" >> "$MTG_ENV"
fi fi
set -a set -a
source "$MTG_ENV" source "$MTG_ENV"
set +a set +a
docker pull "$MTG_IMAGENAME" $DOCKER_CMD pull "$MTG_IMAGENAME" > /dev/null
if [ ! -f "$MTG_SECRET" ]; then if [ ! -f "$MTG_SECRET" ]; then
docker run \ $DOCKER_CMD run \
--rm \ --rm \
"$MTG_IMAGENAME" \ "$MTG_IMAGENAME" \
generate-secret tls -c "$(openssl rand -hex 16).com" \ generate-secret tls -c "$(openssl rand -hex 16).com" \
> "$MTG_SECRET" > "$MTG_SECRET"
fi fi
echo
echo "Proxy secret is $(cat "$MTG_SECRET"). Port is $MTG_PORT." echo "Proxy secret is $(cat "$MTG_SECRET"). Port is $MTG_PORT."
echo
docker ps --filter "Name=$MTG_CONTAINER" -aq | xargs -r docker rm -fv $DOCKER_CMD ps --filter "Name=$MTG_CONTAINER" -aq | xargs -r $DOCKER_CMD rm -fv > /dev/null
docker run \ $DOCKER_CMD run \
-d \ -d \
--restart=unless-stopped \ --restart=unless-stopped \
--name "$MTG_CONTAINER" \ --name "$MTG_CONTAINER" \
--ulimit nofile=51200:51200 \ --ulimit nofile=51200:51200 \
-p "$MTG_PORT:3128" \ -p "$MTG_PORT:3128" \
"$MTG_IMAGENAME" run "$(cat "$MTG_SECRET")" "$MTG_IMAGENAME" run "$(cat "$MTG_SECRET")" > /dev/null
+11 -1
View File
@@ -3,7 +3,7 @@ package stats
import ( import (
"net" "net"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type IngressTrafficInterface interface { type IngressTrafficInterface interface {
@@ -38,6 +38,14 @@ type ReplayDetectedInterface interface {
ReplayDetected() ReplayDetected()
} }
type AuthenticationFailedInterface interface {
AuthenticationFailed()
}
type CloakedRequestInterface interface {
CloakedRequest()
}
type Interface interface { type Interface interface {
IngressTrafficInterface IngressTrafficInterface
EgressTrafficInterface EgressTrafficInterface
@@ -47,4 +55,6 @@ type Interface interface {
TelegramDisconnectedInterface TelegramDisconnectedInterface
CrashInterface CrashInterface
ReplayDetectedInterface ReplayDetectedInterface
AuthenticationFailedInterface
CloakedRequestInterface
} }
+13 -1
View File
@@ -3,7 +3,7 @@ package stats
import ( import (
"net" "net"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type multiStats []Interface type multiStats []Interface
@@ -55,3 +55,15 @@ func (m multiStats) ReplayDetected() {
go m[i].ReplayDetected() go m[i].ReplayDetected()
} }
} }
func (m multiStats) AuthenticationFailed() {
for i := range m {
go m[i].AuthenticationFailed()
}
}
func (m multiStats) CloakedRequest() {
for i := range m {
go m[i].CloakedRequest()
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"net" "net"
"net/http" "net/http"
"mtg/config" "github.com/9seconds/mtg/config"
) )
var Stats Interface var Stats Interface
+24 -2
View File
@@ -8,8 +8,8 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type statsPrometheus struct { type statsPrometheus struct {
@@ -18,6 +18,8 @@ type statsPrometheus struct {
traffic *prometheus.GaugeVec traffic *prometheus.GaugeVec
crashes prometheus.Counter crashes prometheus.Counter
replayAttacks prometheus.Counter replayAttacks prometheus.Counter
authenticationFailed prometheus.Counter
cloakedRequests prometheus.Counter
} }
func (s *statsPrometheus) IngressTraffic(traffic int) { func (s *statsPrometheus) IngressTraffic(traffic int) {
@@ -87,6 +89,14 @@ func (s *statsPrometheus) ReplayDetected() {
s.replayAttacks.Inc() s.replayAttacks.Inc()
} }
func (s *statsPrometheus) AuthenticationFailed() {
s.authenticationFailed.Inc()
}
func (s *statsPrometheus) CloakedRequest() {
s.cloakedRequests.Inc()
}
func newStatsPrometheus(mux *http.ServeMux) Interface { func newStatsPrometheus(mux *http.ServeMux) Interface {
registry := prometheus.NewPedanticRegistry() registry := prometheus.NewPedanticRegistry()
@@ -116,6 +126,16 @@ func newStatsPrometheus(mux *http.ServeMux) Interface {
Name: "replay_attacks", Name: "replay_attacks",
Help: "How many replay attacks were prevented.", Help: "How many replay attacks were prevented.",
}), }),
authenticationFailed: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: config.C.StatsNamespace,
Name: "authentication_failed",
Help: "How many authentication failed events we've seen.",
}),
cloakedRequests: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: config.C.StatsNamespace,
Name: "cloaked_requests",
Help: "How many requests were proxified during cloaking.",
}),
} }
registry.MustRegister(instance.connections) registry.MustRegister(instance.connections)
@@ -123,6 +143,8 @@ func newStatsPrometheus(mux *http.ServeMux) Interface {
registry.MustRegister(instance.traffic) registry.MustRegister(instance.traffic)
registry.MustRegister(instance.crashes) registry.MustRegister(instance.crashes)
registry.MustRegister(instance.replayAttacks) registry.MustRegister(instance.replayAttacks)
registry.MustRegister(instance.authenticationFailed)
registry.MustRegister(instance.cloakedRequests)
handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
mux.Handle("/", handler) mux.Handle("/", handler)
+10 -2
View File
@@ -11,8 +11,8 @@ import (
statsd "github.com/smira/go-statsd" statsd "github.com/smira/go-statsd"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
var ( var (
@@ -137,6 +137,14 @@ func (s *statsStatsd) ReplayDetected() {
s.gauge("replay_attacks", 1) s.gauge("replay_attacks", 1)
} }
func (s *statsStatsd) AuthenticationFailed() {
s.gauge("authentication_failed", 1)
}
func (s *statsStatsd) CloakedRequest() {
s.gauge("cloaked_requests", 1)
}
func (s *statsStatsd) gauge(metric string, value int64, tags ...*statsStatsdTag) { func (s *statsStatsd) gauge(metric string, value int64, tags ...*statsStatsdTag) {
key, tagList := s.prepareVals(metric, tags) key, tagList := s.prepareVals(metric, tags)
s.initGauge(metric, key, tagList) s.initGauge(metric, key, tagList)
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
const ( const (
+1 -1
View File
@@ -9,7 +9,7 @@ import (
) )
const ( const (
apiUserAgent = "mtg" apiUserAgent = "github.com/9seconds/mtg"
apiHTTPTimeout = 30 * time.Second apiHTTPTimeout = 30 * time.Second
) )
+23 -13
View File
@@ -1,21 +1,24 @@
package telegram package telegram
import ( import (
"fmt" "errors"
"math/rand" "math/rand"
"net" "net"
"mtg/conntypes" "go.uber.org/zap"
"mtg/utils"
"mtg/wrappers/stream" "github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/utils"
"github.com/9seconds/mtg/wrappers/stream"
) )
type baseTelegram struct { type baseTelegram struct {
dialer net.Dialer dialer net.Dialer
logger *zap.SugaredLogger
secret []byte secret []byte
v4DefaultDC conntypes.DC v4DefaultDC conntypes.DC
V6DefaultDC conntypes.DC v6DefaultDC conntypes.DC
v4Addresses map[conntypes.DC][]string v4Addresses map[conntypes.DC][]string
v6Addresses map[conntypes.DC][]string v6Addresses map[conntypes.DC][]string
} }
@@ -26,27 +29,34 @@ func (b *baseTelegram) Secret() []byte {
func (b *baseTelegram) dial(dc conntypes.DC, func (b *baseTelegram) dial(dc conntypes.DC,
protocol conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) { protocol conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) {
addr := "" addresses := make([]string, 0, 2)
switch protocol { if protocol&conntypes.ConnectionProtocolIPv6 != 0 {
case conntypes.ConnectionProtocolIPv4: addresses = append(addresses, b.chooseAddress(b.v6Addresses, dc, b.v6DefaultDC))
addr = b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC)
default:
addr = b.chooseAddress(b.v6Addresses, dc, b.V6DefaultDC)
} }
if protocol&conntypes.ConnectionProtocolIPv4 != 0 {
addresses = append(addresses, b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC))
}
for _, addr := range addresses {
conn, err := b.dialer.Dial("tcp", addr) conn, err := b.dialer.Dial("tcp", addr)
if err != nil { if err != nil {
return nil, fmt.Errorf("dial has failed: %w", err) b.logger.Infow("Cannot dial to Telegram", "address", addr, "error", err)
continue
} }
if err := utils.InitTCP(conn); err != nil { if err := utils.InitTCP(conn); err != nil {
return nil, fmt.Errorf("cannot initialize tcp socket: %w", err) b.logger.Infow("Cannot initialize TCP socket", "address", addr, "error", err)
continue
} }
return stream.NewTelegramConn(dc, conn), nil return stream.NewTelegramConn(dc, conn), nil
} }
return nil, errors.New("cannot dial to the chosen DC")
}
func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string, func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
dc, defaultDC conntypes.DC) string { dc, defaultDC conntypes.DC) string {
addrs, ok := addresses[dc] addrs, ok := addresses[dc]
+2 -2
View File
@@ -1,6 +1,6 @@
package telegram package telegram
import "mtg/conntypes" import "github.com/9seconds/mtg/conntypes"
const ( const (
directV4DefaultIdx conntypes.DC = 1 directV4DefaultIdx conntypes.DC = 1
@@ -37,5 +37,5 @@ func (d *directTelegram) Dial(dc conntypes.DC,
dc = conntypes.DCDefaultIdx dc = conntypes.DCDefaultIdx
} }
return d.baseTelegram.dial(dc-1, protocol) return d.baseTelegram.dial(dc-1, conntypes.ConnectionProtocolAny)
} }
+7 -1
View File
@@ -4,6 +4,8 @@ import (
"net" "net"
"sync" "sync"
"time" "time"
"go.uber.org/zap"
) )
const telegramDialTimeout = 10 * time.Second const telegramDialTimeout = 10 * time.Second
@@ -17,11 +19,14 @@ var (
func Init() { func Init() {
initOnce.Do(func() { initOnce.Do(func() {
logger := zap.S().Named("telegram")
Direct = &directTelegram{ Direct = &directTelegram{
baseTelegram: baseTelegram{ baseTelegram: baseTelegram{
dialer: net.Dialer{Timeout: telegramDialTimeout}, dialer: net.Dialer{Timeout: telegramDialTimeout},
logger: logger.Named("direct"),
v4DefaultDC: directV4DefaultIdx, v4DefaultDC: directV4DefaultIdx,
V6DefaultDC: directV6DefaultIdx, v6DefaultDC: directV6DefaultIdx,
v4Addresses: directV4Addresses, v4Addresses: directV4Addresses,
v6Addresses: directV6Addresses, v6Addresses: directV6Addresses,
}, },
@@ -30,6 +35,7 @@ func Init() {
tg := &middleTelegram{ tg := &middleTelegram{
baseTelegram: baseTelegram{ baseTelegram: baseTelegram{
dialer: net.Dialer{Timeout: telegramDialTimeout}, dialer: net.Dialer{Timeout: telegramDialTimeout},
logger: logger.Named("middle"),
}, },
} }
if err := tg.update(); err != nil { if err := tg.update(); err != nil {
+1 -1
View File
@@ -1,6 +1,6 @@
package telegram package telegram
import "mtg/conntypes" import "github.com/9seconds/mtg/conntypes"
type Telegram interface { type Telegram interface {
Dial(conntypes.DC, conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) Dial(conntypes.DC, conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error)
+3 -3
View File
@@ -7,8 +7,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/telegram/api" "github.com/9seconds/mtg/telegram/api"
) )
const middleTelegramBackgroundUpdateEvery = time.Hour const middleTelegramBackgroundUpdateEvery = time.Hour
@@ -45,7 +45,7 @@ func (m *middleTelegram) update() error {
m.mutex.Lock() m.mutex.Lock()
m.secret = secret m.secret = secret
m.v4DefaultDC = v4DefaultDC m.v4DefaultDC = v4DefaultDC
m.V6DefaultDC = v6DefaultDC m.v6DefaultDC = v6DefaultDC
m.v4Addresses = v4Addresses m.v4Addresses = v4Addresses
m.v6Addresses = v6Addresses m.v6Addresses = v6Addresses
m.mutex.Unlock() m.mutex.Unlock()
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
type ClientHello struct { type ClientHello struct {
+1 -1
View File
@@ -3,7 +3,7 @@ package tlstypes
import ( import (
"bytes" "bytes"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
type Handshake struct { type Handshake struct {
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
"mtg/config" "github.com/9seconds/mtg/config"
) )
type ServerHello struct { type ServerHello struct {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"net" "net"
"mtg/config" "github.com/9seconds/mtg/config"
) )
func InitTCP(conn net.Conn) error { func InitTCP(conn net.Conn) error {
+1 -1
View File
@@ -12,7 +12,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
const ( const (
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
const ( const (
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
const clientIntermediateQuickAckLength = 0x80000000 const clientIntermediateQuickAckLength = 0x80000000
@@ -8,7 +8,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type wrapperClientIntermediateSecure struct { type wrapperClientIntermediateSecure struct {
+5 -5
View File
@@ -6,11 +6,11 @@ import (
"fmt" "fmt"
"net" "net"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/hub" "github.com/9seconds/mtg/hub"
"mtg/mtproto/rpc" "github.com/9seconds/mtg/mtproto/rpc"
"mtg/protocol" "github.com/9seconds/mtg/protocol"
) )
type wrapperProxy struct { type wrapperProxy struct {
+48
View File
@@ -0,0 +1,48 @@
package rwc
import (
"context"
"io"
)
type wrapperPing struct {
parent io.ReadWriteCloser
ctx context.Context
channelPing chan<- struct{}
}
func (w *wrapperPing) Read(p []byte) (int, error) {
n, err := w.parent.Read(p)
if err == nil {
select {
case <-w.ctx.Done():
case w.channelPing <- struct{}{}:
}
}
return n, err
}
func (w *wrapperPing) Write(p []byte) (int, error) {
n, err := w.parent.Write(p)
if err == nil {
select {
case <-w.ctx.Done():
case w.channelPing <- struct{}{}:
}
}
return n, err
}
func (w *wrapperPing) Close() error {
return w.parent.Close()
}
func NewPing(ctx context.Context, parent io.ReadWriteCloser, channelPing chan<- struct{}) io.ReadWriteCloser {
return &wrapperPing{
parent: parent,
ctx: ctx,
channelPing: channelPing,
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ package stream
import ( import (
"net" "net"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
func NewClientConn(parent net.Conn, connID conntypes.ConnID) conntypes.StreamReadWriteCloser { func NewClientConn(parent net.Conn, connID conntypes.ConnID) conntypes.StreamReadWriteCloser {
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
type wrapperBlockCipher struct { type wrapperBlockCipher struct {
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/config" "github.com/9seconds/mtg/config"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type connPurpose uint8 type connPurpose uint8
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type wrapperCtx struct { type wrapperCtx struct {
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/tlstypes" "github.com/9seconds/mtg/tlstypes"
) )
type wrapperFakeTLS struct { type wrapperFakeTLS struct {
+3 -3
View File
@@ -9,9 +9,9 @@ import (
"encoding/binary" "encoding/binary"
"net" "net"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/mtproto/rpc" "github.com/9seconds/mtg/mtproto/rpc"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
type mtprotoCipherPurpose uint8 type mtprotoCipherPurpose uint8
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type wrapperObfuscated2 struct { type wrapperObfuscated2 struct {
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
type ReadWriteCloseRewinder interface { type ReadWriteCloseRewinder interface {
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/stats" "github.com/9seconds/mtg/stats"
) )
type wrapperTelegramStats struct { type wrapperTelegramStats struct {
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
"mtg/stats" "github.com/9seconds/mtg/stats"
) )
type wrapperTrafficStats struct { type wrapperTrafficStats struct {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes" "github.com/9seconds/mtg/conntypes"
) )
const ( const (