REPOSITORY / ScuroNeko/mtg

Compare commits

DIFF REPOSITORY

Compare commits

..
4 Commits
83 changed files with 674 additions and 1508 deletions
+1 -7
View File
@@ -1,9 +1,3 @@
version.go
vendor/
tags
.github/
.bin/
*.md
mtg
.golangci.toml
.gitignore
run.sh
-131
View File
@@ -1,131 +0,0 @@
---
name: CI
on:
push:
tags:
- v*
branches:
- master
- stable
- v1
release:
types:
- published
- released
pull_request:
types:
- opened
- edited
- reopened
- synchronize
- ready_for_review
jobs:
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
matrix:
go_version:
- ^1.19
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: recursive
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go_version }}
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Run tests
run: go test -coverprofile=./coverage.txt -covermode=atomic -v ./...
- name: Collect coverage
uses: codecov/codecov-action@v1
with:
file: ./coverage.txt
lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: recursive
- name: Run linter
uses: golangci/golangci-lint-action@v2
with:
version: v1.48.0
docker:
name: Docker
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: recursive
- name: Get Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v1
with:
images: nineseconds/mtg,ghcr.io/9seconds/mtg
tag-semver: "{{version}},{{major}},{{major}}.{{minor}}"
- name: Setup QEMU
uses: docker/setup-qemu-action@v1
- name: Setup BuildX
uses: docker/setup-buildx-action@v1
- name: Setup cache
uses: actions/cache@v2
with:
path: /tmp/buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GHCR.io
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GH_PAT }}
- name: Build and push
uses: docker/build-push-action@v2
with:
pull: true
context: .
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7,linux/arm/v6
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=local,src=/tmp/buildx-cache
cache-to: type=local,dest=/tmp/buildx-cache
-69
View File
@@ -1,69 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches:
- master
- stable
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '24 20 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
+2 -2
View File
@@ -7,5 +7,5 @@
*.out
mtg
vendor/
.bin/
dist/
version.go
ccbuilds/
+2 -11
View File
@@ -3,20 +3,11 @@ concurrency = 4
deadline = "2m"
tests = true
skip-dirs = ["vendor"]
skip-files = ["version.go"]
[output]
format = "colored-line-number"
[linters]
enable-all = true
disable = [
"containedctx",
"exhaustivestruct",
"exhaustruct",
"gas",
"gochecknoglobals",
"goerr113",
"ireturn",
"thelper",
"varnamelen",
]
disable = ["gochecknoglobals", "gomnd"]
-65
View File
@@ -1,65 +0,0 @@
---
project_name: mtg
before:
hooks:
- go mod tidy
- go generate ./...
builds:
- binary: '{{ .ProjectName }}'
goos:
- darwin
- freebsd
- linux
- netbsd
- openbsd
goarch:
- 386
- amd64
- arm
- arm64
goarm:
- 6
- 7
env:
- CGO_ENABLED=0
flags:
- -trimpath
- -mod=readonly
ldflags: -s -w -X main.version={{ .Version }}
ignore:
- goos: darwin
goarch: 386
- goos: freebsd
goarch: arm64
- goos: netbsd
goarch: arm64
- goos: openbsd
goarch: arm64
archives:
- name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
format: tar.gz
wrap_in_directory: true
format_overrides:
- goos: windows
format: zip
files:
- LICENSE
- README.md
- SECURITY.md
gomod:
proxy: true
snapshot:
name_template: '{{ .Version }}'
checksum:
name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'
source:
enabled: true
name_template: '{{ .ProjectName }}-sources'
+19
View File
@@ -0,0 +1,19 @@
---
language: go
sudo: false
dist: trusty
go:
- 1.13.x
- master
before_script: make prepare
script:
- make all
- make lint
matrix:
allow_failures:
- go: master
+13 -9
View File
@@ -1,7 +1,7 @@
###############################################################################
# BUILD STAGE
FROM golang:1.19-alpine AS build
FROM golang:1.13-alpine
RUN set -x \
&& apk --no-cache --update add \
@@ -9,13 +9,15 @@ RUN set -x \
ca-certificates \
curl \
git \
make
make \
upx
COPY . /app
WORKDIR /app
COPY . /go/src/github.com/9seconds/mtg/
RUN set -x \
&& make -j 4 static
&& cd /go/src/github.com/9seconds/mtg \
&& make -j 4 static \
&& upx --ultra-brute -qq ./mtg
###############################################################################
@@ -24,9 +26,11 @@ RUN set -x \
FROM scratch
ENTRYPOINT ["/mtg"]
ENV MTG_BIND=0.0.0.0:3128 \
MTG_STATS_BIND=0.0.0.0:3129
ENV MTG_IP=0.0.0.0 \
MTG_PORT=3128 \
MTG_STATS_IP=0.0.0.0 \
MTG_STATS_PORT=3129
EXPOSE 3128 3129
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=build /app/mtg /mtg
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=0 /go/src/github.com/9seconds/mtg/mtg /mtg
+42 -61
View File
@@ -2,41 +2,58 @@ ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
IMAGE_NAME := mtg
APP_NAME := $(IMAGE_NAME)
GOLANGCI_LINT_VERSION := v1.48.0
CC_BINARIES := $(shell bash -c "echo -n $(APP_NAME)-{linux,freebsd,openbsd}-{386,amd64} $(APP_NAME)-linux-{arm,arm64}")
GOLANGCI_LINT_VERSION := v1.23.3
VERSION_GO := $(shell go version)
VERSION_DATE := $(shell date -Ru)
VERSION_TAG := $(shell git describe --tags --always)
COMMON_BUILD_FLAGS := -trimpath -mod=readonly -ldflags="-s -w -X 'main.version=$(VERSION_TAG) ($(VERSION_GO)) [$(VERSION_DATE)]'"
COMMON_BUILD_FLAGS := -ldflags="-s -w -X 'main.version=$(VERSION_TAG) ($(VERSION_GO)) [$(VERSION_DATE)]'"
GOBIN := $(ROOT_DIR)/.bin
GOTOOL := env "GOBIN=$(GOBIN)" "PATH=$(ROOT_DIR)/.bin:$(PATH)"
MOD_ON := env GO111MODULE=on
MOD_OFF := env GO111MODULE=auto
# -----------------------------------------------------------------------------
.PHONY: all
all: build
$(APP_NAME):
@$(MOD_ON) go build $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
.PHONY: build
build:
@go build $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
static-$(APP_NAME):
@$(MOD_ON) env CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
$(APP_NAME): build
$(APP_NAME)-%: GOOS=$(shell echo -n "$@" | sed 's?$(APP_NAME)-??' | cut -f1 -d-)
$(APP_NAME)-%: GOARCH=$(shell echo -n "$@" | sed 's?$(APP_NAME)-??' | cut -f2 -d-)
$(APP_NAME)-%: ccbuilds
@$(MOD_ON) env "GOOS=$(GOOS)" "GOARCH=$(GOARCH)" \
go build \
$(COMMON_BUILD_FLAGS) \
-o "./ccbuilds/$(APP_NAME)-$(GOOS)-$(GOARCH)"
.PHONY: static
static:
@env CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
ccbuilds:
@rm -rf ./ccbuilds && mkdir -p ./ccbuilds
vendor: go.mod go.sum
@$(MOD_ON) go mod vendor
.PHONY: test
test:
@go test -v ./...
# -----------------------------------------------------------------------------
.PHONY: citest
citest:
@go test -coverprofile=coverage.txt -covermode=atomic -race -v ./...
.PHONY: all
all: $(APP_NAME)
.PHONY: static
static: static-$(APP_NAME)
.PHONY: crosscompile
crosscompile: $(CC_BINARIES)
.PHONY: crosscompile-dir
crosscompile-dir:
@rm -rf "$(CC_DIR)" && mkdir -p "$(CC_DIR)"
.PHONY: lint
lint: vendor
@$(MOD_OFF) golangci-lint run
.PHONY: clean
clean:
@@ -44,50 +61,14 @@ clean:
git reset --hard >/dev/null && \
git submodule foreach --recursive sh -c 'git clean -xfd && git reset --hard' >/dev/null
.PHONY: lint
lint:
@$(GOTOOL) golangci-lint run
.PHONY: docker
docker:
@docker build --pull -t "$(IMAGE_NAME)" "$(ROOT_DIR)"
.PHONY: doc
doc:
@$(GOTOOL) godoc -http 0.0.0.0:10000
.PHONY: prepare
prepare: install-lint
.PHONY: fmt
fmt:
@$(GOTOOL) gofumpt -w -extra "$(ROOT_DIR)"
.PHONY: release
release:
@$(GOTOOL) goreleaser release --snapshot --rm-dist && \
find "$(ROOT_DIR)/dist" -type d | grep -vP "dist$$" | xargs -r rm -rf && \
rm -f "$(ROOT_DIR)/dist/config.yaml"
.PHONY: install-tools
install-tools: install-tools-lint install-tools-godoc install-tools-gofumpt install-tools-goreleaser
.PHONY: install-tools-lint
install-tools-lint:
@mkdir -p "$(GOBIN)" || true && \
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh \
| bash -s -- -b "$(GOBIN)" "$(GOLANGCI_LINT_VERSION)"
.PHONY: install-tools-godoc
install-tools-godoc:
@mkdir -p "$(GOBIN)" || true && \
$(GOTOOL) go get -u golang.org/x/tools/cmd/godoc
.PHONY: install-tools-gofumpt
install-tools-gofumpt: .bin
@$(GOTOOL) go install mvdan.cc/gofumpt@latest
.PHONY: goreleaser
install-tools-goreleaser: .bin
@$(GOTOOL) go install github.com/goreleaser/goreleaser@latest
.PHONY: update-deps
update-deps:
@go get -u && go mod tidy -go=1.18
.PHONY: install-lint
install-lint:
@curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh \
| $(MOD_OFF) bash -s -- -b $(GOPATH)/bin $(GOLANGCI_LINT_VERSION)
+4 -6
View File
@@ -189,18 +189,16 @@ supported environment variables:
| `MTG_IPV6` | `-6`, `--public-ipv6` | [Autodetect](https://ifconfig.co) | IPv6 address:port of this proxy. This is required if you NAT your proxy or run it in a docker container. In that case, you absolutely need to specify public IPv6 address of the proxy, otherwise either URLs will be broken or proxy could not access Telegram middle proxies. |
| `MTG_STATS_BIND` | `-t`, `--stats-bind` | `127.0.0.1:3129` | Which hist:port should we bind the internal statistics HTTP server (Prometheus). |
| `MTG_STATS_NAMESPACE` | `--stats-namespace` | `mtg` | Which namespace should be used for prometheus metrics. |
| `MTG_STATSD_ADDR` | `--statsd-addr` | | host:port of statsd service. No defaults, by default we do not send anything there. |
| `MTG_STATSD_ADDR` | `--statsd-addr` | | IP:host addresses of statsd service. No defaults, by defaults we do not send anything there. |
| `MTG_STATSD_PORT` | `--statsd-port` | `8125` | Which port should we use to work with statsd. |
| `MTG_STATSD_PREFIX` | `--statsd-prefix` | `mtg` | Which bucket prefix we should use. For example, if you set `mtg`, then metric `traffic.ingress` would be send as `mtg.traffic.ingress`. |
| `MTG_STATSD_TAGS_FORMAT` | `--statsd-tags-format` | | Which tags format we should use. By default, we are using default vanilla statsd tags format but if you want to send directly to InfluxDB or Datadog, please specify it there. Possible options are `influxdb` and `datadog`. |
| `MTG_STATSD_TAGS` | `--statsd-tags` | | Which tags should we send to statsd with our metrics. Please specify them as `key=value` pairs. |
| `MTG_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` | `32KB` | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client. |
| `MTG_BUFFER_WRITE` | `-w`, `--write-buffer` | `64KB` | The size of TCP write buffer in bytes. Write buffer is the buffer for messages which are going from client to Telegram. |
| `MTG_BUFFER_READ` | `-r`, `--read-buffer` | `128KB` | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client. |
| `MTG_ANTIREPLAY_MAXSIZE` | `--anti-replay-max-size` | `128MB` | Max size of antireplay cache. |
| `MTG_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_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
that proxy is slow, try to increase both sizes giving more priority to
-24
View File
@@ -1,24 +0,0 @@
# Security Policy
## Supported Versions
We support 2 tracks: 2.x and 1.x
| Version | Supported |
| ------- | ------------------ |
| 2.x | :white_check_mark: |
| 1.x | :interrobang: |
| < 1.0 | :x: |
1.x has adtag support. We do not plan any active development there but we guarantee:
1. Regular dependency updates
2. Updates for Golang versions
3. Security vulnerability fixes
4. Merging small PRs
2.x is in active development and have a full support.
## Reporting a Vulnerability
If you have found a vulnerability, please report about it to nineseconds@yandex.ru, telegram @9seconds or here in issues
+2 -1
View File
@@ -3,8 +3,9 @@ package antireplay
import (
"sync"
"github.com/9seconds/mtg/config"
"github.com/VictoriaMetrics/fastcache"
"github.com/9seconds/mtg/config"
)
type CacheInterface interface {
-84
View File
@@ -1,84 +0,0 @@
package main
import (
"crypto/sha256"
"encoding/base64"
"encoding/binary"
"fmt"
"io"
"runtime/debug"
"sort"
"strconv"
"time"
)
var version = "dev" // has to be set by ldflags
const (
buildInfoModuleStart byte = iota
buildInfoModuleFinish
buildInfoModuleDelimeter
)
func getVersion() string {
buildInfo, ok := debug.ReadBuildInfo()
if !ok {
return version
}
date := time.Now()
commit := ""
goVersion := buildInfo.GoVersion
dirtySuffix := ""
for _, setting := range buildInfo.Settings {
switch setting.Key {
case "vcs.time":
date, _ = time.Parse(time.RFC3339, setting.Value)
case "vcs.revision":
commit = setting.Value
case "vcs.modified":
if dirty, _ := strconv.ParseBool(setting.Value); dirty {
dirtySuffix = " [dirty]"
}
}
}
hasher := sha256.New()
checksumModule := func(mod *debug.Module) {
hasher.Write([]byte{buildInfoModuleStart})
io.WriteString(hasher, mod.Path) //nolint: errcheck
hasher.Write([]byte{buildInfoModuleDelimeter})
io.WriteString(hasher, mod.Version) //nolint: errcheck
hasher.Write([]byte{buildInfoModuleDelimeter})
io.WriteString(hasher, mod.Sum) //nolint: errcheck
hasher.Write([]byte{buildInfoModuleFinish})
}
io.WriteString(hasher, buildInfo.Path) //nolint: errcheck
binary.Write(hasher, binary.LittleEndian, uint64(1+len(buildInfo.Deps))) //nolint: errcheck
sort.Slice(buildInfo.Deps, func(i, j int) bool {
return buildInfo.Deps[i].Path > buildInfo.Deps[j].Path
})
checksumModule(&buildInfo.Main)
for _, module := range buildInfo.Deps {
checksumModule(module)
}
return fmt.Sprintf("%s (%s: %s on %s%s, modules checksum %s)",
version,
goVersion,
date.Format(time.RFC3339),
commit,
dirtySuffix,
base64.StdEncoding.EncodeToString(hasher.Sum(nil)))
}
+6 -5
View File
@@ -5,6 +5,9 @@ import (
"os"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/9seconds/mtg/antireplay"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/faketls"
@@ -15,11 +18,9 @@ import (
"github.com/9seconds/mtg/stats"
"github.com/9seconds/mtg/telegram"
"github.com/9seconds/mtg/utils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func Proxy() error { //nolint: funlen,cyclop
func Proxy() error { // nolint: funlen
ctx := utils.GetSignalContext()
atom := zap.NewAtomicLevel()
@@ -41,7 +42,7 @@ func Proxy() error { //nolint: funlen,cyclop
))
zap.ReplaceGlobals(logger)
defer logger.Sync() //nolint: errcheck
defer logger.Sync() // nolint: errcheck
if err := config.InitPublicAddress(ctx); err != nil {
Fatal(err)
@@ -49,7 +50,7 @@ func Proxy() error { //nolint: funlen,cyclop
zap.S().Debugw("Configuration", "config", config.Printable())
if config.C.MiddleProxyMode() {
if len(config.C.AdTag) > 0 {
zap.S().Infow("Use middle proxy connection to Telegram")
diff, err := ntp.Fetch()
+2 -2
View File
@@ -9,7 +9,7 @@ import (
func Fatal(arg interface{}) {
if value, ok := arg.(error); ok {
arg = fmt.Errorf("fatal error: %+v", value) //nolint: errorlint
arg = fmt.Errorf("fatal error: %+v", value)
}
PrintStderr(arg)
@@ -21,7 +21,7 @@ func PrintStderr(args ...interface{}) {
}
func PrintStdout(args ...interface{}) {
fmt.Println(args...) //nolint: forbidigo
fmt.Println(args...)
}
func PrintJSONStderr(data interface{}) {
+32 -109
View File
@@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"net"
"github.com/alecthomas/units"
@@ -22,8 +21,6 @@ func (s SecretMode) String() string {
return "simple"
case SecretModeSecured:
return "secured"
case SecretModeTLS:
return "tls"
}
return "tls"
@@ -35,13 +32,6 @@ const (
SecretModeTLS
)
type PreferIP uint8
const (
PreferIPv4 PreferIP = iota
PreferIPv6
)
const SimpleSecretLength = 16
type OptionType uint8
@@ -50,8 +40,6 @@ const (
OptionTypeDebug OptionType = iota
OptionTypeVerbose
OptionTypePreferIP
OptionTypeBind
OptionTypePublicIPv4
OptionTypePublicIPv6
@@ -71,88 +59,38 @@ const (
OptionTypeMultiplexPerConnection
OptionTypeNTPServers
OptionTypeSecret
OptionTypeAdtag
)
type Config struct {
Bind *net.TCPAddr `json:"bind"`
PublicIPv4 *net.TCPAddr `json:"public_ipv4"` //nolint: tagliatelle
PublicIPv6 *net.TCPAddr `json:"public_ipv6"` //nolint: tagliatelle
StatsBind *net.TCPAddr `json:"stats_bind"` //nolint: tagliatelle
StatsdAddr *net.TCPAddr `json:"stats_addr"` //nolint: tagliatelle
StatsdTagsFormat *statsd.TagFormat `json:"statsd_tags_format"` //nolint: tagliatelle
PublicIPv4 *net.TCPAddr `json:"public_ipv4"`
PublicIPv6 *net.TCPAddr `json:"public_ipv6"`
StatsBind *net.TCPAddr `json:"stats_bind"`
StatsdAddr *net.TCPAddr `json:"stats_addr"`
StatsdTagsFormat *statsd.TagFormat `json:"statsd_tags_format"`
StatsNamespace string `json:"stats_namespace"` //nolint: tagliatelle
CloakHost string `json:"cloak_host"` //nolint: tagliatelle
StatsdTags map[string]string `json:"statsd_tags"` //nolint: tagliatelle
StatsNamespace string `json:"stats_namespace"`
CloakHost string `json:"cloak_host"`
StatsdTags map[string]string `json:"statsd_tags"`
WriteBuffer int `json:"write_buffer"` //nolint: tagliatelle
ReadBuffer int `json:"read_buffer"` //nolint: tagliatelle
CloakPort int `json:"cloak_port"` //nolint: tagliatelle
WriteBuffer int `json:"write_buffer"`
ReadBuffer int `json:"read_buffer"`
CloakPort int `json:"cloak_port"`
AntiReplayMaxSize int `json:"anti_replay_max_size"` //nolint: tagliatelle
AntiReplayMaxSize int `json:"anti_replay_max_size"`
MultiplexPerConnection int `json:"multiplex_per_connection"` //nolint: tagliatelle
MultiplexPerConnection int `json:"multiplex_per_connection"`
Debug bool `json:"debug"`
Verbose bool `json:"verbose"`
SecretMode SecretMode `json:"secret_mode"` //nolint: tagliatelle
PreferIP PreferIP `json:"prefer_ip"` //nolint: tagliatelle
NTPServers []string `json:"ntp_servers"` //nolint: tagliatelle
SecretMode SecretMode `json:"secret_mode"`
Secret []byte `json:"secret"`
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)) //nolint: gomnd
newValue = math.Ceil(newValue)
newValue = math.Max(fvalue, newValue)
return int(newValue)
}
type Opt struct {
Option OptionType
Value interface{}
@@ -160,43 +98,33 @@ type Opt struct {
var C = Config{}
func Init(options ...Opt) error { //nolint: gocyclo, funlen, cyclop
func Init(options ...Opt) error { // nolint: gocyclo, funlen
for _, opt := range options {
switch opt.Option {
case OptionTypeDebug:
C.Debug = opt.Value.(bool) //nolint: forcetypeassert
C.Debug = opt.Value.(bool)
case OptionTypeVerbose:
C.Verbose = opt.Value.(bool) //nolint: forcetypeassert
case OptionTypePreferIP:
value := opt.Value.(string) //nolint: forcetypeassert
switch value {
case "ipv4":
C.PreferIP = PreferIPv4
case "ipv6":
C.PreferIP = PreferIPv6
default:
return fmt.Errorf("incorrect direct IP mode %s", value)
}
C.Verbose = opt.Value.(bool)
case OptionTypeBind:
C.Bind = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
C.Bind = opt.Value.(*net.TCPAddr)
case OptionTypePublicIPv4:
C.PublicIPv4 = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
C.PublicIPv4 = opt.Value.(*net.TCPAddr)
if C.PublicIPv4 == nil {
C.PublicIPv4 = &net.TCPAddr{}
}
case OptionTypePublicIPv6:
C.PublicIPv6 = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
C.PublicIPv6 = opt.Value.(*net.TCPAddr)
if C.PublicIPv6 == nil {
C.PublicIPv6 = &net.TCPAddr{}
}
case OptionTypeStatsBind:
C.StatsBind = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
C.StatsBind = opt.Value.(*net.TCPAddr)
case OptionTypeStatsNamespace:
C.StatsNamespace = opt.Value.(string) //nolint: forcetypeassert
C.StatsNamespace = opt.Value.(string)
case OptionTypeStatsdAddress:
C.StatsdAddr = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
C.StatsdAddr = opt.Value.(*net.TCPAddr)
case OptionTypeStatsdTagsFormat:
value := opt.Value.(string) //nolint: forcetypeassert
value := opt.Value.(string)
switch value {
case "datadog":
C.StatsdTagsFormat = statsd.TagFormatDatadog
@@ -206,26 +134,21 @@ func Init(options ...Opt) error { //nolint: gocyclo, funlen, cyclop
return fmt.Errorf("incorrect statsd tag %s", value)
}
case OptionTypeStatsdTags:
C.StatsdTags = opt.Value.(map[string]string) //nolint: forcetypeassert
C.StatsdTags = opt.Value.(map[string]string)
case OptionTypeWriteBufferSize:
C.WriteBuffer = int(opt.Value.(units.Base2Bytes)) //nolint: forcetypeassert
C.WriteBuffer = int(opt.Value.(units.Base2Bytes))
case OptionTypeReadBufferSize:
C.ReadBuffer = int(opt.Value.(units.Base2Bytes)) //nolint: forcetypeassert
C.ReadBuffer = int(opt.Value.(units.Base2Bytes))
case OptionTypeCloakPort:
C.CloakPort = int(opt.Value.(uint16)) //nolint: forcetypeassert
C.CloakPort = int(opt.Value.(uint16))
case OptionTypeAntiReplayMaxSize:
C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes)) //nolint: forcetypeassert
C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes))
case OptionTypeMultiplexPerConnection:
C.MultiplexPerConnection = int(opt.Value.(uint)) //nolint: forcetypeassert
case OptionTypeNTPServers:
C.NTPServers = opt.Value.([]string) //nolint: forcetypeassert
if len(C.NTPServers) == 0 {
return errors.New("ntp server list is empty")
}
C.MultiplexPerConnection = int(opt.Value.(uint))
case OptionTypeSecret:
C.Secret = opt.Value.([]byte) //nolint: forcetypeassert
C.Secret = opt.Value.([]byte)
case OptionTypeAdtag:
C.AdTag = opt.Value.([]byte) //nolint: forcetypeassert
C.AdTag = opt.Value.([]byte)
default:
return fmt.Errorf("unknown tag %v", opt.Option)
}
+6 -5
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
@@ -40,12 +41,12 @@ func fetchIP(ctx context.Context, network string) (net.IP, error) {
Timeout: ifconfigTimeout,
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, network, addr) //nolint: wrapcheck
return dialer.DialContext(ctx, network, addr)
},
},
}
req, err := http.NewRequest(http.MethodGet, ifconfigAddress, nil)
req, err := http.NewRequest("GET", ifconfigAddress, nil)
if err != nil {
return nil, fmt.Errorf("cannot create a request: %w", err)
}
@@ -53,15 +54,15 @@ func fetchIP(ctx context.Context, network string) (net.IP, error) {
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
if resp != nil {
io.Copy(io.Discard, resp.Body) //nolint: errcheck
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
}
return nil, fmt.Errorf("cannot perform a request: %w", err)
}
defer resp.Body.Close()
defer resp.Body.Close() // nolint: errcheck
respDataBytes, err := io.ReadAll(resp.Body)
respDataBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("cannot read response body: %w", err)
}
+17 -26
View File
@@ -8,21 +8,20 @@ import (
)
type URLs struct {
TG string `json:"tg_url"` //nolint: tagliatelle
TMe string `json:"tme_url"` //nolint: tagliatelle
TGQRCode string `json:"tg_qrcode"` //nolint: tagliatelle
TMeQRCode string `json:"tme_qrcode"` //nolint: tagliatelle
TG string `json:"tg_url"`
TMe string `json:"tme_url"`
TGQRCode string `json:"tg_qrcode"`
TMeQRCode string `json:"tme_qrcode"`
}
type IPURLs struct {
IPv4 *URLs `json:"ipv4,omitempty"`
IPv6 *URLs `json:"ipv6,omitempty"`
BotSecret string `json:"secret_for_mtproxybot"` //nolint: tagliatelle
IPv4 URLs `json:"ipv4"`
IPv6 URLs `json:"ipv6"`
BotSecret string `json:"secret_for_mtproxybot"`
}
func GetURLs() IPURLs {
func GetURLs() (urls IPURLs) {
secret := ""
urls := IPURLs{}
switch C.SecretMode {
case SecretModeSimple:
@@ -33,33 +32,25 @@ func GetURLs() IPURLs {
secret = "ee" + hex.EncodeToString(C.Secret) + hex.EncodeToString([]byte(C.CloakHost))
}
if C.PublicIPv4.IP != nil {
urls.IPv4 = makeURLs(C.PublicIPv4, secret)
}
if C.PublicIPv6.IP != nil {
urls.IPv6 = makeURLs(C.PublicIPv6, secret)
}
urls.IPv4 = makeURLs(C.PublicIPv4, secret)
urls.IPv6 = makeURLs(C.PublicIPv6, secret)
urls.BotSecret = hex.EncodeToString(C.Secret)
return urls
}
func makeURLs(addr *net.TCPAddr, secret string) *URLs {
urls := &URLs{}
func makeURLs(addr *net.TCPAddr, secret string) (urls URLs) {
values := url.Values{}
values.Set("server", addr.IP.String())
values.Set("port", strconv.Itoa(addr.Port))
values.Set("secret", secret)
return &URLs{
TG: makeTGURL(values),
TMe: makeTMeURL(values),
TGQRCode: makeQRCodeURL(urls.TG),
TMeQRCode: makeQRCodeURL(urls.TMe),
}
urls.TG = makeTGURL(values)
urls.TMe = makeTMeURL(values)
urls.TGQRCode = makeQRCodeURL(urls.TG)
urls.TMeQRCode = makeQRCodeURL(urls.TG)
return
}
func makeTGURL(values url.Values) string {
-2
View File
@@ -8,8 +8,6 @@ func (c ConnectionProtocol) String() string {
return "any"
case ConnectionProtocolIPv4:
return "ipv4"
case ConnectionProtocolIPv6:
return "ipv6"
}
return "ipv6"
+1 -3
View File
@@ -21,9 +21,7 @@ func (t ConnectionType) Tag() []byte {
return ConnectionTagAbridged
case ConnectionTypeIntermediate:
return ConnectionTagIntermediate
case ConnectionTypeSecure, ConnectionTypeUnknown:
default:
return ConnectionTagSecure
}
return ConnectionTagSecure
}
+5 -10
View File
@@ -2,7 +2,6 @@ package faketls
import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"fmt"
@@ -49,13 +48,13 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
}
conn := stream.NewFakeTLS(socket)
conn, err := c.ClientProtocol.Handshake(conn)
if err != nil {
return nil, err //nolint: wrapcheck
return nil, err
}
return conn, err //nolint: wrapcheck
return conn, err
}
func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
@@ -64,10 +63,7 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
return fmt.Errorf("cannot read initial record: %w", err)
}
buf := &bytes.Buffer{}
helloRecord.Data.WriteBytes(buf)
clientHello, err := tlstypes.ParseClientHello(buf.Bytes())
clientHello, err := tlstypes.ParseClientHello(helloRecord.Data.Bytes())
if err != nil {
return fmt.Errorf("cannot parse client hello: %w", err)
}
@@ -89,7 +85,6 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
if antireplay.Cache.HasTLS(clientHello.Random[:]) {
stats.Stats.ReplayDetected()
return errors.New("replay attack is detected")
}
@@ -108,8 +103,8 @@ func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) {
stats.Stats.CloakedRequest()
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort))
hostConn, err := net.Dial("tcp", addr)
if err != nil {
return
}
+9 -11
View File
@@ -26,11 +26,17 @@ func cloak(one, another io.ReadWriteCloser) {
another = rwc.NewPing(ctx, another, channelPing)
wg := &sync.WaitGroup{}
wg.Add(2) //nolint: gomnd
wg.Add(2)
go cloakPipe(one, another, wg)
go func() {
defer wg.Done()
io.Copy(one, another) // nolint: errcheck
}()
go cloakPipe(another, one, wg)
go func() {
defer wg.Done()
io.Copy(another, one) // nolint: errcheck
}()
go func() {
wg.Wait()
@@ -53,11 +59,9 @@ func cloak(one, another io.ReadWriteCloser) {
return
case <-lastActivityTimer.C:
cancel()
return
case <-maxTimer.C:
cancel()
return
}
}
@@ -65,9 +69,3 @@ func cloak(one, another io.ReadWriteCloser) {
<-ctx.Done()
}
func cloakPipe(one io.Writer, another io.Reader, wg *sync.WaitGroup) {
defer wg.Done()
io.Copy(one, another) //nolint: errcheck
}
+15 -25
View File
@@ -1,31 +1,21 @@
module github.com/9seconds/mtg
go 1.18
go 1.13
require (
github.com/VictoriaMetrics/fastcache v1.10.0
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
github.com/beevik/ntp v0.3.0
github.com/golang/snappy v0.0.4 // indirect
github.com/prometheus/client_golang v1.13.0
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/smira/go-statsd v1.3.2
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.22.0
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
golang.org/x/net v0.0.0-20220809012201-f428fae20770 // indirect
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
google.golang.org/protobuf v1.28.1 // indirect
github.com/VictoriaMetrics/fastcache v1.5.7
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
github.com/beevik/ntp v0.2.0
github.com/golang/protobuf v1.3.3 // indirect
github.com/prometheus/client_golang v1.4.0
github.com/smira/go-statsd v1.3.1
go.uber.org/atomic v1.5.1 // indirect
go.uber.org/multierr v1.4.0 // indirect
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d
golang.org/x/lint v0.0.0-20200130185559-910be7a94367 // indirect
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)
require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
)
+73 -401
View File
@@ -1,159 +1,65 @@
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=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY=
github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
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/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-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
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/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
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/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
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.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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.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.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
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.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
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.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/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
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/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
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=
@@ -161,352 +67,118 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
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 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/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.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/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.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
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.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smira/go-statsd v1.3.2 h1:1EeuzxNZ/TD9apbTOFSM9nulqfcsQFmT4u1A2DREabI=
github.com/smira/go-statsd v1.3.2/go.mod h1:1srXJ9/pbnN04G8f4F1jUzsGOnwkPKXciyqpewGlkC4=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
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/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
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-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U=
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
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.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.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-20181114220301-adae6a3d119a/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-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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220809012201-f428fae20770 h1:dIi4qVdvjZEjiMDv7vhokAZNGnz3kepwuXqFKYDdDMs=
golang.org/x/net v0.0.0-20220809012201-f428fae20770/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
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/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
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-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/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-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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/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-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/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-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74 h1:KW20qMcLRWuIgjdCpHFJbVZA7zsDKtFXPNcm7/eI5ZA=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
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-20190418145605-e7d98fc518a7/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-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
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/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
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/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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/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.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/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/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+4 -4
View File
@@ -6,11 +6,12 @@ import (
"sync"
"time"
"go.uber.org/zap"
"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"
)
const connectionTTL = time.Hour
@@ -30,7 +31,7 @@ type connection struct {
channelConnDetach chan conntypes.ConnID
}
func (c *connection) run() { //nolint: cyclop
func (c *connection) run() {
defer c.Close()
ttl := time.NewTimer(connectionTTL)
@@ -89,7 +90,6 @@ func (c *connection) readLoop() {
response, err := rpc.ParseProxyResponse(packet)
if err != nil {
c.logger.Debugw("Failed response", "error", err)
continue
}
@@ -148,7 +148,7 @@ func newConnection(req *protocol.TelegramRequest) (*connection, error) {
return nil, fmt.Errorf("cannot create a new connection: %w", err)
}
id := rand.Int() //nolint: gosec
id := rand.Int() // nolint: gosec
rv := &connection{
conn: conn,
id: id,
-1
View File
@@ -25,7 +25,6 @@ func (c *connectionList) get(conn *ProxyConn) (*connection, error) {
if err = newConn.Attach(conn); err != nil {
newConn.Close()
return nil, fmt.Errorf("cannot attach to the newly created connection: %w", err)
}
+1 -1
View File
@@ -18,7 +18,7 @@ func (h *hub) Register(req *protocol.TelegramRequest) (*ProxyConn, error) {
}
func (h *hub) getMux(req *protocol.TelegramRequest) *mux {
key := 32767 + int32(req.ClientProtocol.DC()) + 100000*int32(req.ClientProtocol.ConnectionProtocol()) //nolint: gomnd
var key int32 = 32767 + int32(req.ClientProtocol.DC()) + 100000*int32(req.ClientProtocol.ConnectionProtocol())
h.mutex.RLock()
m, ok := h.muxes[key]
+35 -15
View File
@@ -3,13 +3,19 @@ package main
import (
"math/rand"
"os"
"runtime/debug"
"strings"
"time"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/9seconds/mtg/cli"
"github.com/9seconds/mtg/config"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/9seconds/mtg/utils"
)
var version = "dev" // has to be set by ldflags
var (
app = kingpin.New("mtg", "Simple MTPROTO proxy.")
@@ -37,11 +43,6 @@ var (
Short('v').
Envar("MTG_VERBOSE").
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",
"Host:Port to bind proxy to.").
Short('b').
@@ -86,13 +87,13 @@ var (
"Write buffer size. You can think about it as a buffer from client to Telegram.").
Short('w').
Envar("MTG_BUFFER_WRITE").
Default("32KB").
Default("64KB").
Bytes()
runReadBufferSize = runCommand.Flag("read-buffer",
"Read buffer size. You can think about it as a buffer from Telegram to client.").
Short('r').
Envar("MTG_BUFFER_READ").
Default("32KB").
Default("128KB").
Bytes()
runTLSCloakPort = runCommand.Flag("cloak-port",
"Port which should be used for host cloaking.").
@@ -109,11 +110,6 @@ var (
Envar("MTG_MULTIPLEX_PERCONNECTION").
Default("50").
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()
runAdtag = runCommand.Arg("adtag", "ADTag of the proxy.").HexBytes()
)
@@ -123,6 +119,10 @@ func main() {
app.Version(getVersion())
app.HelpFlag.Short('h')
if err := utils.SetLimits(); err != nil {
cli.Fatal(err)
}
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
case generateSecretCommand.FullCommand():
cli.Generate(*generateSecretType, *generateCloakHost)
@@ -130,7 +130,6 @@ func main() {
err := config.Init(
config.Opt{Option: config.OptionTypeDebug, Value: *runDebug},
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.OptionTypePublicIPv4, Value: *runPublicIPv4},
config.Opt{Option: config.OptionTypePublicIPv6, Value: *runPublicIPv6},
@@ -144,7 +143,6 @@ func main() {
config.Opt{Option: config.OptionTypeCloakPort, Value: *runTLSCloakPort},
config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *runAntiReplayMaxSize},
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.OptionTypeAdtag, Value: *runAdtag},
)
@@ -157,3 +155,25 @@ func main() {
}
}
}
func getVersion() string {
if version != "dev" {
return version
}
info, ok := debug.ReadBuildInfo()
if !ok {
return version
}
builder := strings.Builder{}
builder.WriteString(info.Main.Version)
if info.Main.Sum != "" {
builder.WriteString(" (checksum: ")
builder.WriteString(info.Main.Sum)
builder.WriteRune(')')
}
return builder.String()
}
+2 -2
View File
@@ -19,8 +19,8 @@ func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.PacketReadWriteC
}
rpcNonceConn := packet.NewMtprotoFrame(conn, rpc.SeqNoNonce)
rpcNonceReq, err := doRPCNonceRequest(rpcNonceConn)
if err != nil {
return nil, fmt.Errorf("cannot do nonce request: %w", err)
}
@@ -51,7 +51,7 @@ func doRPCNonceRequest(conn conntypes.BasePacketWriter) (*rpc.NonceRequest, erro
}
if err := conn.Write(rpcNonceReq.Bytes()); err != nil {
return nil, err //nolint: wrapcheck
return nil, err
}
return rpcNonceReq, nil
+1 -1
View File
@@ -7,7 +7,7 @@ const (
SeqNoHandshake = -1
)
// Different constants for RPC protocol.
// Different constants for RPC protocol
var (
TagCloseExt = []byte{0xa2, 0x34, 0xb6, 0x5e}
TagProxyAns = []byte{0x0d, 0xda, 0x03, 0x44}
+5 -5
View File
@@ -17,10 +17,10 @@ type HandshakeResponse struct {
func (r *HandshakeResponse) Bytes() []byte {
buf := &bytes.Buffer{}
buf.Write(r.Type)
buf.Write(r.Flags)
buf.Write(r.SenderPID)
buf.Write(r.PeerPID)
buf.Write(r.Type) // nolint: gosec
buf.Write(r.Flags) // nolint: gosec
buf.Write(r.SenderPID) // nolint: gosec
buf.Write(r.PeerPID) // nolint: gosec
return buf.Bytes()
}
@@ -41,7 +41,7 @@ func (r *HandshakeResponse) Valid() error {
// NewHandshakeResponse constructs new handshake response from the given
// data.
func NewHandshakeResponse(data []byte) (*HandshakeResponse, error) {
if len(data) != 32 { //nolint: gomnd
if len(data) != 32 {
return nil, fmt.Errorf("incorrect handshake response length %d", len(data))
}
+5 -5
View File
@@ -29,17 +29,17 @@ func (r *NonceRequest) Bytes() []byte {
// NewNonceRequest builds new none request based on proxy secret.
func NewNonceRequest(proxySecret []byte) (*NonceRequest, error) {
nonce := make([]byte, 16) //nolint: gomnd
keySelector := make([]byte, 4) //nolint: gomnd
cryptoTS := make([]byte, 4) //nolint: gomnd
nonce := make([]byte, 16)
keySelector := make([]byte, 4)
cryptoTS := make([]byte, 4)
if _, err := rand.Read(nonce); err != nil {
return nil, fmt.Errorf("cannot generate nonce: %w", err)
}
copy(keySelector, proxySecret)
// 256 ^ 4 - do not know how to name
timestamp := time.Now().Truncate(time.Second).Unix() % 4294967296 //nolint: gomnd
timestamp := time.Now().Truncate(time.Second).Unix() % 4294967296 // 256 ^ 4 - do not know how to name
binary.LittleEndian.PutUint32(cryptoTS, uint32(timestamp))
return &NonceRequest{
+7 -7
View File
@@ -15,13 +15,13 @@ type NonceResponse struct {
// Bytes returns serialized form of the nonce response.
func (r *NonceResponse) Bytes() []byte {
buf := bytes.Buffer{}
buf := &bytes.Buffer{}
buf.Write(r.Type)
buf.Write(r.KeySelector)
buf.Write(r.Crypto)
buf.Write(r.CryptoTS)
buf.Write(r.Nonce)
buf.Write(r.Type) // nolint: gosec
buf.Write(r.KeySelector) // nolint: gosec
buf.Write(r.Crypto) // nolint: gosec
buf.Write(r.CryptoTS) // nolint: gosec
buf.Write(r.Nonce) // nolint: gosec
return buf.Bytes()
}
@@ -44,7 +44,7 @@ func (r *NonceResponse) Valid(req *NonceRequest) error {
// NewNonceResponse build new nonce response based on the given data.
func NewNonceResponse(data []byte) (*NonceResponse, error) {
if len(data) != 32 { //nolint: gomnd
if len(data) != 32 {
return nil, fmt.Errorf("unexpected message length %d", len(data))
}
+2 -2
View File
@@ -21,14 +21,14 @@ const (
var ProxyRequestFlagsEncryptedPrefix [8]byte
func (r ProxyRequestFlags) Bytes() []byte {
converted := make([]byte, 4) //nolint: gomnd
converted := make([]byte, 4)
binary.LittleEndian.PutUint32(converted, uint32(r))
return converted
}
func (r ProxyRequestFlags) String() string {
flags := make([]string, 0, 7) //nolint: gomnd
flags := make([]string, 0, 7)
if r&ProxyRequestFlagsHasAdTag != 0 {
flags = append(flags, "HAS_AD_TAG")
+1 -1
View File
@@ -24,7 +24,7 @@ type ProxyResponse struct {
func ParseProxyResponse(packet conntypes.Packet) (*ProxyResponse, error) {
var response ProxyResponse
if len(packet) < 4 { //nolint: gomnd
if len(packet) < 4 {
return nil, fmt.Errorf("incorrect packet length: %d", len(packet))
}
+8 -3
View File
@@ -5,16 +5,22 @@ import (
"math/rand"
"time"
"github.com/9seconds/mtg/config"
"github.com/beevik/ntp"
"go.uber.org/zap"
)
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.
func Fetch() (time.Duration, error) {
url := config.C.NTPServers[rand.Intn(len(config.C.NTPServers))] //nolint: gosec
url := ntpEndpoints[rand.Intn(len(ntpEndpoints))]
resp, err := ntp.Query(url)
if err != nil {
@@ -39,7 +45,6 @@ func AutoUpdate() {
diff, err := Fetch()
if err != nil {
logger.Debugw("Cannot fetch time from NTP", "error", err)
continue
}
+9 -12
View File
@@ -45,14 +45,14 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
}
decHasher := sha256.New()
decHasher.Write(fm.Key())
decHasher.Write(config.C.Secret)
decHasher.Write(fm.Key()) // nolint: errcheck
decHasher.Write(config.C.Secret) // nolint: errcheck
decryptor := utils.MakeStreamCipher(decHasher.Sum(nil), fm.IV())
invertedFrame := fm.Invert()
encHasher := sha256.New()
encHasher.Write(invertedFrame.Key())
encHasher.Write(config.C.Secret)
encHasher.Write(invertedFrame.Key()) // nolint: errcheck
encHasher.Write(config.C.Secret) // nolint: errcheck
encryptor := utils.MakeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
decryptedFrame := Frame{}
@@ -84,7 +84,6 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
replayKey := decryptedFrame.Unique()
if antireplay.Cache.HasObfuscated2(replayKey) {
stats.Stats.ReplayDetected()
return nil, errors.New("replay attack is detected")
}
@@ -93,14 +92,12 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
return stream.NewObfuscated2(socket, encryptor, decryptor), nil
}
func (c *ClientProtocol) ReadFrame(socket conntypes.StreamReader) (Frame, error) {
fm := Frame{}
if _, err := io.ReadFull(handshakeReader{socket}, fm.Bytes()); err != nil {
return fm, fmt.Errorf("cannot extract obfuscated2 frame: %w", err)
func (c *ClientProtocol) ReadFrame(socket conntypes.StreamReader) (fm Frame, err error) {
if _, err = io.ReadFull(handshakeReader{socket}, fm.Bytes()); err != nil {
err = fmt.Errorf("cannot extract obfuscated2 frame: %w", err)
}
return fm, nil
return
}
type handshakeReader struct {
@@ -108,7 +105,7 @@ type handshakeReader struct {
}
func (h handshakeReader) Read(p []byte) (int, error) {
return h.parent.ReadTimeout(p, clientProtocolHandshakeTimeout) //nolint: wrapcheck
return h.parent.ReadTimeout(p, clientProtocolHandshakeTimeout)
}
func MakeClientProtocol() protocol.ClientProtocol {
+4 -4
View File
@@ -15,7 +15,7 @@ const (
frameLen = 64
)
// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd].
// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
type Frame struct {
data [frameLen]byte
}
@@ -44,11 +44,11 @@ func (f *Frame) Unique() []byte {
return f.data[frameOffsetFirst:frameOffsetDC]
}
func (f *Frame) Invert() Frame {
nf := *f
func (f *Frame) Invert() (nf Frame) {
nf = *f
for i := 0; i < frameLenKey+frameLenIV; i++ {
nf.data[frameOffsetFirst+i] = f.data[frameOffsetIV-1-i]
}
return nf
return
}
+7 -8
View File
@@ -39,8 +39,7 @@ func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.StreamReadWriteC
return stream.NewObfuscated2(conn, encryptor, decryptor), nil
}
func generateFrame(cp protocol.ClientProtocol) Frame {
fm := Frame{}
func generateFrame(cp protocol.ClientProtocol) (fm Frame) {
data := fm.Bytes()
for {
@@ -48,22 +47,22 @@ func generateFrame(cp protocol.ClientProtocol) Frame {
continue
}
if data[0] == 0xef { //nolint: gomnd
if data[0] == 0xef {
continue
}
val := (uint32(data[3]) << 24) | (uint32(data[2]) << 16) | (uint32(data[1]) << 8) | uint32(data[0]) //nolint: gomnd, lll
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee { //nolint: lll
val := (uint32(data[3]) << 24) | (uint32(data[2]) << 16) | (uint32(data[1]) << 8) | uint32(data[0])
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
continue
}
val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4]) //nolint: gomnd
if val == 0x00000000 { //nolint: gomnd
val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4])
if val == 0x00000000 {
continue
}
copy(fm.Magic(), cp.ConnectionType().Tag())
return fm
return
}
}
+2 -1
View File
@@ -3,8 +3,9 @@ package protocol
import (
"context"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
type TelegramRequest struct {
+13 -10
View File
@@ -4,27 +4,31 @@ import (
"io"
"sync"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/obfuscated2"
"github.com/9seconds/mtg/protocol"
"go.uber.org/zap"
)
const directPipeBufferSize = 1024
const directPipeBufferSize = 1024 * 1024
func directConnection(request *protocol.TelegramRequest) error {
telegramConnRaw, err := obfuscated2.TelegramProtocol(request)
if err != nil {
return err //nolint: wrapcheck
return err
}
defer telegramConnRaw.Close()
telegramConn := telegramConnRaw.(conntypes.StreamReadWriteCloser)
defer telegramConn.Close()
wg := &sync.WaitGroup{}
wg.Add(2) //nolint: gomnd
wg.Add(2)
go directPipe(telegramConnRaw, request.ClientConn, wg, request.Logger)
go directPipe(telegramConn, request.ClientConn, wg, request.Logger)
go directPipe(request.ClientConn, telegramConnRaw, wg, request.Logger)
go directPipe(request.ClientConn, telegramConn, wg, request.Logger)
wg.Wait()
@@ -38,9 +42,8 @@ func directPipe(dst io.WriteCloser, src io.ReadCloser, wg *sync.WaitGroup, logge
wg.Done()
}()
buf := [directPipeBufferSize]byte{}
if _, err := io.CopyBuffer(dst, src, buf[:]); err != nil {
buf := make([]byte, directPipeBufferSize)
if _, err := io.CopyBuffer(dst, src, buf); err != nil {
logger.Debugw("Cannot pump sockets", "error", err)
}
}
+6 -9
View File
@@ -3,17 +3,17 @@ package proxy
import (
"sync"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/protocol"
"github.com/9seconds/mtg/wrappers/packetack"
"go.uber.org/zap"
)
func middleConnection(request *protocol.TelegramRequest) {
telegramConn, err := packetack.NewProxy(request)
if err != nil {
request.Logger.Debugw("Cannot dial to Telegram", "error", err)
return
}
defer telegramConn.Close()
@@ -27,12 +27,12 @@ func middleConnection(request *protocol.TelegramRequest) {
clientConn = packetack.NewClientIntermediate(request.ClientConn)
case conntypes.ConnectionTypeSecure:
clientConn = packetack.NewClientIntermediateSecure(request.ClientConn)
case conntypes.ConnectionTypeUnknown:
default:
panic("unknown connection type")
}
wg := &sync.WaitGroup{}
wg.Add(2) //nolint: gomnd
wg.Add(2)
go middlePipe(telegramConn, clientConn, wg, request.Logger)
@@ -44,8 +44,7 @@ func middleConnection(request *protocol.TelegramRequest) {
func middlePipe(dst conntypes.PacketAckWriteCloser,
src conntypes.PacketAckReadCloser,
wg *sync.WaitGroup,
logger *zap.SugaredLogger,
) {
logger *zap.SugaredLogger) {
defer func() {
dst.Close()
src.Close()
@@ -54,17 +53,15 @@ func middlePipe(dst conntypes.PacketAckWriteCloser,
for {
acks := conntypes.ConnectionAcks{}
packet, err := src.Read(&acks)
if err != nil {
logger.Debugw("Cannot read packet", "error", err)
return
}
if err = dst.Write(packet, &acks); err != nil {
logger.Debugw("Cannot send packet", "error", err)
return
}
}
+5 -5
View File
@@ -4,13 +4,14 @@ import (
"context"
"net"
"go.uber.org/zap"
"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"
)
type Proxy struct {
@@ -50,9 +51,8 @@ func (p *Proxy) accept(conn net.Conn) {
connID := conntypes.NewConnID()
logger := p.Logger.With("connection_id", connID)
if err := utils.InitTCP(conn, config.C.ClientReadBuffer(), config.C.ClientWriteBuffer()); err != nil {
if err := utils.InitTCP(conn); err != nil {
logger.Errorw("Cannot initialize client TCP connection", "error", err)
return
}
@@ -66,8 +66,8 @@ func (p *Proxy) accept(conn net.Conn) {
defer clientConn.Close()
clientProtocol := p.ClientProtocolMaker()
clientConn, err := clientProtocol.Handshake(clientConn)
if err != nil {
stats.Stats.AuthenticationFailed()
logger.Warnw("Cannot perform client handshake", "error", err)
@@ -90,7 +90,7 @@ func (p *Proxy) accept(conn net.Conn) {
err = nil
if config.C.MiddleProxyMode() {
if len(config.C.AdTag) > 0 {
middleConnection(req)
} else {
err = directConnection(req)
+2 -2
View File
@@ -28,11 +28,11 @@ func Init(ctx context.Context) error {
Handler: mux,
}
go srv.Serve(listener) //nolint: errcheck
go srv.Serve(listener) // nolint: errcheck
go func() {
<-ctx.Done()
srv.Shutdown(context.Background()) //nolint: errcheck
srv.Shutdown(context.Background()) // nolint: errcheck
}()
Stats = multiStats(stats)
+5 -9
View File
@@ -5,10 +5,11 @@ import (
"net/http"
"strconv"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
)
type statsPrometheus struct {
@@ -39,8 +40,7 @@ func (s *statsPrometheus) ClientDisconnected(connectionType conntypes.Connection
func (s *statsPrometheus) changeConnections(connectionType conntypes.ConnectionType,
addr *net.TCPAddr,
increment float64,
) {
increment float64) {
labels := [...]string{
"intermediate",
"ipv4",
@@ -51,14 +51,10 @@ func (s *statsPrometheus) changeConnections(connectionType conntypes.ConnectionT
labels[0] = "abridged"
case conntypes.ConnectionTypeSecure:
labels[0] = "secured"
case conntypes.ConnectionTypeIntermediate:
labels[0] = "intermediate"
case conntypes.ConnectionTypeUnknown:
panic("unknown connection type")
}
if addr.IP.To4() == nil {
labels[1] = "ipv6"
labels[1] = "ipv6" // nolint: goconst
}
s.connections.WithLabelValues(labels[:]...).Add(increment)
+11 -13
View File
@@ -8,10 +8,11 @@ import (
"sync"
"time"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
statsd "github.com/smira/go-statsd"
"go.uber.org/zap"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
)
var (
@@ -83,17 +84,15 @@ func (s *statsStatsd) ClientDisconnected(connectionType conntypes.ConnectionType
}
func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, increment int64) {
tags := make([]*statsStatsdTag, 0, 2) //nolint: gomnd
tags := make([]*statsStatsdTag, 0, 2)
switch connectionType {
case conntypes.ConnectionTypeAbridged:
tags = append(tags, tagConnectionTypeAbridged)
case conntypes.ConnectionTypeIntermediate:
tags = append(tags, tagConnectionTypeIntermediate)
case conntypes.ConnectionTypeSecure:
default:
tags = append(tags, tagConnectionTypeSecured)
case conntypes.ConnectionTypeUnknown:
panic("Unknown connection type")
}
if addr.IP.To4() == nil {
@@ -168,18 +167,17 @@ func (s *statsStatsd) prepareVals(metric string, tags []*statsStatsdTag) (string
func (s *statsStatsd) initGauge(metric, key string, tags []statsd.Tag) {
s.seenMutex.RLock()
if _, ok := s.seen[key]; ok {
s.seenMutex.RUnlock()
_, ok := s.seen[key]
s.seenMutex.RUnlock()
if ok {
return
} else { //nolint: golint,revive
s.seenMutex.RUnlock()
}
s.seenMutex.Lock()
defer s.seenMutex.Unlock()
if _, ok := s.seen[key]; !ok {
if _, ok = s.seen[key]; !ok {
s.seen[key] = struct{}{}
s.client.Gauge(metric, 0, tags...)
}
@@ -194,8 +192,8 @@ func newStatsStatsd() Interface {
return &statsStatsd{
seen: make(map[string]struct{}),
client: statsd.NewClient(config.C.StatsdAddr.String(),
statsd.SendLoopCount(2), //nolint: gomnd
statsd.ReconnectInterval(10*time.Second), //nolint: gomnd
statsd.SendLoopCount(2),
statsd.ReconnectInterval(10*time.Second),
statsd.Logger(logger),
statsd.MetricPrefix(prefix),
statsd.TagStyle(config.C.StatsdTagsFormat),
+6 -6
View File
@@ -12,8 +12,8 @@ import (
)
const (
addressesURLV4 = "https://core.telegram.org/getProxyConfig" //nolint: gas
addressesURLV6 = "https://core.telegram.org/getProxyConfigV6" //nolint: gas
addressesURLV4 = "https://core.telegram.org/getProxyConfig" // nolint: gas
addressesURLV6 = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
)
var addressesProxyForSplitter = regexp.MustCompile(`\s+`)
@@ -74,12 +74,12 @@ func getAddresses(url string) (map[conntypes.DC][]string, conntypes.DC, error) {
}
func addressesParseProxyFor(text string) (string, conntypes.DC, error) {
chunks := addressesProxyForSplitter.Split(text, 3) //nolint: gomnd
chunks := addressesProxyForSplitter.Split(text, 3)
if len(chunks) != 3 || chunks[0] != "proxy_for" {
return "", 0, fmt.Errorf("incorrect config %s", text)
}
dc, err := strconv.ParseInt(chunks[1], 10, 16) //nolint: gomnd
dc, err := strconv.ParseInt(chunks[1], 10, 16)
if err != nil {
return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
}
@@ -93,14 +93,14 @@ func addressesParseProxyFor(text string) (string, conntypes.DC, error) {
}
func addressesParseDefault(text string) (conntypes.DC, error) {
chunks := addressesProxyForSplitter.Split(text, 2) //nolint: gomnd
chunks := addressesProxyForSplitter.Split(text, 2)
if len(chunks) != 2 || chunks[0] != "default" {
return 0, fmt.Errorf("incorrect config '%s'", text)
}
dcString := strings.TrimRight(chunks[1], ";")
dc, err := strconv.ParseInt(dcString, 10, 16) //nolint: gomnd
dc, err := strconv.ParseInt(dcString, 10, 16)
if err != nil {
return 0, fmt.Errorf("incorrect config '%s': %w", text, err)
}
+4 -7
View File
@@ -1,9 +1,9 @@
package api
import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
)
@@ -18,10 +18,7 @@ var httpClient = http.Client{
}
func request(url string) (io.ReadCloser, error) {
ctx, cancel := context.WithTimeout(context.Background(), apiHTTPTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err)
}
@@ -32,12 +29,12 @@ func request(url string) (io.ReadCloser, error) {
resp, err := httpClient.Do(req)
if err != nil {
if resp != nil {
io.Copy(io.Discard, resp.Body) //nolint: errcheck
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
resp.Body.Close()
}
return nil, fmt.Errorf("cannot perform a request: %w", err)
}
return resp.Body, err //nolint: wrapcheck
return resp.Body, err
}
+3 -3
View File
@@ -2,10 +2,10 @@ package api
import (
"fmt"
"io"
"io/ioutil"
)
const secretURL = "https://core.telegram.org/getProxySecret" //nolint: gas
const secretURL = "https://core.telegram.org/getProxySecret" // nolint: gas
func Secret() ([]byte, error) {
resp, err := request(secretURL)
@@ -15,7 +15,7 @@ func Secret() ([]byte, error) {
defer resp.Close()
secret, err := io.ReadAll(resp)
secret, err := ioutil.ReadAll(resp)
if err != nil {
return nil, fmt.Errorf("cannot read response: %w", err)
}
+17 -35
View File
@@ -5,11 +5,11 @@ import (
"math/rand"
"net"
"github.com/9seconds/mtg/config"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/utils"
"github.com/9seconds/mtg/wrappers/stream"
"go.uber.org/zap"
)
type baseTelegram struct {
@@ -28,19 +28,26 @@ func (b *baseTelegram) Secret() []byte {
}
func (b *baseTelegram) dial(dc conntypes.DC,
protocol conntypes.ConnectionProtocol,
) (conntypes.StreamReadWriteCloser, error) {
for _, addr := range b.getAddresses(dc, protocol) {
protocol conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) {
addresses := make([]string, 0, 2)
if protocol&conntypes.ConnectionProtocolIPv6 != 0 {
addresses = append(addresses, b.chooseAddress(b.v6Addresses, dc, b.v6DefaultDC))
}
if protocol&conntypes.ConnectionProtocolIPv4 != 0 {
addresses = append(addresses, b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC))
}
for _, addr := range addresses {
conn, err := b.dialer.Dial("tcp", addr)
if err != nil {
b.logger.Infow("Cannot dial to Telegram", "address", addr, "error", err)
continue
}
if err := utils.InitTCP(conn, config.C.ProxyReadBuffer(), config.C.ProxyWriteBuffer()); err != nil {
if err := utils.InitTCP(conn); err != nil {
b.logger.Infow("Cannot initialize TCP socket", "address", addr, "error", err)
continue
}
@@ -50,33 +57,8 @@ func (b *baseTelegram) dial(dc conntypes.DC,
return nil, errors.New("cannot dial to the chosen DC")
}
func (b *baseTelegram) getAddresses(dc conntypes.DC, protocol conntypes.ConnectionProtocol) []string {
addresses := make([]string, 0, 2) //nolint: gomnd
protos := []conntypes.ConnectionProtocol{
conntypes.ConnectionProtocolIPv6,
conntypes.ConnectionProtocolIPv4,
}
if config.C.PreferIP == config.PreferIPv4 {
protos[0], protos[1] = protos[1], protos[0]
}
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,
dc, defaultDC conntypes.DC,
) string {
dc, defaultDC conntypes.DC) string {
addrs, ok := addresses[dc]
if !ok {
addrs = addresses[defaultDC]
@@ -86,7 +68,7 @@ func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
case len(addrs) == 1:
return addrs[0]
case len(addrs) > 1:
return addrs[rand.Intn(len(addrs))] //nolint: gosec
return addrs[rand.Intn(len(addrs))]
}
return ""
+1 -2
View File
@@ -29,8 +29,7 @@ type directTelegram struct {
}
func (d *directTelegram) Dial(dc conntypes.DC,
protocol conntypes.ConnectionProtocol,
) (conntypes.StreamReadWriteCloser, error) {
protocol conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) {
switch {
case dc < 0:
dc = -dc
+3 -3
View File
@@ -5,9 +5,10 @@ import (
"sync"
"time"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/telegram/api"
"go.uber.org/zap"
)
const middleTelegramBackgroundUpdateEvery = time.Hour
@@ -63,8 +64,7 @@ func (m *middleTelegram) backgroundUpdate() {
}
func (m *middleTelegram) Dial(dc conntypes.DC,
protocol conntypes.ConnectionProtocol,
) (conntypes.StreamReadWriteCloser, error) {
protocol conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) {
if dc == 0 {
dc = conntypes.DCDefaultIdx
}
+1 -1
View File
@@ -25,7 +25,7 @@ func (c ClientHello) Digest() []byte {
}
mac := hmac.New(sha256.New, config.C.Secret)
rec.WriteBytes(mac)
mac.Write(rec.Bytes()) // nolint: errcheck
computedDigest := mac.Sum(nil)
for i := range computedDigest {
+14 -25
View File
@@ -1,7 +1,5 @@
package tlstypes
import "io"
type RecordType uint8
const (
@@ -20,22 +18,20 @@ const (
type CipherSuiteType uint8
const (
CipherSuiteType_TLS_AES_128_GCM_SHA256 CipherSuiteType = iota //nolint: stylecheck,golint,revive,nosnakecase
CipherSuiteType_TLS_AES_256_GCM_SHA384 //nolint: stylecheck,golint,revive,nosnakecase
CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256 //nolint: stylecheck,golint,revive,nosnakecase
CipherSuiteType_TLS_AES_128_GCM_SHA256 CipherSuiteType = iota // nolint: stylecheck, golint
CipherSuiteType_TLS_AES_256_GCM_SHA384 // nolint: stylecheck, golint
CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256 // nolint: stylecheck, golint
)
func (c CipherSuiteType) Bytes() []byte {
switch c {
case CipherSuiteType_TLS_AES_128_GCM_SHA256: //nolint: nosnakecase
return CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes //nolint: nosnakecase
case CipherSuiteType_TLS_AES_256_GCM_SHA384: //nolint: nosnakecase
return CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes //nolint: nosnakecase
case CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256: //nolint: nosnakecase
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes //nolint: nosnakecase
case CipherSuiteType_TLS_AES_128_GCM_SHA256:
return CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes
case CipherSuiteType_TLS_AES_256_GCM_SHA384:
return CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes
}
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes //nolint: nosnakecase
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes
}
type Version uint8
@@ -48,8 +44,6 @@ func (v Version) Bytes() []byte {
return Version12Bytes
case Version11:
return Version11Bytes
case Version10, VersionUnknown:
return Version10Bytes
}
return Version10Bytes
@@ -69,22 +63,17 @@ var (
Version12Bytes = []byte{0x03, 0x03}
Version13Bytes = []byte{0x03, 0x04}
CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes = []byte{0x13, 0x01} //nolint: stylecheck,golint,revive,nosnakecase
CipherSuiteType_TLS_AES_256_GCM_SHA384_Bytes = []byte{0x13, 0x02} //nolint: stylecheck,golint,revive,nosnakecase
CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes = []byte{0x13, 0x03} //nolint: stylecheck,golint,revive,nosnakecase
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_CHACHA20_POLY1305_SHA256_Bytes = []byte{0x13, 0x03} // nolint; stylecheck, golint
)
type Byter interface {
WriteBytes(io.Writer)
Len() int
Bytes() []byte
}
type RawBytes []byte
func (r RawBytes) WriteBytes(writer io.Writer) {
writer.Write(r) //nolint: errcheck
}
func (r RawBytes) Len() int {
return len(r)
func (r RawBytes) Bytes() []byte {
return []byte(r)
}
+7 -13
View File
@@ -2,7 +2,6 @@ package tlstypes
import (
"bytes"
"io"
"github.com/9seconds/mtg/utils"
)
@@ -15,29 +14,24 @@ type Handshake struct {
Tail Byter
}
func (h *Handshake) WriteBytes(writer io.Writer) {
func (h *Handshake) Bytes() []byte {
buf := bytes.Buffer{}
packetBuf := bytes.Buffer{}
writer.Write([]byte{byte(h.Type)}) //nolint: errcheck
buf.WriteByte(byte(h.Type))
packetBuf.Write(h.Version.Bytes())
packetBuf.Write(h.Random[:])
packetBuf.WriteByte(byte(len(h.SessionID)))
packetBuf.Write(h.SessionID)
h.Tail.WriteBytes(&packetBuf)
packetBuf.Write(h.Tail.Bytes())
sizeUint24 := utils.ToUint24(uint32(packetBuf.Len()))
sizeUint24Bytes := sizeUint24[:]
sizeUint24Bytes[0], sizeUint24Bytes[2] = sizeUint24Bytes[2], sizeUint24Bytes[0]
writer.Write(sizeUint24Bytes) //nolint: errcheck
packetBuf.WriteTo(writer) //nolint: errcheck
}
buf.Write(sizeUint24Bytes)
packetBuf.WriteTo(&buf) // nolint: errcheck
func (h *Handshake) Len() int {
buf := bytes.Buffer{}
h.WriteBytes(&buf)
return buf.Len()
return buf.Bytes()
}
+11 -12
View File
@@ -15,15 +15,16 @@ type Record struct {
Data Byter
}
func (r Record) WriteBytes(writer io.Writer) {
writer.Write([]byte{byte(r.Type)}) //nolint: errcheck
writer.Write(r.Version.Bytes()) //nolint: errcheck
binary.Write(writer, binary.BigEndian, uint16(r.Data.Len())) //nolint: errcheck
r.Data.WriteBytes(writer)
}
func (r Record) Bytes() []byte {
buf := bytes.Buffer{}
data := r.Data.Bytes()
func (r Record) Len() int {
return 1 + 2 + 2 + r.Data.Len()
buf.WriteByte(byte(r.Type))
buf.Write(r.Version.Bytes())
binary.Write(&buf, binary.BigEndian, uint16(len(data))) // nolint: errcheck
buf.Write(data)
return buf.Bytes()
}
func ReadRecord(reader io.Reader) (Record, error) {
@@ -65,9 +66,7 @@ func ReadRecord(reader io.Reader) (Record, error) {
return rec, nil
}
func MakeRecords(raw []byte) []Record {
var arr []Record
func MakeRecords(raw []byte) (arr []Record) {
for len(raw) > 0 {
chunkSize := recordMaxChunkSize
if chunkSize > len(raw) {
@@ -82,5 +81,5 @@ func MakeRecords(raw []byte) []Record {
raw = raw[chunkSize:]
}
return arr
return
}
+15 -17
View File
@@ -8,8 +8,9 @@ import (
"io"
mrand "math/rand"
"github.com/9seconds/mtg/config"
"golang.org/x/crypto/curve25519"
"github.com/9seconds/mtg/config"
)
type ServerHello struct {
@@ -19,38 +20,35 @@ type ServerHello struct {
}
func (s ServerHello) WelcomePacket() []byte {
buf := &bytes.Buffer{}
s.Random = [32]byte{}
rec := Record{
Type: RecordTypeHandshake,
Version: Version12,
Data: &s,
}
rec.WriteBytes(buf)
buf := bytes.NewBuffer(rec.Bytes())
recChangeCipher := Record{
Type: RecordTypeChangeCipherSpec,
Version: Version12,
Data: RawBytes([]byte{0x01}),
}
recChangeCipher.WriteBytes(buf)
buf.Write(recChangeCipher.Bytes())
hostCert := make([]byte, 1024+mrand.Intn(3092)) //nolint: gosec, gomnd
rand.Read(hostCert) //nolint: errcheck
hostCert := make([]byte, 1024+mrand.Intn(3092))
rand.Read(hostCert) // nolint: errcheck
recData := Record{
Type: RecordTypeApplicationData,
Version: Version12,
Data: RawBytes(hostCert),
}
recData.WriteBytes(buf)
buf.Write(recData.Bytes())
packet := buf.Bytes()
mac := hmac.New(sha256.New, config.C.Secret)
mac.Write(s.clientHello.Random[:])
mac.Write(packet)
mac.Write(s.clientHello.Random[:]) // nolint: errcheck
mac.Write(packet) // nolint: errcheck
copy(packet[11:], mac.Sum(nil))
return packet
@@ -66,8 +64,8 @@ func NewServerHello(clientHello *ClientHello) *ServerHello {
rv.SessionID = make([]byte, len(clientHello.SessionID))
copy(rv.SessionID, clientHello.SessionID)
tail := bytes.NewBuffer(CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes) //nolint: nosnakecase
tail.WriteByte(0x00) //nolint: gomnd // no compression
tail := bytes.NewBuffer(CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes)
tail.WriteByte(0x00) // no compression
makeTLSExtensions(tail)
rv.Tail = RawBytes(tail.Bytes())
@@ -75,7 +73,7 @@ func NewServerHello(clientHello *ClientHello) *ServerHello {
}
func makeTLSExtensions(buf io.Writer) {
buf.Write([]byte{ //nolint: errcheck
buf.Write([]byte{ // nolint: errcheck
0x00, 0x2e, // 46 bytes of data
0x00, 0x33, // Extension - Key Share
0x00, 0x24, // 36 bytes
@@ -85,11 +83,11 @@ func makeTLSExtensions(buf io.Writer) {
var scalar [32]byte
rand.Read(scalar[:]) //nolint: errcheck
rand.Read(scalar[:]) // nolint: errcheck
curve, _ := curve25519.X25519(scalar[:], curve25519.Basepoint)
buf.Write(curve) //nolint: errcheck
buf.Write(curve) // nolint: errcheck
buf.Write([]byte{ //nolint: errcheck
buf.Write([]byte{ // nolint: errcheck
0x00, 0x2b, // Extension - Supported Versions
0x00, 0x02, // 2 bytes are following
0x03, 0x04, // TLS 1.3
+6 -8
View File
@@ -3,26 +3,24 @@ package utils
import (
"fmt"
"net"
"github.com/9seconds/mtg/config"
)
func InitTCP(conn net.Conn, readBufferSize, writeBufferSize int) error {
tcpConn := conn.(*net.TCPConn) //nolint: forcetypeassert
func InitTCP(conn net.Conn) error {
tcpConn := conn.(*net.TCPConn)
if err := tcpConn.SetNoDelay(true); err != nil {
return fmt.Errorf("cannot set TCP_NO_DELAY: %w", err)
}
if err := tcpConn.SetReadBuffer(readBufferSize); err != nil {
if err := tcpConn.SetReadBuffer(config.C.ReadBuffer); err != nil {
return fmt.Errorf("cannot set read buffer size: %w", err)
}
if err := tcpConn.SetWriteBuffer(writeBufferSize); err != nil {
if err := tcpConn.SetWriteBuffer(config.C.WriteBuffer); err != nil {
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
}
+3 -4
View File
@@ -4,15 +4,14 @@ import "io"
const readFullBufferSize = 1024 + 1 // +1 because telegram opreates with blocks mod 4
func ReadFull(src io.Reader) ([]byte, error) {
func ReadFull(src io.Reader) (rv []byte, err error) {
buf := make([]byte, readFullBufferSize)
n := readFullBufferSize
rv := []byte{}
for n == len(buf) {
n, err := src.Read(buf)
n, err = src.Read(buf)
if err != nil {
return nil, err //nolint: wrapcheck
return nil, err
}
rv = append(rv, buf[:n]...)
+1 -1
View File
@@ -6,7 +6,7 @@ func ReverseBytes(data []byte) []byte {
rv := make([]byte, dataLen)
rv[dataLen/2] = data[dataLen/2]
for i := dataLen/2 - 1; i >= 0; i-- { //nolint: gomnd
for i := dataLen/2 - 1; i >= 0; i-- {
opp := dataLen - i - 1
rv[i], rv[opp] = data[opp], data[i]
}
+24
View File
@@ -0,0 +1,24 @@
// +build !windows
package utils
import (
"fmt"
"golang.org/x/sys/unix"
)
func SetLimits() error {
rLimit := unix.Rlimit{}
if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rLimit); err != nil {
return fmt.Errorf("cannot get rlimit: %w", err)
}
rLimit.Cur = rLimit.Max
if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &rLimit); err != nil {
return fmt.Errorf("cannot set rlimit: %w", err)
}
return nil
}
-1
View File
@@ -1,4 +1,3 @@
//go:build windows
// +build windows
package utils
-1
View File
@@ -1,4 +1,3 @@
//go:build !windows
// +build !windows
package utils
-1
View File
@@ -1,4 +1,3 @@
//go:build windows
// +build windows
package utils
+1 -2
View File
@@ -6,7 +6,6 @@ import (
)
func MakeStreamCipher(key, iv []byte) cipher.Stream {
block, _ := aes.NewCipher(key)
block, _ := aes.NewCipher(key) // nolint: gosec
return cipher.NewCTR(block, iv)
}
+2 -2
View File
@@ -3,9 +3,9 @@ package utils
type Uint24 [3]byte
func ToUint24(number uint32) Uint24 {
return Uint24{byte(number), byte(number >> 8), byte(number >> 16)} //nolint: gomnd
return Uint24{byte(number), byte(number >> 8), byte(number >> 16)}
}
func FromUint24(number Uint24) uint32 {
return uint32(number[0]) + (uint32(number[1]) << 8) + (uint32(number[2]) << 16) //nolint: gomnd
return uint32(number[0]) + (uint32(number[1]) << 8) + (uint32(number[2]) << 16)
}
+20 -20
View File
@@ -7,10 +7,12 @@ import (
"fmt"
"hash/crc32"
"io"
"io/ioutil"
"net"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
const (
@@ -27,14 +29,11 @@ var mtprotoFramePadding = []byte{0x04, 0x00, 0x00, 0x00}
//
// MSGLEN is the length of the message + len of seqno and msglen.
// SEQNO is the number of frame in the receive/send sequence. If client
//
// sends a message with SeqNo 18, it has to receive message with SeqNo 18.
//
// sends a message with SeqNo 18, it has to receive message with SeqNo 18.
// MSG is the data which has to be written
// CRC32 is the CRC32 checksum of MSGLEN + SEQNO + MSG
// PADDING is custom padding schema to complete frame length to such that
//
// len(frame) % 16 == 0
// len(frame) % 16 == 0
type wrapperMtprotoFrame struct {
parent conntypes.StreamReadWriteCloser
logger *zap.SugaredLogger
@@ -42,9 +41,8 @@ type wrapperMtprotoFrame struct {
writeSeqNo int32
}
func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { //nolint: funlen, cyclop
func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funlen
buf := &bytes.Buffer{}
sum := crc32.NewIEEE()
writer := io.MultiWriter(buf, sum)
@@ -52,7 +50,7 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { //nolint: funle
buf.Reset()
sum.Reset()
if _, err := io.CopyN(writer, w.parent, 4); err != nil { //nolint: gomnd
if _, err := io.CopyN(writer, w.parent, 4); err != nil {
return nil, fmt.Errorf("cannot read frame padding: %w", err)
}
@@ -73,24 +71,25 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { //nolint: funle
}
buf.Reset()
buf.Grow(int(messageLength) - 4 - 4)
if _, err := io.CopyN(writer, w.parent, int64(messageLength)-4-4); err != nil { //nolint: gomnd
if _, err := io.CopyN(writer, w.parent, int64(messageLength)-4-4); err != nil {
return nil, fmt.Errorf("cannot read the message frame: %w", err)
}
var seqNo int32
binary.Read(buf, binary.LittleEndian, &seqNo) //nolint: errcheck
binary.Read(buf, binary.LittleEndian, &seqNo) // nolint: errcheck
if seqNo != w.readSeqNo {
return nil, fmt.Errorf("unexpected sequence number %d (wait for %d)", seqNo, w.readSeqNo)
}
data, _ := io.ReadAll(buf)
data, _ := ioutil.ReadAll(buf) // nolint: gosec
buf.Reset()
// write to buf, not to writer. This is because we are going to fetch
// crc32 checksum.
if _, err := io.CopyN(buf, w.parent, 4); err != nil { //nolint: gomnd
if _, err := io.CopyN(buf, w.parent, 4); err != nil {
return nil, fmt.Errorf("cannot read checksum: %w", err)
}
@@ -111,18 +110,19 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { //nolint: funle
}
func (w *wrapperMtprotoFrame) Write(p conntypes.Packet) error {
messageLength := 4 + 4 + len(p) + 4 //nolint: gomnd
messageLength := 4 + 4 + len(p) + 4
paddingLength := (aes.BlockSize - messageLength%aes.BlockSize) % aes.BlockSize
buf := &bytes.Buffer{}
buf.Grow(messageLength + paddingLength)
binary.Write(buf, binary.LittleEndian, uint32(messageLength)) //nolint: errcheck
binary.Write(buf, binary.LittleEndian, w.writeSeqNo) //nolint: errcheck
binary.Write(buf, binary.LittleEndian, uint32(messageLength)) // nolint: errcheck
binary.Write(buf, binary.LittleEndian, w.writeSeqNo) // nolint: errcheck
buf.Write(p)
checksum := crc32.ChecksumIEEE(buf.Bytes())
binary.Write(buf, binary.LittleEndian, checksum) //nolint: errcheck
buf.Write(bytes.Repeat(mtprotoFramePadding, paddingLength/4)) //nolint: gomnd
binary.Write(buf, binary.LittleEndian, checksum) // nolint: errcheck
buf.Write(bytes.Repeat(mtprotoFramePadding, paddingLength/4))
w.logger.Debugw("Write MTProto frame",
"length", len(p),
@@ -134,11 +134,11 @@ func (w *wrapperMtprotoFrame) Write(p conntypes.Packet) error {
_, err := w.parent.Write(buf.Bytes())
return err //nolint: wrapcheck
return err
}
func (w *wrapperMtprotoFrame) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperMtprotoFrame) Conn() net.Conn {
+6 -5
View File
@@ -6,9 +6,10 @@ import (
"io"
"net"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/utils"
"go.uber.org/zap"
)
const (
@@ -39,9 +40,9 @@ func (w *wrapperClientAbridged) Read(acks *conntypes.ConnectionAcks) (conntypes.
}
if msgLength == clientAbridgedSmallPacketLength {
buf.Grow(3) //nolint: gomnd
buf.Grow(3)
if _, err := io.CopyN(&buf, w.parent, 3); err != nil { //nolint: gomnd
if _, err := io.CopyN(&buf, w.parent, 3); err != nil {
return nil, fmt.Errorf("cannot read correct message length: %w", err)
}
@@ -75,7 +76,7 @@ func (w *wrapperClientAbridged) Write(packet conntypes.Packet, acks *conntypes.C
return nil
}
packetLength := len(packet) / 4 //nolint: gomnd
packetLength := len(packet) / 4
switch {
case packetLength < clientAbridgedSmallPacketLength:
@@ -104,7 +105,7 @@ func (w *wrapperClientAbridged) Write(packet conntypes.Packet, acks *conntypes.C
}
func (w *wrapperClientAbridged) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperClientAbridged) Conn() net.Conn {
+5 -4
View File
@@ -7,8 +7,9 @@ import (
"io"
"net"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
const clientIntermediateQuickAckLength = 0x80000000
@@ -20,9 +21,9 @@ type wrapperClientIntermediate struct {
func (w *wrapperClientIntermediate) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, error) {
buf := bytes.Buffer{}
buf.Grow(4) //nolint: gomnd
buf.Grow(4)
if _, err := io.CopyN(&buf, w.parent, 4); err != nil { //nolint: gomnd
if _, err := io.CopyN(&buf, w.parent, 4); err != nil {
return nil, fmt.Errorf("cannot read message length: %w", err)
}
@@ -63,7 +64,7 @@ func (w *wrapperClientIntermediate) Write(packet conntypes.Packet, acks *conntyp
}
func (w *wrapperClientIntermediate) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperClientIntermediate) Conn() net.Conn {
@@ -6,8 +6,9 @@ import (
"fmt"
"math/rand"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
type wrapperClientIntermediateSecure struct {
@@ -20,7 +21,7 @@ func (w *wrapperClientIntermediateSecure) Read(acks *conntypes.ConnectionAcks) (
return nil, err
}
length := len(data) - (len(data) % 4) //nolint: gomnd
length := len(data) - (len(data) % 4)
return data[:length], nil
}
@@ -34,12 +35,11 @@ func (w *wrapperClientIntermediateSecure) Write(packet conntypes.Packet, acks *c
return nil
}
buf := &bytes.Buffer{}
paddingLength := rand.Intn(4) //nolint: gosec, gomnd
buf := bytes.Buffer{}
paddingLength := rand.Intn(4)
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(make([]byte, paddingLength))
+4 -6
View File
@@ -23,8 +23,8 @@ type wrapperProxy struct {
func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.ConnectionAcks) error {
buf := bytes.Buffer{}
flags := w.flags
flags := w.flags
if acks.Quick {
flags |= rpc.ProxyRequestFlagsQuickAck
}
@@ -42,11 +42,10 @@ func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.Connection
buf.Write(rpc.ProxyRequestProxyTag)
buf.WriteByte(byte(len(config.C.AdTag)))
buf.Write(config.C.AdTag)
buf.Write(make([]byte, (4-buf.Len()%4)%4)) //nolint: gomnd
buf.Grow(len(packet))
buf.Write(make([]byte, (4-buf.Len()%4)%4))
buf.Write(packet)
return w.proxy.Write(buf.Bytes()) //nolint: wrapcheck
return w.proxy.Write(buf.Bytes())
}
func (w *wrapperProxy) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, error) {
@@ -64,7 +63,6 @@ func (w *wrapperProxy) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, e
func (w *wrapperProxy) Close() error {
w.proxy.Close()
return nil
}
@@ -78,7 +76,7 @@ func NewProxy(request *protocol.TelegramRequest) (conntypes.PacketAckReadWriteCl
flags |= rpc.ProxyRequestFlagsIntermediate
case conntypes.ConnectionTypeSecure:
flags |= rpc.ProxyRequestFlagsIntermediate | rpc.ProxyRequestFlagsPad
case conntypes.ConnectionTypeUnknown:
default:
panic("unknown connection type")
}
+3 -3
View File
@@ -20,7 +20,7 @@ func (w *wrapperPing) Read(p []byte) (int, error) {
}
}
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperPing) Write(p []byte) (int, error) {
@@ -32,11 +32,11 @@ func (w *wrapperPing) Write(p []byte) (int, error) {
}
}
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperPing) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func NewPing(ctx context.Context, parent io.ReadWriteCloser, channelPing chan<- struct{}) io.ReadWriteCloser {
+6 -6
View File
@@ -7,9 +7,10 @@ import (
"net"
"time"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/utils"
"go.uber.org/zap"
)
type wrapperBlockCipher struct {
@@ -26,7 +27,7 @@ func (w *wrapperBlockCipher) Write(p []byte) (int, error) {
return 0, err
}
return w.parent.Write(encrypted) //nolint: wrapcheck
return w.parent.Write(encrypted)
}
func (w *wrapperBlockCipher) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
@@ -35,7 +36,7 @@ func (w *wrapperBlockCipher) WriteTimeout(p []byte, timeout time.Duration) (int,
return 0, err
}
return w.parent.WriteTimeout(encrypted, timeout) //nolint: wrapcheck
return w.parent.WriteTimeout(encrypted, timeout)
}
func (w *wrapperBlockCipher) encrypt(p []byte) ([]byte, error) {
@@ -50,7 +51,7 @@ func (w *wrapperBlockCipher) encrypt(p []byte) ([]byte, error) {
}
func (w *wrapperBlockCipher) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperBlockCipher) Conn() net.Conn {
@@ -70,8 +71,7 @@ func (w *wrapperBlockCipher) RemoteAddr() *net.TCPAddr {
}
func newBlockCipher(parent conntypes.StreamReadWriteCloser,
encryptor, decryptor cipher.BlockMode,
) conntypes.StreamReadWriteCloser {
encryptor, decryptor cipher.BlockMode) conntypes.StreamReadWriteCloser {
cipher := &wrapperBlockCipher{
parent: parent,
encryptor: encryptor,
+1 -1
View File
@@ -33,7 +33,7 @@ func (b *bufferedReader) ReadTimeout(p []byte, _ time.Duration) (int, error) {
func (b *bufferedReader) flush(p []byte) (int, error) {
if b.buf.Len() > len(p) {
return b.buf.Read(p) //nolint: wrapcheck
return b.buf.Read(p)
}
sizeToReturn := b.buf.Len()
+10 -13
View File
@@ -5,9 +5,10 @@ import (
"net"
"time"
"go.uber.org/zap"
"github.com/9seconds/mtg/config"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
)
type connPurpose uint8
@@ -28,7 +29,6 @@ type wrapperConn struct {
func (w *wrapperConn) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
if err := w.parent.SetWriteDeadline(time.Now().Add(timeout)); err != nil {
w.Close()
return 0, fmt.Errorf("cannot set write deadline to the socket: %w", err)
}
@@ -40,16 +40,15 @@ func (w *wrapperConn) Write(p []byte) (int, error) {
w.logger.Debugw("write to stream", "bytes", n, "error", err)
if err != nil {
w.Close()
w.Close() // nolint: gosec
}
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperConn) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
if err := w.parent.SetReadDeadline(time.Now().Add(timeout)); err != nil {
w.Close()
return 0, fmt.Errorf("cannot set read deadline to the socket: %w", err)
}
@@ -64,13 +63,12 @@ func (w *wrapperConn) Read(p []byte) (int, error) {
w.Close()
}
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperConn) Close() error {
w.logger.Debugw("Close connection")
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperConn) Conn() net.Conn {
@@ -91,11 +89,10 @@ func (w *wrapperConn) RemoteAddr() *net.TCPAddr {
func newConn(parent net.Conn,
connID conntypes.ConnID,
purpose connPurpose,
) conntypes.StreamReadWriteCloser {
localAddr := *parent.LocalAddr().(*net.TCPAddr) //nolint: forcetypeassert
purpose connPurpose) conntypes.StreamReadWriteCloser {
localAddr := *parent.LocalAddr().(*net.TCPAddr)
if parent.RemoteAddr().(*net.TCPAddr).IP.To4() != nil { //nolint: forcetypeassert
if parent.RemoteAddr().(*net.TCPAddr).IP.To4() != nil {
if config.C.PublicIPv4.IP != nil {
localAddr.IP = config.C.PublicIPv4.IP
}
@@ -118,7 +115,7 @@ func newConn(parent net.Conn,
parent: parent,
connID: connID,
logger: logger,
remoteAddr: parent.RemoteAddr().(*net.TCPAddr), //nolint: forcetypeassert
remoteAddr: parent.RemoteAddr().(*net.TCPAddr),
localAddr: &localAddr,
}
}
+8 -13
View File
@@ -6,8 +6,9 @@ import (
"net"
"time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
type wrapperCtx struct {
@@ -20,10 +21,9 @@ func (w *wrapperCtx) WriteTimeout(p []byte, timeout time.Duration) (int, error)
select {
case <-w.ctx.Done():
w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default:
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
return w.parent.WriteTimeout(p, timeout)
}
}
@@ -31,10 +31,9 @@ func (w *wrapperCtx) Write(p []byte) (int, error) {
select {
case <-w.ctx.Done():
w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default:
return w.parent.Write(p) //nolint: wrapcheck
return w.parent.Write(p)
}
}
@@ -42,10 +41,9 @@ func (w *wrapperCtx) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
select {
case <-w.ctx.Done():
w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default:
return w.parent.ReadTimeout(p, timeout) //nolint: wrapcheck
return w.parent.ReadTimeout(p, timeout)
}
}
@@ -53,17 +51,15 @@ func (w *wrapperCtx) Read(p []byte) (int, error) {
select {
case <-w.ctx.Done():
w.Close()
return 0, fmt.Errorf("cannot write because context was closed: %w", w.ctx.Err())
default:
return w.parent.Read(p) //nolint: wrapcheck
return w.parent.Read(p)
}
}
func (w *wrapperCtx) Close() error {
w.cancel()
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperCtx) Conn() net.Conn {
@@ -84,8 +80,7 @@ func (w *wrapperCtx) RemoteAddr() *net.TCPAddr {
func NewCtx(ctx context.Context,
cancel context.CancelFunc,
parent conntypes.StreamReadWriteCloser,
) conntypes.StreamReadWriteCloser {
parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
return &wrapperCtx{
parent: parent,
ctx: ctx,
+9 -19
View File
@@ -1,15 +1,15 @@
package stream
import (
"bytes"
"errors"
"fmt"
"net"
"time"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/tlstypes"
"go.uber.org/zap"
)
type wrapperFakeTLS struct {
@@ -20,7 +20,7 @@ type wrapperFakeTLS struct {
func (w *wrapperFakeTLS) Write(p []byte) (int, error) {
return w.write(p, func(b []byte) (int, error) {
return w.parent.Write(b) //nolint: wrapcheck
return w.parent.Write(b)
})
}
@@ -30,27 +30,22 @@ func (w *wrapperFakeTLS) WriteTimeout(p []byte, timeout time.Duration) (int, err
return w.write(p, func(b []byte) (int, error) {
elapsed := time.Since(startTime)
if elapsed > timeout {
return w.parent.WriteTimeout(b, timeout-elapsed) //nolint: wrapcheck
return w.parent.WriteTimeout(b, timeout-elapsed)
}
return 0, errors.New("timeout")
})
}
func (w *wrapperFakeTLS) write(p []byte, writeFunc func([]byte) (int, error)) (int, error) {
sum := 0
buf := bytes.Buffer{}
for _, v := range tlstypes.MakeRecords(p) {
buf.Reset()
v.WriteBytes(&buf)
_, err := writeFunc(buf.Bytes())
_, err := writeFunc(v.Bytes())
if err != nil {
return sum, err
}
sum += v.Data.Len()
sum += len(v.Data.Bytes())
}
return sum, nil
@@ -73,7 +68,7 @@ func (w *wrapperFakeTLS) RemoteAddr() *net.TCPAddr {
}
func (w *wrapperFakeTLS) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func NewFakeTLS(socket conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
@@ -85,18 +80,13 @@ func NewFakeTLS(socket conntypes.StreamReadWriteCloser) conntypes.StreamReadWrit
for {
rec, err := tlstypes.ReadRecord(faketls.parent)
if err != nil {
return nil, err //nolint: wrapcheck
return nil, err
}
switch rec.Type {
case tlstypes.RecordTypeChangeCipherSpec:
case tlstypes.RecordTypeApplicationData:
buf := &bytes.Buffer{}
rec.Data.WriteBytes(buf)
return buf.Bytes(), nil
case tlstypes.RecordTypeHandshake:
return nil, errors.New("unsupported record type handshake")
return rec.Data.Bytes(), nil
default:
return nil, fmt.Errorf("unsupported record type %v", rec.Type)
}
+21 -24
View File
@@ -4,8 +4,8 @@ import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/sha1"
"crypto/md5" // nolint: gosec
"crypto/sha1" // nolint: gosec
"encoding/binary"
"net"
@@ -26,8 +26,7 @@ var mtprotoEmptyIP = [4]byte{0x00, 0x00, 0x00, 0x00}
func NewMiddleProxyCipher(parent conntypes.StreamReadWriteCloser,
req *rpc.NonceRequest,
resp *rpc.NonceResponse,
secret []byte,
) conntypes.StreamReadWriteCloser {
secret []byte) conntypes.StreamReadWriteCloser {
localAddr := parent.LocalAddr()
remoteAddr := parent.RemoteAddr()
@@ -54,13 +53,11 @@ func mtprotoDeriveKeys(purpose mtprotoCipherPurpose,
req *rpc.NonceRequest,
resp *rpc.NonceResponse,
client, remote *net.TCPAddr,
secret []byte,
) ([]byte, []byte) {
secret []byte) ([]byte, []byte) {
message := bytes.Buffer{}
message.Write(resp.Nonce)
message.Write(req.Nonce)
message.Write(req.CryptoTS)
message.Write(resp.Nonce) // nolint: gosec
message.Write(req.Nonce) // nolint: gosec
message.Write(req.CryptoTS) // nolint: gosec
clientIPv4 := mtprotoEmptyIP[:]
serverIPv4 := mtprotoEmptyIP[:]
@@ -70,41 +67,41 @@ func mtprotoDeriveKeys(purpose mtprotoCipherPurpose,
serverIPv4 = utils.ReverseBytes(remote.IP.To4())
}
message.Write(serverIPv4)
message.Write(serverIPv4) // nolint: gosec
var port [2]byte
binary.LittleEndian.PutUint16(port[:], uint16(client.Port))
message.Write(port[:])
message.Write(port[:]) // nolint: gosec
switch purpose {
case mtprotoCipherPurposeClient:
message.WriteString("CLIENT")
message.WriteString("CLIENT") // nolint: gosec
case mtprotoCipherPurposeServer:
message.WriteString("SERVER")
message.WriteString("SERVER") // nolint: gosec
default:
panic("Unexpected cipher purpose")
}
message.Write(clientIPv4)
message.Write(clientIPv4) // nolint: gosec
binary.LittleEndian.PutUint16(port[:], uint16(remote.Port))
message.Write(port[:])
message.Write(secret)
message.Write(resp.Nonce)
message.Write(port[:]) // nolint: gosec
message.Write(secret) // nolint: gosec
message.Write(resp.Nonce) // nolint: gosec
if client.IP.To4() == nil {
message.Write(client.IP.To16())
message.Write(remote.IP.To16())
message.Write(client.IP.To16()) // nolint: gosec
message.Write(remote.IP.To16()) // nolint: gosec
}
message.Write(req.Nonce)
message.Write(req.Nonce) // nolint: gosec
data := message.Bytes()
md5sum := md5.Sum(data[1:]) //nolint: gas
sha1sum := sha1.Sum(data) //nolint: gosec
md5sum := md5.Sum(data[1:]) // nolint: gas
sha1sum := sha1.Sum(data) // nolint: gosec
key := append(md5sum[:12], sha1sum[:]...)
iv := md5.Sum(data[2:]) //nolint: gas
iv := md5.Sum(data[2:]) // nolint: gas
return key, iv[:]
}
+11 -20
View File
@@ -1,14 +1,14 @@
package stream
import (
"bytes"
"crypto/cipher"
"fmt"
"net"
"time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
type wrapperObfuscated2 struct {
@@ -31,7 +31,7 @@ func (w *wrapperObfuscated2) ReadTimeout(p []byte, timeout time.Duration) (int,
func (w *wrapperObfuscated2) Read(p []byte) (int, error) {
n, err := w.parent.Read(p)
if err != nil {
return n, err //nolint: wrapcheck
return n, err
}
w.decryptor.XORKeyStream(p, p[:n])
@@ -40,27 +40,19 @@ func (w *wrapperObfuscated2) Read(p []byte) (int, error) {
}
func (w *wrapperObfuscated2) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
buffer := bytes.Buffer{}
buffer.Write(p)
buf := buffer.Bytes()
buf := make([]byte, len(p))
copy(buf, p)
w.encryptor.XORKeyStream(buf, buf)
return w.parent.WriteTimeout(buf, timeout) //nolint: wrapcheck
return w.parent.WriteTimeout(buf, timeout)
}
func (w *wrapperObfuscated2) Write(p []byte) (int, error) {
buffer := bytes.Buffer{}
buffer.Write(p)
buf := buffer.Bytes()
buf := make([]byte, len(p))
copy(buf, p)
w.encryptor.XORKeyStream(buf, buf)
return w.parent.Write(buf) //nolint: wrapcheck
return w.parent.Write(buf)
}
func (w *wrapperObfuscated2) Conn() net.Conn {
@@ -80,12 +72,11 @@ func (w *wrapperObfuscated2) RemoteAddr() *net.TCPAddr {
}
func (w *wrapperObfuscated2) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func NewObfuscated2(socket conntypes.StreamReadWriteCloser,
encryptor, decryptor cipher.Stream,
) conntypes.StreamReadWriteCloser {
encryptor, decryptor cipher.Stream) conntypes.StreamReadWriteCloser {
return &wrapperObfuscated2{
parent: socket,
encryptor: encryptor,
+38 -17
View File
@@ -7,8 +7,9 @@ import (
"sync"
"time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
type ReadWriteCloseRewinder interface {
@@ -17,32 +18,56 @@ type ReadWriteCloseRewinder interface {
}
type wrapperRewind struct {
parent conntypes.StreamReadWriteCloser
activeReader io.Reader
buf bytes.Buffer
mutex sync.Mutex
parent conntypes.StreamReadWriteCloser
buf bytes.Buffer
mutex sync.Mutex
rewinded bool
}
func (w *wrapperRewind) Write(p []byte) (int, error) {
return w.parent.Write(p) //nolint: wrapcheck
return w.parent.Write(p)
}
func (w *wrapperRewind) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
return w.parent.WriteTimeout(p, timeout)
}
func (w *wrapperRewind) Read(p []byte) (int, error) {
w.mutex.Lock()
defer w.mutex.Unlock()
return w.activeReader.Read(p) //nolint: wrapcheck
if w.rewinded {
if n, err := w.buf.Read(p); err != io.EOF {
return n, err
}
}
n, err := w.parent.Read(p)
if !w.rewinded {
w.buf.Write(p[:n])
}
return n, err
}
func (w *wrapperRewind) ReadTimeout(p []byte, _ time.Duration) (int, error) {
func (w *wrapperRewind) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
w.mutex.Lock()
defer w.mutex.Unlock()
return w.activeReader.Read(p) //nolint: wrapcheck
if w.rewinded {
if n, err := w.buf.Read(p); err != io.EOF {
return n, err
}
}
n, err := w.parent.ReadTimeout(p, timeout)
if !w.rewinded {
w.buf.Write(p[:n])
}
return n, err
}
func (w *wrapperRewind) Conn() net.Conn {
@@ -63,21 +88,17 @@ func (w *wrapperRewind) RemoteAddr() *net.TCPAddr {
func (w *wrapperRewind) Close() error {
w.buf.Reset()
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperRewind) Rewind() {
w.mutex.Lock()
w.activeReader = io.MultiReader(&w.buf, w.parent)
w.rewinded = true
w.mutex.Unlock()
}
func NewRewind(parent conntypes.StreamReadWriteCloser) ReadWriteCloseRewinder {
rv := &wrapperRewind{
return &wrapperRewind{
parent: parent,
}
rv.activeReader = io.TeeReader(parent, &rv.buf)
return rv
}
+7 -6
View File
@@ -5,9 +5,10 @@ import (
"sync"
"time"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/stats"
"go.uber.org/zap"
)
type wrapperTelegramStats struct {
@@ -17,19 +18,19 @@ type wrapperTelegramStats struct {
}
func (w *wrapperTelegramStats) Write(p []byte) (int, error) {
return w.parent.Write(p) //nolint: wrapcheck
return w.parent.Write(p)
}
func (w *wrapperTelegramStats) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
return w.parent.WriteTimeout(p, timeout)
}
func (w *wrapperTelegramStats) Read(p []byte) (int, error) {
return w.parent.Read(p) //nolint: wrapcheck
return w.parent.Read(p)
}
func (w *wrapperTelegramStats) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
return w.parent.ReadTimeout(p, timeout) //nolint: wrapcheck
return w.parent.ReadTimeout(p, timeout)
}
func (w *wrapperTelegramStats) Conn() net.Conn {
@@ -56,7 +57,7 @@ func (w *wrapperTelegramStats) Close() error {
stats.Stats.TelegramDisconnected(w.dc, w.RemoteAddr())
})
return err //nolint: wrapcheck
return err
}
func NewTelegramStats(dc conntypes.DC, parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
+7 -6
View File
@@ -4,9 +4,10 @@ import (
"net"
"time"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
"github.com/9seconds/mtg/stats"
"go.uber.org/zap"
)
type wrapperTrafficStats struct {
@@ -17,28 +18,28 @@ func (w *wrapperTrafficStats) Write(p []byte) (int, error) {
n, err := w.parent.Write(p)
stats.Stats.EgressTraffic(n)
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperTrafficStats) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
n, err := w.parent.WriteTimeout(p, timeout)
stats.Stats.EgressTraffic(n)
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperTrafficStats) Read(p []byte) (int, error) {
n, err := w.parent.Read(p)
stats.Stats.IngressTraffic(n)
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperTrafficStats) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
n, err := w.parent.ReadTimeout(p, timeout)
stats.Stats.IngressTraffic(n)
return n, err //nolint: wrapcheck
return n, err
}
func (w *wrapperTrafficStats) Conn() net.Conn {
@@ -58,7 +59,7 @@ func (w *wrapperTrafficStats) RemoteAddr() *net.TCPAddr {
}
func (w *wrapperTrafficStats) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func NewTrafficStats(parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
+7 -6
View File
@@ -4,8 +4,9 @@ import (
"net"
"time"
"github.com/9seconds/mtg/conntypes"
"go.uber.org/zap"
"github.com/9seconds/mtg/conntypes"
)
const (
@@ -18,23 +19,23 @@ type wrapperTimeout struct {
}
func (w *wrapperTimeout) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
return w.parent.WriteTimeout(p, timeout)
}
func (w *wrapperTimeout) Write(p []byte) (int, error) {
return w.parent.WriteTimeout(p, timeoutWrite) //nolint: wrapcheck
return w.parent.WriteTimeout(p, timeoutWrite)
}
func (w *wrapperTimeout) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
return w.parent.ReadTimeout(p, timeout) //nolint: wrapcheck
return w.parent.ReadTimeout(p, timeout)
}
func (w *wrapperTimeout) Read(p []byte) (int, error) {
return w.parent.ReadTimeout(p, timeoutRead) //nolint: wrapcheck
return w.parent.ReadTimeout(p, timeoutRead)
}
func (w *wrapperTimeout) Close() error {
return w.parent.Close() //nolint: wrapcheck
return w.parent.Close()
}
func (w *wrapperTimeout) Conn() net.Conn {