REPOSITORY / ScuroNeko/mtg

Compare commits

DIFF REPOSITORY

Compare commits

...
91 Commits
Author SHA1 Message Date
9seconds a8c4d0a9c4 Merge remote-tracking branch 'origin/master' into stable 2020-09-21 12:03:19 +03:00
9seconds bfeded67ee Update travis 2020-09-21 11:46:13 +03:00
9seconds dde0d25b77 Update golangci lint to 1.31.0 2020-09-21 11:45:09 +03:00
9seconds 296a34cd6e Update dockerfile to use 1.15 2020-09-21 11:44:06 +03:00
9seconds 44cea68e83 Upgrade dependencies 2020-09-21 11:43:23 +03:00
9seconds 790bf21166 Merge remote-tracking branch 'origin/master' into stable 2020-08-11 13:32:01 +03:00
Sergey ArkhipovandGitHub 5d17e264e6 Merge pull request #156 from 9seconds/no-pools
Get rid of sync pools
2020-08-10 15:20:15 +03:00
9seconds 7ef1e99f66 Add 1.14 to a travis 2020-08-10 15:02:05 +03:00
9seconds 3acbacbdb3 Install lint in a local directory 2020-08-10 15:01:38 +03:00
9seconds 5fd7062972 Update dependencies 2020-08-10 14:41:22 +03:00
9seconds 7a6695f6c4 Update golangci-lint 2020-08-10 14:39:50 +03:00
9seconds 8ac786581b Update golangci lint 2020-08-10 13:30:07 +03:00
9seconds 86a8f69273 Cleanup pools from wrappes 2020-08-10 13:29:08 +03:00
9seconds 95b16cd805 Cleanup pools from tlstypes 2020-08-10 13:27:23 +03:00
9seconds 3996b9a6b8 Remove pools from faketls 2020-08-10 13:21:30 +03:00
Sergey ArkhipovandGitHub e286dea650 Merge pull request #151 from FollowMeDown/master
Fix Keep-Alive Issue for OpenBSD/ArchLinux
2020-08-10 12:49:16 +03:00
DEFACE 5e27e48129 Fix Keep-Alive Issue for OpenBSD/ArchLinux 2020-06-15 21:38:35 +02:00
Sergey ArkhipovandGitHub 95abb54dc8 Merge pull request #146 from 9seconds/fix-docker-image
Updates for dockerfile
2020-05-19 11:31:25 +03:00
9seconds dbd3d3c266 Updates for dockerfile 2020-05-19 11:26:08 +03:00
9seconds e5b9c841cd Merge remote-tracking branch 'origin/master' into stable 2020-03-31 10:09:47 +03:00
9seconds ad7acee64d Update dependencies 2020-03-31 09:51:38 +03:00
Sergey ArkhipovandGitHub 9ce6674070 Merge pull request #144 from 9seconds/tune-buffers
Add possibility to scale middleproxy buffers
2020-03-31 09:51:40 +03:00
9seconds 25edb60f2c Use different formula for calculating proxy buffer 2020-03-31 09:45:59 +03:00
9seconds b5a8d8b804 Add possibility to scale middleproxy buffers 2020-03-30 16:53:14 +03:00
9seconds 8ccf61c23e Merge remote-tracking branch 'origin/master' into stable 2020-03-25 10:24:31 +03:00
9seconds 35f0fca3c5 Update dependencies 2020-03-25 10:24:17 +03:00
Sergey ArkhipovandGitHub cd46a734ea Merge pull request #143 from 9seconds/32kb
Tune buffer limits to 32kb by default
2020-03-25 10:15:47 +03:00
Sergey ArkhipovandGitHub cd92a343aa Merge pull request #142 from 9seconds/keep-alives
Set keep-alive for tcp connections
2020-03-25 10:07:26 +03:00
9seconds 289e8f5945 Tune buffer limits to 32kb by default 2020-03-25 10:07:10 +03:00
9seconds 850bed0dfc Set keep-alive for tcp connections 2020-03-25 10:01:17 +03:00
Sergey ArkhipovandGitHub 8977d77a13 Merge pull request #141 from 9seconds/change-defaults
Decrease defaults
2020-03-24 17:05:25 +03:00
9seconds 91726d461f Decrease defaults 2020-03-24 16:58:30 +03:00
Sergey ArkhipovandGitHub be1a47287a Merge pull request #140 from 9seconds/pools
Add pool support everywhere
2020-03-24 16:53:48 +03:00
9seconds 426483d27b Microoptimization 2020-03-24 16:46:39 +03:00
9seconds bc72717582 Fix a bug with crashing desktop telegram 2020-03-24 16:36:03 +03:00
9seconds 391d901402 Reset bytes buffer before returning back to a pool 2020-03-24 15:54:29 +03:00
9seconds 837d96dc43 Add pool support everywhere 2020-03-24 11:22:59 +03:00
9seconds 9125a29e79 Add pools for packetack 2020-03-23 17:08:13 +03:00
9seconds 6449109b2b Add pooler for mtproto_frame wrapper 2020-03-23 17:00:54 +03:00
9seconds 829669eefd Update dependencies 2020-03-23 15:10:41 +03:00
Sergey ArkhipovandGitHub 2d9f2345dc Merge pull request #139 from 9seconds/memory-direct
Memory optimizations for direct mode
2020-03-23 15:08:37 +03:00
9seconds 6a9069ca72 Fixes 2020-03-23 10:53:58 +03:00
9seconds d72ed03a43 Use pools for obfuscated2 write 2020-03-23 10:29:00 +03:00
9seconds f0d2cd494a Use stack allocation instead of heap one 2020-03-23 09:05:18 +03:00
9seconds b5810c955d Decrease a size of direct pipe buffer 2020-03-23 08:42:02 +03:00
9seconds 4ebae693e0 Memory optimizations for direct mode 2020-03-20 15:54:30 +03:00
9seconds 0e033b59b3 Merge remote-tracking branch 'origin/master' into stable 2020-03-20 14:39:45 +03:00
Sergey ArkhipovandGitHub 1a619e3090 Merge pull request #138 from 9seconds/ntp-servers
Add possibility to define your own ntp servers
2020-03-20 14:37:38 +03:00
9seconds 8e29ff78ba Add possibility to define your own ntp servers 2020-03-20 14:32:23 +03:00
Sergey ArkhipovandGitHub efdac2c0d8 Merge pull request #136 from 9seconds/prefer-options
Option for IP preference
2020-03-20 13:23:16 +03:00
Sergey ArkhipovandGitHub e559388802 Merge pull request #137 from 9seconds/golang-1.14
Use golang 1.14
2020-03-20 13:23:06 +03:00
9seconds cb691453f0 Allow golang 1.14 to fail 2020-03-20 13:17:35 +03:00
9seconds 020065f389 Use golang 1.14 2020-03-20 13:15:08 +03:00
9seconds cf5197cee0 Update golangci lint 2020-03-20 13:10:56 +03:00
9seconds 720158f15c Implement IP preferences 2020-03-20 13:09:30 +03:00
9seconds 07f00a363e Add new option for preferring of new IP 2020-03-20 12:51:56 +03:00
9seconds d32ab34e60 Update dependencies 2020-03-20 12:38:33 +03:00
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
77 changed files with 1104 additions and 385 deletions
+1
View File
@@ -9,3 +9,4 @@ mtg
vendor/ vendor/
version.go version.go
ccbuilds/ ccbuilds/
.bin/
+1 -1
View File
@@ -10,4 +10,4 @@ format = "colored-line-number"
[linters] [linters]
enable-all = true enable-all = true
disable = ["gochecknoglobals"] disable = ["gochecknoglobals", "gas", "gomnd", "goerr113"]
+2
View File
@@ -5,6 +5,8 @@ sudo: false
dist: trusty dist: trusty
go: go:
- 1.15.x
- 1.14.x
- 1.13.x - 1.13.x
- master - master
+6 -8
View File
@@ -1,7 +1,7 @@
############################################################################### ###############################################################################
# BUILD STAGE # BUILD STAGE
FROM golang:1.13-alpine FROM golang:1.15-alpine AS build
RUN set -x \ RUN set -x \
&& apk --no-cache --update add \ && apk --no-cache --update add \
@@ -13,9 +13,9 @@ RUN set -x \
upx upx
COPY . /go/src/github.com/9seconds/mtg/ COPY . /go/src/github.com/9seconds/mtg/
WORKDIR /go/src/github.com/9seconds/mtg
RUN set -x \ RUN set -x \
&& cd /go/src/github.com/9seconds/mtg \
&& make -j 4 static \ && make -j 4 static \
&& upx --ultra-brute -qq ./mtg && upx --ultra-brute -qq ./mtg
@@ -26,11 +26,9 @@ RUN set -x \
FROM scratch FROM scratch
ENTRYPOINT ["/mtg"] ENTRYPOINT ["/mtg"]
ENV MTG_IP=0.0.0.0 \ ENV MTG_BIND=0.0.0.0:3128 \
MTG_PORT=3128 \ MTG_STATS_BIND=0.0.0.0:3129
MTG_STATS_IP=0.0.0.0 \
MTG_STATS_PORT=3129
EXPOSE 3128 3129 EXPOSE 3128 3129
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=0 /go/src/github.com/9seconds/mtg/mtg /mtg COPY --from=build /go/src/github.com/9seconds/mtg/mtg /mtg
+5 -4
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.31.0
VERSION_GO := $(shell go version) VERSION_GO := $(shell go version)
VERSION_DATE := $(shell date -Ru) VERSION_DATE := $(shell date -Ru)
@@ -53,7 +53,7 @@ crosscompile-dir:
.PHONY: lint .PHONY: lint
lint: vendor lint: vendor
@$(MOD_OFF) golangci-lint run @$(MOD_OFF) "$(ROOT_DIR)/.bin/golangci-lint" run
.PHONY: clean .PHONY: clean
clean: clean:
@@ -70,5 +70,6 @@ prepare: install-lint
.PHONY: install-lint .PHONY: install-lint
install-lint: install-lint:
@curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh \ @mkdir -p ./bin || true && \
| $(MOD_OFF) bash -s -- -b $(GOPATH)/bin $(GOLANGCI_LINT_VERSION) curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh \
| $(MOD_OFF) bash -s -- -b "$(ROOT_DIR)/.bin" $(GOLANGCI_LINT_VERSION)
+8 -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,11 +194,14 @@ 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` | `32KB` | 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` | `32KB` | 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 |
| `MTG_NTP_SERVERS` | `--ntp-server` | default pool | A list of NTP servers to use. |
| `MTG_PREFER_DIRECT_IP` | `--prefer-ip` | `ipv6` | Which IP protocol to prefer if possible. Works mostly in direct mode. |
Usually you want to modify only read/write buffer sizes. If you feel 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 that proxy is slow, try to increase both sizes giving more priority to
+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 -4
View File
@@ -3,18 +3,28 @@ package antireplay
import ( import (
"sync" "sync"
"github.com/9seconds/mtg/config"
"github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/fastcache"
"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) {
+11 -12
View File
@@ -5,19 +5,18 @@ import (
"os" "os"
"time" "time"
"github.com/9seconds/mtg/antireplay"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/faketls"
"github.com/9seconds/mtg/hub"
"github.com/9seconds/mtg/ntp"
"github.com/9seconds/mtg/obfuscated2"
"github.com/9seconds/mtg/proxy"
"github.com/9seconds/mtg/stats"
"github.com/9seconds/mtg/telegram"
"github.com/9seconds/mtg/utils"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"mtg/antireplay"
"mtg/config"
"mtg/faketls"
"mtg/hub"
"mtg/ntp"
"mtg/obfuscated2"
"mtg/proxy"
"mtg/stats"
"mtg/telegram"
"mtg/utils"
) )
func Proxy() error { // nolint: funlen func Proxy() error { // nolint: funlen
@@ -50,7 +49,7 @@ func Proxy() error { // nolint: funlen
zap.S().Debugw("Configuration", "config", config.Printable()) zap.S().Debugw("Configuration", "config", config.Printable())
if len(config.C.AdTag) > 0 { if config.C.MiddleProxyMode() {
zap.S().Infow("Use middle proxy connection to Telegram") zap.S().Infow("Use middle proxy connection to Telegram")
diff, err := ntp.Fetch() diff, err := ntp.Fetch()
+77
View File
@@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math"
"net" "net"
"github.com/alecthomas/units" "github.com/alecthomas/units"
@@ -21,6 +22,8 @@ func (s SecretMode) String() string {
return "simple" return "simple"
case SecretModeSecured: case SecretModeSecured:
return "secured" return "secured"
case SecretModeTLS:
return "tls"
} }
return "tls" return "tls"
@@ -32,6 +35,13 @@ const (
SecretModeTLS SecretModeTLS
) )
type PreferIP uint8
const (
PreferIPv4 PreferIP = iota
PreferIPv6
)
const SimpleSecretLength = 16 const SimpleSecretLength = 16
type OptionType uint8 type OptionType uint8
@@ -40,6 +50,8 @@ const (
OptionTypeDebug OptionType = iota OptionTypeDebug OptionType = iota
OptionTypeVerbose OptionTypeVerbose
OptionTypePreferIP
OptionTypeBind OptionTypeBind
OptionTypePublicIPv4 OptionTypePublicIPv4
OptionTypePublicIPv6 OptionTypePublicIPv6
@@ -59,6 +71,8 @@ const (
OptionTypeMultiplexPerConnection OptionTypeMultiplexPerConnection
OptionTypeNTPServers
OptionTypeSecret OptionTypeSecret
OptionTypeAdtag OptionTypeAdtag
) )
@@ -86,11 +100,59 @@ type Config struct {
Debug bool `json:"debug"` Debug bool `json:"debug"`
Verbose bool `json:"verbose"` Verbose bool `json:"verbose"`
SecretMode SecretMode `json:"secret_mode"` SecretMode SecretMode `json:"secret_mode"`
PreferIP PreferIP `json:"prefer_ip"`
NTPServers []string `json:"ntp_servers"`
Secret []byte `json:"secret"` Secret []byte `json:"secret"`
AdTag []byte `json:"adtag"` AdTag []byte `json:"adtag"`
} }
func (c *Config) ClientReadBuffer() int {
return c.ReadBuffer
}
func (c *Config) ClientWriteBuffer() int {
return c.WriteBuffer
}
func (c *Config) MiddleProxyMode() bool {
return len(c.AdTag) > 0
}
func (c *Config) ProxyReadBuffer() int {
value := c.ReadBuffer
if c.MiddleProxyMode() {
value = c.adjustProxyValue(value)
}
return value
}
func (c *Config) ProxyWriteBuffer() int {
value := c.WriteBuffer
if c.MiddleProxyMode() {
value = c.adjustProxyValue(value)
}
return value
}
func (c *Config) adjustProxyValue(value int) int {
if c.MultiplexPerConnection == 0 {
return value
}
fvalue := float64(value)
newValue := fvalue * 2 * math.Log(float64(c.MultiplexPerConnection))
newValue = math.Ceil(newValue)
newValue = math.Max(fvalue, newValue)
return int(newValue)
}
type Opt struct { type Opt struct {
Option OptionType Option OptionType
Value interface{} Value interface{}
@@ -105,6 +167,16 @@ func Init(options ...Opt) error { // nolint: gocyclo, funlen
C.Debug = opt.Value.(bool) C.Debug = opt.Value.(bool)
case OptionTypeVerbose: case OptionTypeVerbose:
C.Verbose = opt.Value.(bool) C.Verbose = opt.Value.(bool)
case OptionTypePreferIP:
value := opt.Value.(string)
switch value {
case "ipv4":
C.PreferIP = PreferIPv4
case "ipv6":
C.PreferIP = PreferIPv6
default:
return fmt.Errorf("incorrect direct IP mode %s", value)
}
case OptionTypeBind: case OptionTypeBind:
C.Bind = opt.Value.(*net.TCPAddr) C.Bind = opt.Value.(*net.TCPAddr)
case OptionTypePublicIPv4: case OptionTypePublicIPv4:
@@ -145,6 +217,11 @@ func Init(options ...Opt) error { // nolint: gocyclo, funlen
C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes)) C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes))
case OptionTypeMultiplexPerConnection: case OptionTypeMultiplexPerConnection:
C.MultiplexPerConnection = int(opt.Value.(uint)) C.MultiplexPerConnection = int(opt.Value.(uint))
case OptionTypeNTPServers:
C.NTPServers = opt.Value.([]string)
if len(C.NTPServers) == 0 {
return errors.New("ntp server list is empty")
}
case OptionTypeSecret: case OptionTypeSecret:
C.Secret = opt.Value.([]byte) C.Secret = opt.Value.([]byte)
case OptionTypeAdtag: case OptionTypeAdtag:
+1 -1
View File
@@ -60,7 +60,7 @@ func fetchIP(ctx context.Context, network string) (net.IP, error) {
return nil, fmt.Errorf("cannot perform a request: %w", err) return nil, fmt.Errorf("cannot perform a request: %w", err)
} }
defer resp.Body.Close() // nolint: errcheck defer resp.Body.Close()
respDataBytes, err := ioutil.ReadAll(resp.Body) respDataBytes, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
+2
View File
@@ -8,6 +8,8 @@ func (c ConnectionProtocol) String() string {
return "any" return "any"
case ConnectionProtocolIPv4: case ConnectionProtocolIPv4:
return "ipv4" return "ipv4"
case ConnectionProtocolIPv6:
return "ipv6"
} }
return "ipv6" return "ipv6"
+3 -1
View File
@@ -21,7 +21,9 @@ func (t ConnectionType) Tag() []byte {
return ConnectionTagAbridged return ConnectionTagAbridged
case ConnectionTypeIntermediate: case ConnectionTypeIntermediate:
return ConnectionTagIntermediate return ConnectionTagIntermediate
default: case ConnectionTypeSecure, ConnectionTypeUnknown:
return ConnectionTagSecure return ConnectionTagSecure
} }
return ConnectionTagSecure
} }
+20 -32
View File
@@ -2,23 +2,23 @@ package faketls
import ( import (
"bufio" "bufio"
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"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 {
@@ -49,8 +49,8 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
} }
conn := stream.NewFakeTLS(socket) conn := stream.NewFakeTLS(socket)
conn, err := c.ClientProtocol.Handshake(conn)
conn, err := c.ClientProtocol.Handshake(conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -64,7 +64,10 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
return fmt.Errorf("cannot read initial record: %w", err) return fmt.Errorf("cannot read initial record: %w", err)
} }
clientHello, err := tlstypes.ParseClientHello(helloRecord.Data.Bytes()) buf := &bytes.Buffer{}
helloRecord.Data.WriteBytes(buf)
clientHello, err := tlstypes.ParseClientHello(buf.Bytes())
if err != nil { if err != nil {
return fmt.Errorf("cannot parse client hello: %w", err) return fmt.Errorf("cannot parse client hello: %w", err)
} }
@@ -86,6 +89,7 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
if antireplay.Cache.HasTLS(clientHello.Random[:]) { if antireplay.Cache.HasTLS(clientHello.Random[:]) {
stats.Stats.ReplayDetected() stats.Stats.ReplayDetected()
return errors.New("replay attack is detected") return errors.New("replay attack is detected")
} }
@@ -101,32 +105,16 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
} }
func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) { func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) {
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort)) stats.Stats.CloakedRequest()
hostConn, err := net.Dial("tcp", addr)
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort))
hostConn, err := net.Dial("tcp", addr)
if err != nil { if err != nil {
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 {
+73
View File
@@ -0,0 +1,73 @@
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 cloakPipe(one, another, wg)
go cloakPipe(another, one, wg)
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()
}
func cloakPipe(one io.Writer, another io.Reader, wg *sync.WaitGroup) {
defer wg.Done()
io.Copy(one, another) // nolint: errcheck
}
+14 -12
View File
@@ -1,20 +1,22 @@
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.3.0
github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/prometheus/client_golang v1.7.1
github.com/prometheus/client_golang v1.2.1 github.com/prometheus/common v0.13.0 // indirect
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/multierr v1.4.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.13.0 go.uber.org/zap v1.16.0
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/net v0.0.0-20191116160921-f9c825593386 // indirect golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6 golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3 // indirect golang.org/x/sys v0.0.0-20200918174421-af09f7315aff
golang.org/x/tools v0.0.0-20200319210407-521f4a0cd458 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
) )
+345 -36
View File
@@ -1,9 +1,14 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
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/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/VictoriaMetrics/fastcache v1.5.2 h1:Erd8iIuBAL9kke8JzM4+WxkKuFkHh3ktwLanJvDgR44= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VictoriaMetrics/fastcache v1.5.2/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
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=
@@ -16,98 +21,268 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2c
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
github.com/beevik/ntp v0.3.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 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
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=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= 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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 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.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= 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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 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/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.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/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
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.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
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=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
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 v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
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.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
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-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 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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
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.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.13.0 h1:vJlpe9wPgDRM1Z+7Wj3zUUjY1nr6/1jNKyl7llliccg=
github.com/prometheus/common v0.13.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
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.0-20190117184657-bf6a532e95b1/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.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.0.7/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
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=
@@ -116,63 +291,197 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
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= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
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.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
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.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-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=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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-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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6 h1:8mlr2HX+lfl0eaQcjiHfVeM2FHxWkuYQ5a2Wcy8mE1s= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8=
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/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/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200319210407-521f4a0cd458 h1:DgonIcqC7u+gVZX7lpuReBil5B/i8fvW/hAQdhT6/ao=
golang.org/x/tools v0.0.0-20200319210407-521f4a0cd458/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
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=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
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/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
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=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
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=
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
+14 -5
View File
@@ -4,15 +4,17 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"sync" "sync"
"time"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/mtproto"
"github.com/9seconds/mtg/mtproto/rpc"
"github.com/9seconds/mtg/protocol"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/mtproto"
"mtg/mtproto/rpc"
"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 +33,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 +44,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 {
@@ -81,6 +89,7 @@ func (c *connection) readLoop() {
response, err := rpc.ParseProxyResponse(packet) response, err := rpc.ParseProxyResponse(packet)
if err != nil { if err != nil {
c.logger.Debugw("Failed response", "error", err) c.logger.Debugw("Failed response", "error", err)
continue continue
} }
+6 -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
@@ -29,6 +25,7 @@ func (c *connectionList) Get(conn *ProxyConn) (*connection, error) {
if err = newConn.Attach(conn); err != nil { if err = newConn.Attach(conn); err != nil {
newConn.Close() newConn.Close()
return nil, fmt.Errorf("cannot attach to the newly created connection: %w", err) return nil, fmt.Errorf("cannot attach to the newly created connection: %w", err)
} }
@@ -41,6 +38,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 (
+43 -8
View File
@@ -3,16 +3,17 @@ package main
import ( import (
"math/rand" "math/rand"
"os" "os"
"runtime/debug"
"strings"
"time" "time"
"github.com/9seconds/mtg/cli"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/utils"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
"mtg/cli"
"mtg/config"
"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.")
@@ -41,6 +42,11 @@ var (
Short('v'). Short('v').
Envar("MTG_VERBOSE"). Envar("MTG_VERBOSE").
Bool() Bool()
runPreferIP = runCommand.Flag("prefer-ip",
"Prefer this IP protocol if possible. Valid options are 'ipv4' and 'ipv6'").
Envar("MTG_PREFER_DIRECT_IP").
Default("ipv6").
Enum("ipv4", "ipv6")
runBind = runCommand.Flag("bind", runBind = runCommand.Flag("bind",
"Host:Port to bind proxy to."). "Host:Port to bind proxy to.").
Short('b'). Short('b').
@@ -85,13 +91,13 @@ var (
"Write buffer size. You can think about it as a buffer from client to Telegram."). "Write buffer size. You can think about it as a buffer from client to Telegram.").
Short('w'). Short('w').
Envar("MTG_BUFFER_WRITE"). Envar("MTG_BUFFER_WRITE").
Default("64KB"). Default("32KB").
Bytes() Bytes()
runReadBufferSize = runCommand.Flag("read-buffer", runReadBufferSize = runCommand.Flag("read-buffer",
"Read buffer size. You can think about it as a buffer from Telegram to client."). "Read buffer size. You can think about it as a buffer from Telegram to client.").
Short('r'). Short('r').
Envar("MTG_BUFFER_READ"). Envar("MTG_BUFFER_READ").
Default("128KB"). Default("32KB").
Bytes() Bytes()
runTLSCloakPort = runCommand.Flag("cloak-port", runTLSCloakPort = runCommand.Flag("cloak-port",
"Port which should be used for host cloaking."). "Port which should be used for host cloaking.").
@@ -108,13 +114,18 @@ var (
Envar("MTG_MULTIPLEX_PERCONNECTION"). Envar("MTG_MULTIPLEX_PERCONNECTION").
Default("50"). Default("50").
Uint() Uint()
runNTPServers = runCommand.Flag("ntp-server",
"A list of NTP servers to use.").
Envar("MTG_NTP_SERVERS").
Default("0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org").
Strings()
runSecret = runCommand.Arg("secret", "Secret of this proxy.").Required().HexBytes() runSecret = runCommand.Arg("secret", "Secret of this proxy.").Required().HexBytes()
runAdtag = runCommand.Arg("adtag", "ADTag of the proxy.").HexBytes() runAdtag = runCommand.Arg("adtag", "ADTag of the proxy.").HexBytes()
) )
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 {
@@ -128,6 +139,7 @@ func main() {
err := config.Init( err := config.Init(
config.Opt{Option: config.OptionTypeDebug, Value: *runDebug}, config.Opt{Option: config.OptionTypeDebug, Value: *runDebug},
config.Opt{Option: config.OptionTypeVerbose, Value: *runVerbose}, config.Opt{Option: config.OptionTypeVerbose, Value: *runVerbose},
config.Opt{Option: config.OptionTypePreferIP, Value: *runPreferIP},
config.Opt{Option: config.OptionTypeBind, Value: *runBind}, config.Opt{Option: config.OptionTypeBind, Value: *runBind},
config.Opt{Option: config.OptionTypePublicIPv4, Value: *runPublicIPv4}, config.Opt{Option: config.OptionTypePublicIPv4, Value: *runPublicIPv4},
config.Opt{Option: config.OptionTypePublicIPv6, Value: *runPublicIPv6}, config.Opt{Option: config.OptionTypePublicIPv6, Value: *runPublicIPv6},
@@ -141,6 +153,7 @@ func main() {
config.Opt{Option: config.OptionTypeCloakPort, Value: *runTLSCloakPort}, config.Opt{Option: config.OptionTypeCloakPort, Value: *runTLSCloakPort},
config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *runAntiReplayMaxSize}, config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *runAntiReplayMaxSize},
config.Opt{Option: config.OptionTypeMultiplexPerConnection, Value: *runMultiplexPerConnection}, config.Opt{Option: config.OptionTypeMultiplexPerConnection, Value: *runMultiplexPerConnection},
config.Opt{Option: config.OptionTypeNTPServers, Value: *runNTPServers},
config.Opt{Option: config.OptionTypeSecret, Value: *runSecret}, config.Opt{Option: config.OptionTypeSecret, Value: *runSecret},
config.Opt{Option: config.OptionTypeAdtag, Value: *runAdtag}, config.Opt{Option: config.OptionTypeAdtag, Value: *runAdtag},
) )
@@ -153,3 +166,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()
}
+7 -7
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) {
@@ -19,8 +19,8 @@ func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.PacketReadWriteC
} }
rpcNonceConn := packet.NewMtprotoFrame(conn, rpc.SeqNoNonce) rpcNonceConn := packet.NewMtprotoFrame(conn, rpc.SeqNoNonce)
rpcNonceReq, err := doRPCNonceRequest(rpcNonceConn)
rpcNonceReq, err := doRPCNonceRequest(rpcNonceConn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot do nonce request: %w", err) return nil, fmt.Errorf("cannot do nonce request: %w", err)
} }
+1 -1
View File
@@ -7,7 +7,7 @@ const (
SeqNoHandshake = -1 SeqNoHandshake = -1
) )
// Different constants for RPC protocol // Different constants for RPC protocol.
var ( var (
TagCloseExt = []byte{0xa2, 0x34, 0xb6, 0x5e} TagCloseExt = []byte{0xa2, 0x34, 0xb6, 0x5e}
TagProxyAns = []byte{0x0d, 0xda, 0x03, 0x44} TagProxyAns = []byte{0x0d, 0xda, 0x03, 0x44}
+4 -4
View File
@@ -17,10 +17,10 @@ type HandshakeResponse struct {
func (r *HandshakeResponse) Bytes() []byte { func (r *HandshakeResponse) Bytes() []byte {
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
buf.Write(r.Type) // nolint: gosec buf.Write(r.Type)
buf.Write(r.Flags) // nolint: gosec buf.Write(r.Flags)
buf.Write(r.SenderPID) // nolint: gosec buf.Write(r.SenderPID)
buf.Write(r.PeerPID) // nolint: gosec buf.Write(r.PeerPID)
return buf.Bytes() return buf.Bytes()
} }
+6 -6
View File
@@ -15,13 +15,13 @@ type NonceResponse struct {
// Bytes returns serialized form of the nonce response. // Bytes returns serialized form of the nonce response.
func (r *NonceResponse) Bytes() []byte { func (r *NonceResponse) Bytes() []byte {
buf := &bytes.Buffer{} buf := bytes.Buffer{}
buf.Write(r.Type) // nolint: gosec buf.Write(r.Type)
buf.Write(r.KeySelector) // nolint: gosec buf.Write(r.KeySelector)
buf.Write(r.Crypto) // nolint: gosec buf.Write(r.Crypto)
buf.Write(r.CryptoTS) // nolint: gosec buf.Write(r.CryptoTS)
buf.Write(r.Nonce) // nolint: gosec buf.Write(r.Nonce)
return buf.Bytes() return buf.Bytes()
} }
+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
+3 -8
View File
@@ -5,22 +5,16 @@ import (
"math/rand" "math/rand"
"time" "time"
"github.com/9seconds/mtg/config"
"github.com/beevik/ntp" "github.com/beevik/ntp"
"go.uber.org/zap" "go.uber.org/zap"
) )
const autoUpdatePeriod = time.Minute const autoUpdatePeriod = time.Minute
var ntpEndpoints = [...]string{
"0.pool.ntp.org",
"1.pool.ntp.org",
"2.pool.ntp.org",
"3.pool.ntp.org",
}
// Fetch fetches the data on time drift. // Fetch fetches the data on time drift.
func Fetch() (time.Duration, error) { func Fetch() (time.Duration, error) {
url := ntpEndpoints[rand.Intn(len(ntpEndpoints))] url := config.C.NTPServers[rand.Intn(len(config.C.NTPServers))] // nolint: gosec
resp, err := ntp.Query(url) resp, err := ntp.Query(url)
if err != nil { if err != nil {
@@ -45,6 +39,7 @@ func AutoUpdate() {
diff, err := Fetch() diff, err := Fetch()
if err != nil { if err != nil {
logger.Debugw("Cannot fetch time from NTP", "error", err) logger.Debugw("Cannot fetch time from NTP", "error", err)
continue continue
} }
+8 -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
@@ -84,6 +84,7 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
replayKey := decryptedFrame.Unique() replayKey := decryptedFrame.Unique()
if antireplay.Cache.HasObfuscated2(replayKey) { if antireplay.Cache.HasObfuscated2(replayKey) {
stats.Stats.ReplayDetected() stats.Stats.ReplayDetected()
return nil, errors.New("replay attack is detected") return nil, errors.New("replay attack is detected")
} }
+1 -1
View File
@@ -15,7 +15,7 @@ const (
frameLen = 64 frameLen = 64
) )
// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd] // [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd].
type Frame struct { type Frame struct {
data [frameLen]byte data [frameLen]byte
} }
+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 -2
View File
@@ -3,9 +3,8 @@ package protocol
import ( import (
"context" "context"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
type TelegramRequest struct { type TelegramRequest struct {
+7 -7
View File
@@ -4,14 +4,13 @@ import (
"io" "io"
"sync" "sync"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/obfuscated2"
"github.com/9seconds/mtg/protocol"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/obfuscated2"
"mtg/protocol"
) )
const directPipeBufferSize = 1024 * 1024 const directPipeBufferSize = 1024
func directConnection(request *protocol.TelegramRequest) error { func directConnection(request *protocol.TelegramRequest) error {
telegramConnRaw, err := obfuscated2.TelegramProtocol(request) telegramConnRaw, err := obfuscated2.TelegramProtocol(request)
@@ -42,8 +41,9 @@ func directPipe(dst io.WriteCloser, src io.ReadCloser, wg *sync.WaitGroup, logge
wg.Done() wg.Done()
}() }()
buf := make([]byte, directPipeBufferSize) buf := [directPipeBufferSize]byte{}
if _, err := io.CopyBuffer(dst, src, buf); err != nil {
if _, err := io.CopyBuffer(dst, src, buf[:]); err != nil {
logger.Debugw("Cannot pump sockets", "error", err) logger.Debugw("Cannot pump sockets", "error", err)
} }
} }
+8 -6
View File
@@ -3,17 +3,17 @@ package proxy
import ( import (
"sync" "sync"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/protocol"
"github.com/9seconds/mtg/wrappers/packetack"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/protocol"
"mtg/wrappers/packetack"
) )
func middleConnection(request *protocol.TelegramRequest) { func middleConnection(request *protocol.TelegramRequest) {
telegramConn, err := packetack.NewProxy(request) telegramConn, err := packetack.NewProxy(request)
if err != nil { if err != nil {
request.Logger.Debugw("Cannot dial to Telegram", "error", err) request.Logger.Debugw("Cannot dial to Telegram", "error", err)
return return
} }
defer telegramConn.Close() defer telegramConn.Close()
@@ -27,7 +27,7 @@ func middleConnection(request *protocol.TelegramRequest) {
clientConn = packetack.NewClientIntermediate(request.ClientConn) clientConn = packetack.NewClientIntermediate(request.ClientConn)
case conntypes.ConnectionTypeSecure: case conntypes.ConnectionTypeSecure:
clientConn = packetack.NewClientIntermediateSecure(request.ClientConn) clientConn = packetack.NewClientIntermediateSecure(request.ClientConn)
default: case conntypes.ConnectionTypeUnknown:
panic("unknown connection type") panic("unknown connection type")
} }
@@ -53,15 +53,17 @@ func middlePipe(dst conntypes.PacketAckWriteCloser,
for { for {
acks := conntypes.ConnectionAcks{} acks := conntypes.ConnectionAcks{}
packet, err := src.Read(&acks)
packet, err := src.Read(&acks)
if err != nil { if err != nil {
logger.Debugw("Cannot read packet", "error", err) logger.Debugw("Cannot read packet", "error", err)
return return
} }
if err = dst.Write(packet, &acks); err != nil { if err = dst.Write(packet, &acks); err != nil {
logger.Debugw("Cannot send packet", "error", err) logger.Debugw("Cannot send packet", "error", err)
return return
} }
} }
+14 -12
View File
@@ -4,14 +4,13 @@ import (
"context" "context"
"net" "net"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/protocol"
"github.com/9seconds/mtg/stats"
"github.com/9seconds/mtg/utils"
"github.com/9seconds/mtg/wrappers/stream"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/config"
"mtg/conntypes"
"mtg/protocol"
"mtg/stats"
"mtg/utils"
"mtg/wrappers/stream"
) )
type Proxy struct { type Proxy struct {
@@ -30,8 +29,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 +40,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)
@@ -51,8 +50,9 @@ func (p *Proxy) accept(conn net.Conn) {
connID := conntypes.NewConnID() connID := conntypes.NewConnID()
logger := p.Logger.With("connection_id", connID) logger := p.Logger.With("connection_id", connID)
if err := utils.InitTCP(conn); err != nil { if err := utils.InitTCP(conn, config.C.ClientReadBuffer(), config.C.ClientWriteBuffer()); err != nil {
logger.Errorw("Cannot initialize client TCP connection", "error", err) logger.Errorw("Cannot initialize client TCP connection", "error", err)
return return
} }
@@ -66,10 +66,12 @@ func (p *Proxy) accept(conn net.Conn) {
defer clientConn.Close() defer clientConn.Close()
clientProtocol := p.ClientProtocolMaker() clientProtocol := p.ClientProtocolMaker()
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
} }
@@ -88,7 +90,7 @@ func (p *Proxy) accept(conn net.Conn) {
err = nil err = nil
if len(config.C.AdTag) > 0 { if config.C.MiddleProxyMode() {
middleConnection(req) middleConnection(req)
} else { } else {
err = directConnection(req) err = directConnection(req)
+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
+34 -9
View File
@@ -5,19 +5,20 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
"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"
"mtg/conntypes"
) )
type statsPrometheus struct { type statsPrometheus struct {
connections *prometheus.GaugeVec connections *prometheus.GaugeVec
telegramConnections *prometheus.GaugeVec telegramConnections *prometheus.GaugeVec
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) {
@@ -49,10 +50,14 @@ func (s *statsPrometheus) changeConnections(connectionType conntypes.ConnectionT
labels[0] = "abridged" labels[0] = "abridged"
case conntypes.ConnectionTypeSecure: case conntypes.ConnectionTypeSecure:
labels[0] = "secured" labels[0] = "secured"
case conntypes.ConnectionTypeIntermediate:
labels[0] = "intermediate"
case conntypes.ConnectionTypeUnknown:
panic("unknown connection type")
} }
if addr.IP.To4() == nil { if addr.IP.To4() == nil {
labels[1] = "ipv6" // nolint: goconst labels[1] = "ipv6"
} }
s.connections.WithLabelValues(labels[:]...).Add(increment) s.connections.WithLabelValues(labels[:]...).Add(increment)
@@ -87,6 +92,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 +129,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 +146,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)
+13 -4
View File
@@ -8,11 +8,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
statsd "github.com/smira/go-statsd" statsd "github.com/smira/go-statsd"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/config"
"mtg/conntypes"
) )
var ( var (
@@ -91,8 +90,10 @@ func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType,
tags = append(tags, tagConnectionTypeAbridged) tags = append(tags, tagConnectionTypeAbridged)
case conntypes.ConnectionTypeIntermediate: case conntypes.ConnectionTypeIntermediate:
tags = append(tags, tagConnectionTypeIntermediate) tags = append(tags, tagConnectionTypeIntermediate)
default: case conntypes.ConnectionTypeSecure:
tags = append(tags, tagConnectionTypeSecured) tags = append(tags, tagConnectionTypeSecured)
case conntypes.ConnectionTypeUnknown:
panic("Unknown connection type")
} }
if addr.IP.To4() == nil { if addr.IP.To4() == nil {
@@ -137,6 +138,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 (
+6 -2
View File
@@ -1,6 +1,7 @@
package api package api
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@@ -9,7 +10,7 @@ import (
) )
const ( const (
apiUserAgent = "mtg" apiUserAgent = "github.com/9seconds/mtg"
apiHTTPTimeout = 30 * time.Second apiHTTPTimeout = 30 * time.Second
) )
@@ -18,7 +19,10 @@ var httpClient = http.Client{
} }
func request(url string) (io.ReadCloser, error) { func request(url string) (io.ReadCloser, error) {
req, err := http.NewRequest("GET", url, nil) ctx, cancel := context.WithTimeout(context.Background(), apiHTTPTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
+44 -18
View File
@@ -1,21 +1,24 @@
package telegram package telegram
import ( import (
"fmt" "errors"
"math/rand" "math/rand"
"net" "net"
"mtg/conntypes" "github.com/9seconds/mtg/config"
"mtg/utils" "github.com/9seconds/mtg/conntypes"
"mtg/wrappers/stream" "github.com/9seconds/mtg/utils"
"github.com/9seconds/mtg/wrappers/stream"
"go.uber.org/zap"
) )
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,25 +29,48 @@ 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 := "" for _, addr := range b.getAddresses(dc, protocol) {
conn, err := b.dialer.Dial("tcp", addr)
if err != nil {
b.logger.Infow("Cannot dial to Telegram", "address", addr, "error", err)
switch protocol { continue
case conntypes.ConnectionProtocolIPv4: }
addr = b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC)
default: if err := utils.InitTCP(conn, config.C.ProxyReadBuffer(), config.C.ProxyWriteBuffer()); err != nil {
addr = b.chooseAddress(b.v6Addresses, dc, b.V6DefaultDC) b.logger.Infow("Cannot initialize TCP socket", "address", addr, "error", err)
continue
}
return stream.NewTelegramConn(dc, conn), nil
} }
conn, err := b.dialer.Dial("tcp", addr) return nil, errors.New("cannot dial to the chosen DC")
if err != nil { }
return nil, fmt.Errorf("dial has failed: %w", err)
func (b *baseTelegram) getAddresses(dc conntypes.DC, protocol conntypes.ConnectionProtocol) []string {
addresses := make([]string, 0, 2)
protos := []conntypes.ConnectionProtocol{
conntypes.ConnectionProtocolIPv6,
conntypes.ConnectionProtocolIPv4,
} }
if err := utils.InitTCP(conn); err != nil { if config.C.PreferIP == config.PreferIPv4 {
return nil, fmt.Errorf("cannot initialize tcp socket: %w", err) protos[0], protos[1] = protos[1], protos[0]
} }
return stream.NewTelegramConn(dc, conn), nil for _, proto := range protos {
switch {
case proto&protocol == 0:
case proto&conntypes.ConnectionProtocolIPv6 != 0:
addresses = append(addresses, b.chooseAddress(b.v6Addresses, dc, b.v6DefaultDC))
case proto&conntypes.ConnectionProtocolIPv4 != 0:
addresses = append(addresses, b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC))
}
}
return addresses
} }
func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string, func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
@@ -58,7 +84,7 @@ func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
case len(addrs) == 1: case len(addrs) == 1:
return addrs[0] return addrs[0]
case len(addrs) > 1: case len(addrs) > 1:
return addrs[rand.Intn(len(addrs))] return addrs[rand.Intn(len(addrs))] // nolint: gosec
} }
return "" return ""
+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 -4
View File
@@ -5,10 +5,9 @@ import (
"sync" "sync"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/telegram/api"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/telegram/api"
) )
const middleTelegramBackgroundUpdateEvery = time.Hour const middleTelegramBackgroundUpdateEvery = time.Hour
@@ -45,7 +44,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()
+3 -3
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 {
@@ -25,7 +25,7 @@ func (c ClientHello) Digest() []byte {
} }
mac := hmac.New(sha256.New, config.C.Secret) mac := hmac.New(sha256.New, config.C.Secret)
mac.Write(rec.Bytes()) // nolint: errcheck rec.WriteBytes(mac)
computedDigest := mac.Sum(nil) computedDigest := mac.Sum(nil)
for i := range computedDigest { for i := range computedDigest {
+20 -9
View File
@@ -1,5 +1,7 @@
package tlstypes package tlstypes
import "io"
type RecordType uint8 type RecordType uint8
const ( const (
@@ -18,9 +20,9 @@ const (
type CipherSuiteType uint8 type CipherSuiteType uint8
const ( const (
CipherSuiteType_TLS_AES_128_GCM_SHA256 CipherSuiteType = iota // nolint: stylecheck, golint CipherSuiteType_TLS_AES_128_GCM_SHA256 CipherSuiteType = iota // nolint: stylecheck,golint
CipherSuiteType_TLS_AES_256_GCM_SHA384 // nolint: stylecheck, golint CipherSuiteType_TLS_AES_256_GCM_SHA384 // nolint: stylecheck,golint
CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256 // nolint: stylecheck, golint CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256 // nolint: stylecheck,golint
) )
func (c CipherSuiteType) Bytes() []byte { func (c CipherSuiteType) Bytes() []byte {
@@ -29,6 +31,8 @@ func (c CipherSuiteType) Bytes() []byte {
return CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes return CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes
case CipherSuiteType_TLS_AES_256_GCM_SHA384: case CipherSuiteType_TLS_AES_256_GCM_SHA384:
return CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes return CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes
case CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256:
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes
} }
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes
@@ -44,6 +48,8 @@ func (v Version) Bytes() []byte {
return Version12Bytes return Version12Bytes
case Version11: case Version11:
return Version11Bytes return Version11Bytes
case Version10, VersionUnknown:
return Version10Bytes
} }
return Version10Bytes return Version10Bytes
@@ -63,17 +69,22 @@ var (
Version12Bytes = []byte{0x03, 0x03} Version12Bytes = []byte{0x03, 0x03}
Version13Bytes = []byte{0x03, 0x04} Version13Bytes = []byte{0x03, 0x04}
CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes = []byte{0x13, 0x01} // nolint: stylecheck, golint CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes = []byte{0x13, 0x01} // nolint: stylecheck,golint
CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes = []byte{0x13, 0x02} // nolint: stylecheck, golint CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes = []byte{0x13, 0x02} // nolint: stylecheck,golint
CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes = []byte{0x13, 0x03} // nolint; stylecheck, golint CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes = []byte{0x13, 0x03} // nolint: stylecheck,golint
) )
type Byter interface { type Byter interface {
Bytes() []byte WriteBytes(io.Writer)
Len() int
} }
type RawBytes []byte type RawBytes []byte
func (r RawBytes) Bytes() []byte { func (r RawBytes) WriteBytes(writer io.Writer) {
return []byte(r) writer.Write(r) // nolint: errcheck
}
func (r RawBytes) Len() int {
return len(r)
} }
+14 -8
View File
@@ -2,8 +2,9 @@ package tlstypes
import ( import (
"bytes" "bytes"
"io"
"mtg/utils" "github.com/9seconds/mtg/utils"
) )
type Handshake struct { type Handshake struct {
@@ -14,24 +15,29 @@ type Handshake struct {
Tail Byter Tail Byter
} }
func (h *Handshake) Bytes() []byte { func (h *Handshake) WriteBytes(writer io.Writer) {
buf := bytes.Buffer{}
packetBuf := bytes.Buffer{} packetBuf := bytes.Buffer{}
buf.WriteByte(byte(h.Type)) writer.Write([]byte{byte(h.Type)}) // nolint: errcheck
packetBuf.Write(h.Version.Bytes()) packetBuf.Write(h.Version.Bytes())
packetBuf.Write(h.Random[:]) packetBuf.Write(h.Random[:])
packetBuf.WriteByte(byte(len(h.SessionID))) packetBuf.WriteByte(byte(len(h.SessionID)))
packetBuf.Write(h.SessionID) packetBuf.Write(h.SessionID)
packetBuf.Write(h.Tail.Bytes()) h.Tail.WriteBytes(&packetBuf)
sizeUint24 := utils.ToUint24(uint32(packetBuf.Len())) sizeUint24 := utils.ToUint24(uint32(packetBuf.Len()))
sizeUint24Bytes := sizeUint24[:] sizeUint24Bytes := sizeUint24[:]
sizeUint24Bytes[0], sizeUint24Bytes[2] = sizeUint24Bytes[2], sizeUint24Bytes[0] sizeUint24Bytes[0], sizeUint24Bytes[2] = sizeUint24Bytes[2], sizeUint24Bytes[0]
buf.Write(sizeUint24Bytes) writer.Write(sizeUint24Bytes) // nolint: errcheck
packetBuf.WriteTo(&buf) // nolint: errcheck packetBuf.WriteTo(writer) // nolint: errcheck
}
return buf.Bytes() func (h *Handshake) Len() int {
buf := bytes.Buffer{}
h.WriteBytes(&buf)
return buf.Len()
} }
+8 -9
View File
@@ -15,16 +15,15 @@ type Record struct {
Data Byter Data Byter
} }
func (r Record) Bytes() []byte { func (r Record) WriteBytes(writer io.Writer) {
buf := bytes.Buffer{} writer.Write([]byte{byte(r.Type)}) // nolint: errcheck
data := r.Data.Bytes() writer.Write(r.Version.Bytes()) // nolint: errcheck
binary.Write(writer, binary.BigEndian, uint16(r.Data.Len())) // nolint: errcheck
r.Data.WriteBytes(writer)
}
buf.WriteByte(byte(r.Type)) func (r Record) Len() int {
buf.Write(r.Version.Bytes()) return 1 + 2 + 2 + r.Data.Len()
binary.Write(&buf, binary.BigEndian, uint16(len(data))) // nolint: errcheck
buf.Write(data)
return buf.Bytes()
} }
func ReadRecord(reader io.Reader) (Record, error) { func ReadRecord(reader io.Reader) (Record, error) {
+9 -7
View File
@@ -8,9 +8,8 @@ import (
"io" "io"
mrand "math/rand" mrand "math/rand"
"github.com/9seconds/mtg/config"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
"mtg/config"
) )
type ServerHello struct { type ServerHello struct {
@@ -20,30 +19,33 @@ type ServerHello struct {
} }
func (s ServerHello) WelcomePacket() []byte { func (s ServerHello) WelcomePacket() []byte {
buf := &bytes.Buffer{}
s.Random = [32]byte{} s.Random = [32]byte{}
rec := Record{ rec := Record{
Type: RecordTypeHandshake, Type: RecordTypeHandshake,
Version: Version12, Version: Version12,
Data: &s, Data: &s,
} }
buf := bytes.NewBuffer(rec.Bytes()) rec.WriteBytes(buf)
recChangeCipher := Record{ recChangeCipher := Record{
Type: RecordTypeChangeCipherSpec, Type: RecordTypeChangeCipherSpec,
Version: Version12, Version: Version12,
Data: RawBytes([]byte{0x01}), Data: RawBytes([]byte{0x01}),
} }
buf.Write(recChangeCipher.Bytes()) recChangeCipher.WriteBytes(buf)
hostCert := make([]byte, 1024+mrand.Intn(3092)) hostCert := make([]byte, 1024+mrand.Intn(3092)) // nolint: gosec
rand.Read(hostCert) // nolint: errcheck rand.Read(hostCert) // nolint: errcheck
recData := Record{ recData := Record{
Type: RecordTypeApplicationData, Type: RecordTypeApplicationData,
Version: Version12, Version: Version12,
Data: RawBytes(hostCert), Data: RawBytes(hostCert),
} }
buf.Write(recData.Bytes()) recData.WriteBytes(buf)
packet := buf.Bytes() packet := buf.Bytes()
mac := hmac.New(sha256.New, config.C.Secret) mac := hmac.New(sha256.New, config.C.Secret)
+7 -5
View File
@@ -3,24 +3,26 @@ package utils
import ( import (
"fmt" "fmt"
"net" "net"
"mtg/config"
) )
func InitTCP(conn net.Conn) error { func InitTCP(conn net.Conn, readBufferSize int, writeBufferSize int) error {
tcpConn := conn.(*net.TCPConn) tcpConn := conn.(*net.TCPConn)
if err := tcpConn.SetNoDelay(true); err != nil { if err := tcpConn.SetNoDelay(true); err != nil {
return fmt.Errorf("cannot set TCP_NO_DELAY: %w", err) return fmt.Errorf("cannot set TCP_NO_DELAY: %w", err)
} }
if err := tcpConn.SetReadBuffer(config.C.ReadBuffer); err != nil { if err := tcpConn.SetReadBuffer(readBufferSize); err != nil {
return fmt.Errorf("cannot set read buffer size: %w", err) return fmt.Errorf("cannot set read buffer size: %w", err)
} }
if err := tcpConn.SetWriteBuffer(config.C.WriteBuffer); err != nil { if err := tcpConn.SetWriteBuffer(writeBufferSize); err != nil {
return fmt.Errorf("cannot set write buffer size: %w", err) return fmt.Errorf("cannot set write buffer size: %w", err)
} }
if err := tcpConn.SetKeepAlive(true); err != nil {
return fmt.Errorf("cannot enable keep-alive: %w", err)
}
return nil return nil
} }
+2 -1
View File
@@ -6,6 +6,7 @@ import (
) )
func MakeStreamCipher(key, iv []byte) cipher.Stream { func MakeStreamCipher(key, iv []byte) cipher.Stream {
block, _ := aes.NewCipher(key) // nolint: gosec block, _ := aes.NewCipher(key)
return cipher.NewCTR(block, iv) return cipher.NewCTR(block, iv)
} }
+3 -5
View File
@@ -10,9 +10,8 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
const ( const (
@@ -43,6 +42,7 @@ type wrapperMtprotoFrame struct {
func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funlen func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funlen
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
sum := crc32.NewIEEE() sum := crc32.NewIEEE()
writer := io.MultiWriter(buf, sum) writer := io.MultiWriter(buf, sum)
@@ -71,7 +71,6 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funl
} }
buf.Reset() buf.Reset()
buf.Grow(int(messageLength) - 4 - 4)
if _, err := io.CopyN(writer, w.parent, int64(messageLength)-4-4); err != nil { if _, err := io.CopyN(writer, w.parent, int64(messageLength)-4-4); err != nil {
return nil, fmt.Errorf("cannot read the message frame: %w", err) return nil, fmt.Errorf("cannot read the message frame: %w", err)
@@ -85,7 +84,7 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funl
return nil, fmt.Errorf("unexpected sequence number %d (wait for %d)", seqNo, w.readSeqNo) return nil, fmt.Errorf("unexpected sequence number %d (wait for %d)", seqNo, w.readSeqNo)
} }
data, _ := ioutil.ReadAll(buf) // nolint: gosec data, _ := ioutil.ReadAll(buf)
buf.Reset() buf.Reset()
// write to buf, not to writer. This is because we are going to fetch // write to buf, not to writer. This is because we are going to fetch
// crc32 checksum. // crc32 checksum.
@@ -114,7 +113,6 @@ func (w *wrapperMtprotoFrame) Write(p conntypes.Packet) error {
paddingLength := (aes.BlockSize - messageLength%aes.BlockSize) % aes.BlockSize paddingLength := (aes.BlockSize - messageLength%aes.BlockSize) % aes.BlockSize
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
buf.Grow(messageLength + paddingLength)
binary.Write(buf, binary.LittleEndian, uint32(messageLength)) // nolint: errcheck binary.Write(buf, binary.LittleEndian, uint32(messageLength)) // nolint: errcheck
binary.Write(buf, binary.LittleEndian, w.writeSeqNo) // nolint: errcheck binary.Write(buf, binary.LittleEndian, w.writeSeqNo) // nolint: errcheck
+2 -3
View File
@@ -6,10 +6,9 @@ import (
"io" "io"
"net" "net"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/utils"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/utils"
) )
const ( const (
+1 -2
View File
@@ -7,9 +7,8 @@ import (
"io" "io"
"net" "net"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
const clientIntermediateQuickAckLength = 0x80000000 const clientIntermediateQuickAckLength = 0x80000000
@@ -6,9 +6,8 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
type wrapperClientIntermediateSecure struct { type wrapperClientIntermediateSecure struct {
@@ -35,11 +34,12 @@ func (w *wrapperClientIntermediateSecure) Write(packet conntypes.Packet, acks *c
return nil return nil
} }
buf := bytes.Buffer{} buf := &bytes.Buffer{}
paddingLength := rand.Intn(4) paddingLength := rand.Intn(4) // nolint: gosec
buf.Grow(4 + len(packet) + paddingLength) buf.Grow(4 + len(packet) + paddingLength)
binary.Write(&buf, binary.LittleEndian, uint32(len(packet)+paddingLength)) // nolint: errcheck binary.Write(buf, binary.LittleEndian, uint32(len(packet)+paddingLength)) // nolint: errcheck
buf.Write(packet) buf.Write(packet)
buf.Write(make([]byte, paddingLength)) buf.Write(make([]byte, paddingLength))
+9 -7
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 {
@@ -23,8 +23,8 @@ type wrapperProxy struct {
func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.ConnectionAcks) error { func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.ConnectionAcks) error {
buf := bytes.Buffer{} buf := bytes.Buffer{}
flags := w.flags flags := w.flags
if acks.Quick { if acks.Quick {
flags |= rpc.ProxyRequestFlagsQuickAck flags |= rpc.ProxyRequestFlagsQuickAck
} }
@@ -43,6 +43,7 @@ func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.Connection
buf.WriteByte(byte(len(config.C.AdTag))) buf.WriteByte(byte(len(config.C.AdTag)))
buf.Write(config.C.AdTag) buf.Write(config.C.AdTag)
buf.Write(make([]byte, (4-buf.Len()%4)%4)) buf.Write(make([]byte, (4-buf.Len()%4)%4))
buf.Grow(len(packet))
buf.Write(packet) buf.Write(packet)
return w.proxy.Write(buf.Bytes()) return w.proxy.Write(buf.Bytes())
@@ -63,6 +64,7 @@ func (w *wrapperProxy) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, e
func (w *wrapperProxy) Close() error { func (w *wrapperProxy) Close() error {
w.proxy.Close() w.proxy.Close()
return nil return nil
} }
@@ -76,7 +78,7 @@ func NewProxy(request *protocol.TelegramRequest) (conntypes.PacketAckReadWriteCl
flags |= rpc.ProxyRequestFlagsIntermediate flags |= rpc.ProxyRequestFlagsIntermediate
case conntypes.ConnectionTypeSecure: case conntypes.ConnectionTypeSecure:
flags |= rpc.ProxyRequestFlagsIntermediate | rpc.ProxyRequestFlagsPad flags |= rpc.ProxyRequestFlagsIntermediate | rpc.ProxyRequestFlagsPad
default: case conntypes.ConnectionTypeUnknown:
panic("unknown connection type") panic("unknown connection type")
} }
+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 -3
View File
@@ -7,10 +7,9 @@ import (
"net" "net"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/utils"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/utils"
) )
type wrapperBlockCipher struct { type wrapperBlockCipher struct {
+6 -4
View File
@@ -5,10 +5,9 @@ import (
"net" "net"
"time" "time"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/config"
"mtg/conntypes"
) )
type connPurpose uint8 type connPurpose uint8
@@ -29,6 +28,7 @@ type wrapperConn struct {
func (w *wrapperConn) WriteTimeout(p []byte, timeout time.Duration) (int, error) { func (w *wrapperConn) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
if err := w.parent.SetWriteDeadline(time.Now().Add(timeout)); err != nil { if err := w.parent.SetWriteDeadline(time.Now().Add(timeout)); err != nil {
w.Close() w.Close()
return 0, fmt.Errorf("cannot set write deadline to the socket: %w", err) return 0, fmt.Errorf("cannot set write deadline to the socket: %w", err)
} }
@@ -40,7 +40,7 @@ func (w *wrapperConn) Write(p []byte) (int, error) {
w.logger.Debugw("write to stream", "bytes", n, "error", err) w.logger.Debugw("write to stream", "bytes", n, "error", err)
if err != nil { if err != nil {
w.Close() // nolint: gosec w.Close()
} }
return n, err return n, err
@@ -49,6 +49,7 @@ func (w *wrapperConn) Write(p []byte) (int, error) {
func (w *wrapperConn) ReadTimeout(p []byte, timeout time.Duration) (int, error) { func (w *wrapperConn) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
if err := w.parent.SetReadDeadline(time.Now().Add(timeout)); err != nil { if err := w.parent.SetReadDeadline(time.Now().Add(timeout)); err != nil {
w.Close() w.Close()
return 0, fmt.Errorf("cannot set read deadline to the socket: %w", err) return 0, fmt.Errorf("cannot set read deadline to the socket: %w", err)
} }
@@ -68,6 +69,7 @@ func (w *wrapperConn) Read(p []byte) (int, error) {
func (w *wrapperConn) Close() error { func (w *wrapperConn) Close() error {
w.logger.Debugw("Close connection") w.logger.Debugw("Close connection")
return w.parent.Close() return w.parent.Close()
} }
+6 -2
View File
@@ -6,9 +6,8 @@ import (
"net" "net"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
type wrapperCtx struct { type wrapperCtx struct {
@@ -21,6 +20,7 @@ func (w *wrapperCtx) WriteTimeout(p []byte, timeout time.Duration) (int, error)
select { select {
case <-w.ctx.Done(): case <-w.ctx.Done():
w.Close() w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err()) return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default: default:
return w.parent.WriteTimeout(p, timeout) return w.parent.WriteTimeout(p, timeout)
@@ -31,6 +31,7 @@ func (w *wrapperCtx) Write(p []byte) (int, error) {
select { select {
case <-w.ctx.Done(): case <-w.ctx.Done():
w.Close() w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err()) return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default: default:
return w.parent.Write(p) return w.parent.Write(p)
@@ -41,6 +42,7 @@ func (w *wrapperCtx) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
select { select {
case <-w.ctx.Done(): case <-w.ctx.Done():
w.Close() w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err()) return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default: default:
return w.parent.ReadTimeout(p, timeout) return w.parent.ReadTimeout(p, timeout)
@@ -51,6 +53,7 @@ func (w *wrapperCtx) Read(p []byte) (int, error) {
select { select {
case <-w.ctx.Done(): case <-w.ctx.Done():
w.Close() w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err()) return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default: default:
return w.parent.Read(p) return w.parent.Read(p)
@@ -59,6 +62,7 @@ func (w *wrapperCtx) Read(p []byte) (int, error) {
func (w *wrapperCtx) Close() error { func (w *wrapperCtx) Close() error {
w.cancel() w.cancel()
return w.parent.Close() return w.parent.Close()
} }
+16 -6
View File
@@ -1,15 +1,15 @@
package stream package stream
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"net" "net"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/tlstypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/tlstypes"
) )
type wrapperFakeTLS struct { type wrapperFakeTLS struct {
@@ -32,20 +32,25 @@ func (w *wrapperFakeTLS) WriteTimeout(p []byte, timeout time.Duration) (int, err
if elapsed > timeout { if elapsed > timeout {
return w.parent.WriteTimeout(b, timeout-elapsed) return w.parent.WriteTimeout(b, timeout-elapsed)
} }
return 0, errors.New("timeout") return 0, errors.New("timeout")
}) })
} }
func (w *wrapperFakeTLS) write(p []byte, writeFunc func([]byte) (int, error)) (int, error) { func (w *wrapperFakeTLS) write(p []byte, writeFunc func([]byte) (int, error)) (int, error) {
sum := 0 sum := 0
buf := bytes.Buffer{}
for _, v := range tlstypes.MakeRecords(p) { for _, v := range tlstypes.MakeRecords(p) {
_, err := writeFunc(v.Bytes()) buf.Reset()
v.WriteBytes(&buf)
_, err := writeFunc(buf.Bytes())
if err != nil { if err != nil {
return sum, err return sum, err
} }
sum += len(v.Data.Bytes()) sum += v.Data.Len()
} }
return sum, nil return sum, nil
@@ -86,7 +91,12 @@ func NewFakeTLS(socket conntypes.StreamReadWriteCloser) conntypes.StreamReadWrit
switch rec.Type { switch rec.Type {
case tlstypes.RecordTypeChangeCipherSpec: case tlstypes.RecordTypeChangeCipherSpec:
case tlstypes.RecordTypeApplicationData: case tlstypes.RecordTypeApplicationData:
return rec.Data.Bytes(), nil buf := &bytes.Buffer{}
rec.Data.WriteBytes(buf)
return buf.Bytes(), nil
case tlstypes.RecordTypeHandshake:
return nil, errors.New("unsupported record type handshake")
default: default:
return nil, fmt.Errorf("unsupported record type %v", rec.Type) return nil, fmt.Errorf("unsupported record type %v", rec.Type)
} }
+20 -19
View File
@@ -4,14 +4,14 @@ import (
"bytes" "bytes"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/md5" // nolint: gosec "crypto/md5"
"crypto/sha1" // nolint: gosec "crypto/sha1"
"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
@@ -55,9 +55,10 @@ func mtprotoDeriveKeys(purpose mtprotoCipherPurpose,
client, remote *net.TCPAddr, client, remote *net.TCPAddr,
secret []byte) ([]byte, []byte) { secret []byte) ([]byte, []byte) {
message := bytes.Buffer{} message := bytes.Buffer{}
message.Write(resp.Nonce) // nolint: gosec
message.Write(req.Nonce) // nolint: gosec message.Write(resp.Nonce)
message.Write(req.CryptoTS) // nolint: gosec message.Write(req.Nonce)
message.Write(req.CryptoTS)
clientIPv4 := mtprotoEmptyIP[:] clientIPv4 := mtprotoEmptyIP[:]
serverIPv4 := mtprotoEmptyIP[:] serverIPv4 := mtprotoEmptyIP[:]
@@ -67,34 +68,34 @@ func mtprotoDeriveKeys(purpose mtprotoCipherPurpose,
serverIPv4 = utils.ReverseBytes(remote.IP.To4()) serverIPv4 = utils.ReverseBytes(remote.IP.To4())
} }
message.Write(serverIPv4) // nolint: gosec message.Write(serverIPv4)
var port [2]byte var port [2]byte
binary.LittleEndian.PutUint16(port[:], uint16(client.Port)) binary.LittleEndian.PutUint16(port[:], uint16(client.Port))
message.Write(port[:]) // nolint: gosec message.Write(port[:])
switch purpose { switch purpose {
case mtprotoCipherPurposeClient: case mtprotoCipherPurposeClient:
message.WriteString("CLIENT") // nolint: gosec message.WriteString("CLIENT")
case mtprotoCipherPurposeServer: case mtprotoCipherPurposeServer:
message.WriteString("SERVER") // nolint: gosec message.WriteString("SERVER")
default: default:
panic("Unexpected cipher purpose") panic("Unexpected cipher purpose")
} }
message.Write(clientIPv4) // nolint: gosec message.Write(clientIPv4)
binary.LittleEndian.PutUint16(port[:], uint16(remote.Port)) binary.LittleEndian.PutUint16(port[:], uint16(remote.Port))
message.Write(port[:]) // nolint: gosec message.Write(port[:])
message.Write(secret) // nolint: gosec message.Write(secret)
message.Write(resp.Nonce) // nolint: gosec message.Write(resp.Nonce)
if client.IP.To4() == nil { if client.IP.To4() == nil {
message.Write(client.IP.To16()) // nolint: gosec message.Write(client.IP.To16())
message.Write(remote.IP.To16()) // nolint: gosec message.Write(remote.IP.To16())
} }
message.Write(req.Nonce) // nolint: gosec message.Write(req.Nonce)
data := message.Bytes() data := message.Bytes()
md5sum := md5.Sum(data[1:]) // nolint: gas md5sum := md5.Sum(data[1:]) // nolint: gas
+14 -6
View File
@@ -1,14 +1,14 @@
package stream package stream
import ( import (
"bytes"
"crypto/cipher" "crypto/cipher"
"fmt" "fmt"
"net" "net"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
type wrapperObfuscated2 struct { type wrapperObfuscated2 struct {
@@ -40,16 +40,24 @@ func (w *wrapperObfuscated2) Read(p []byte) (int, error) {
} }
func (w *wrapperObfuscated2) WriteTimeout(p []byte, timeout time.Duration) (int, error) { func (w *wrapperObfuscated2) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
buf := make([]byte, len(p)) buffer := bytes.Buffer{}
copy(buf, p)
buffer.Write(p)
buf := buffer.Bytes()
w.encryptor.XORKeyStream(buf, buf) w.encryptor.XORKeyStream(buf, buf)
return w.parent.WriteTimeout(buf, timeout) return w.parent.WriteTimeout(buf, timeout)
} }
func (w *wrapperObfuscated2) Write(p []byte) (int, error) { func (w *wrapperObfuscated2) Write(p []byte) (int, error) {
buf := make([]byte, len(p)) buffer := bytes.Buffer{}
copy(buf, p)
buffer.Write(p)
buf := buffer.Bytes()
w.encryptor.XORKeyStream(buf, buf) w.encryptor.XORKeyStream(buf, buf)
return w.parent.Write(buf) return w.parent.Write(buf)
+2 -2
View File
@@ -7,9 +7,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
type ReadWriteCloseRewinder interface { type ReadWriteCloseRewinder interface {
@@ -88,6 +87,7 @@ func (w *wrapperRewind) RemoteAddr() *net.TCPAddr {
func (w *wrapperRewind) Close() error { func (w *wrapperRewind) Close() error {
w.buf.Reset() w.buf.Reset()
return w.parent.Close() return w.parent.Close()
} }
+2 -3
View File
@@ -5,10 +5,9 @@ import (
"sync" "sync"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/stats"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/stats"
) )
type wrapperTelegramStats struct { type wrapperTelegramStats struct {
+2 -3
View File
@@ -4,10 +4,9 @@ import (
"net" "net"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/stats"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
"mtg/stats"
) )
type wrapperTrafficStats struct { type wrapperTrafficStats struct {
+1 -2
View File
@@ -4,9 +4,8 @@ import (
"net" "net"
"time" "time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap" "go.uber.org/zap"
"mtg/conntypes"
) )
const ( const (