mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 22:04:02 +03:00
REPOSITORY / ScuroNeko/mtg
Compare commits
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64859069ed | ||
|
|
c1935b4cef | ||
|
|
f48156814b | ||
|
|
9d67414db6 | ||
|
|
a587f85dd2 | ||
|
|
18a52340fa | ||
|
|
981ffb0dbe | ||
|
|
b976e74fc0 | ||
|
|
b2de98c8f9 | ||
|
|
6f3abf0990 | ||
|
|
e74726af70 | ||
|
|
8da55410de | ||
|
|
4b1f823777 | ||
|
|
511090b806 | ||
|
|
eba378817e | ||
|
|
c178b4b9cc | ||
|
|
3e0880f6b4 | ||
|
|
7718f62477 | ||
|
|
df0994dad3 | ||
|
|
dca43853fb | ||
|
|
ea8e31346c | ||
|
|
ed495b3800 | ||
|
|
4025f223c4 | ||
|
|
90e0ce4c48 | ||
|
|
ac0b442b43 | ||
|
|
af7021fac8 | ||
|
|
5468625212 | ||
|
|
345c1bf715 | ||
|
|
52d47a9786 | ||
|
|
2ba79a8508 | ||
|
|
ce7769472d | ||
|
|
eb5eea2625 | ||
|
|
d965dc3c07 | ||
|
|
040b3c371c | ||
|
|
c7ba8e54be | ||
|
|
33b1a5426c | ||
|
|
91197c0334 | ||
|
|
e075169dd4 | ||
|
|
225444b1b3 | ||
|
|
586ac9dcb9 | ||
|
|
c3be5311e8 | ||
|
|
bfeded67ee | ||
|
|
dde0d25b77 | ||
|
|
296a34cd6e | ||
|
|
44cea68e83 | ||
|
|
5d17e264e6 | ||
|
|
7ef1e99f66 | ||
|
|
3acbacbdb3 | ||
|
|
5fd7062972 | ||
|
|
7a6695f6c4 | ||
|
|
8ac786581b | ||
|
|
86a8f69273 | ||
|
|
95b16cd805 | ||
|
|
3996b9a6b8 | ||
|
|
e286dea650 | ||
|
|
5e27e48129 | ||
|
|
95abb54dc8 | ||
|
|
dbd3d3c266 | ||
|
|
ad7acee64d | ||
|
|
9ce6674070 | ||
|
|
25edb60f2c | ||
|
|
b5a8d8b804 | ||
|
|
35f0fca3c5 | ||
|
|
cd46a734ea | ||
|
|
cd92a343aa | ||
|
|
289e8f5945 | ||
|
|
850bed0dfc | ||
|
|
8977d77a13 | ||
|
|
91726d461f | ||
|
|
be1a47287a | ||
|
|
426483d27b | ||
|
|
bc72717582 | ||
|
|
391d901402 | ||
|
|
837d96dc43 | ||
|
|
9125a29e79 | ||
|
|
6449109b2b | ||
|
|
829669eefd | ||
|
|
2d9f2345dc | ||
|
|
6a9069ca72 | ||
|
|
d72ed03a43 | ||
|
|
f0d2cd494a | ||
|
|
b5810c955d | ||
|
|
4ebae693e0 | ||
|
|
1a619e3090 | ||
|
|
8e29ff78ba | ||
|
|
efdac2c0d8 | ||
|
|
e559388802 | ||
|
|
cb691453f0 | ||
|
|
020065f389 | ||
|
|
cf5197cee0 | ||
|
|
720158f15c | ||
|
|
07f00a363e | ||
|
|
d32ab34e60 | ||
|
|
5a52418394 | ||
|
|
cf43ae780b | ||
|
|
2407748ab0 | ||
|
|
a47edf08d0 | ||
|
|
566955b8b7 | ||
|
|
5cc07a54a2 | ||
|
|
ba2143a6ae | ||
|
|
acb02baa2e | ||
|
|
422ed5b071 | ||
|
|
19efcc93fc | ||
|
|
b4c47ff4e1 | ||
|
|
8a783d6b4e | ||
|
|
c5029c706c | ||
|
|
d7e565e0f5 | ||
|
|
93686377d5 | ||
|
|
87de28636a | ||
|
|
7788b169b6 | ||
|
|
6b9601fc2c | ||
|
|
a65cb05d20 | ||
|
|
31866d5f64 | ||
|
|
0db83a0cc8 | ||
|
|
40bb59faf5 | ||
|
|
307910fe4a | ||
|
|
4c2c468289 | ||
|
|
f2f7c2a4de | ||
|
|
8fdd4292b1 | ||
|
|
44d339d777 | ||
|
|
c6223e256d | ||
|
|
7928c2b323 | ||
|
|
b2e7e1a225 | ||
|
|
843fc4b70f |
+7
-1
@@ -1,3 +1,9 @@
|
||||
version.go
|
||||
vendor/
|
||||
tags
|
||||
.github/
|
||||
.bin/
|
||||
*.md
|
||||
mtg
|
||||
.golangci.toml
|
||||
.gitignore
|
||||
run.sh
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
|
||||
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
|
||||
@@ -0,0 +1,69 @@
|
||||
# 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
@@ -7,5 +7,5 @@
|
||||
*.out
|
||||
mtg
|
||||
vendor/
|
||||
version.go
|
||||
ccbuilds/
|
||||
.bin/
|
||||
dist/
|
||||
|
||||
+11
-2
@@ -3,11 +3,20 @@ concurrency = 4
|
||||
deadline = "2m"
|
||||
tests = true
|
||||
skip-dirs = ["vendor"]
|
||||
skip-files = ["version.go"]
|
||||
|
||||
[output]
|
||||
format = "colored-line-number"
|
||||
|
||||
[linters]
|
||||
enable-all = true
|
||||
disable = ["gochecknoglobals"]
|
||||
disable = [
|
||||
"containedctx",
|
||||
"exhaustivestruct",
|
||||
"exhaustruct",
|
||||
"gas",
|
||||
"gochecknoglobals",
|
||||
"goerr113",
|
||||
"ireturn",
|
||||
"thelper",
|
||||
"varnamelen",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
|
||||
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
@@ -1,19 +0,0 @@
|
||||
---
|
||||
|
||||
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
|
||||
+9
-13
@@ -1,7 +1,7 @@
|
||||
###############################################################################
|
||||
# BUILD STAGE
|
||||
|
||||
FROM golang:1.13-alpine
|
||||
FROM golang:1.19-alpine AS build
|
||||
|
||||
RUN set -x \
|
||||
&& apk --no-cache --update add \
|
||||
@@ -9,15 +9,13 @@ RUN set -x \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git \
|
||||
make \
|
||||
upx
|
||||
make
|
||||
|
||||
COPY . /go/src/github.com/9seconds/mtg/
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN set -x \
|
||||
&& cd /go/src/github.com/9seconds/mtg \
|
||||
&& make -j 4 static \
|
||||
&& upx --ultra-brute -qq ./mtg
|
||||
&& make -j 4 static
|
||||
|
||||
|
||||
###############################################################################
|
||||
@@ -26,11 +24,9 @@ RUN set -x \
|
||||
FROM scratch
|
||||
|
||||
ENTRYPOINT ["/mtg"]
|
||||
ENV MTG_IP=0.0.0.0 \
|
||||
MTG_PORT=3128 \
|
||||
MTG_STATS_IP=0.0.0.0 \
|
||||
MTG_STATS_PORT=3129
|
||||
ENV MTG_BIND=0.0.0.0:3128 \
|
||||
MTG_STATS_BIND=0.0.0.0:3129
|
||||
EXPOSE 3128 3129
|
||||
|
||||
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
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=build /app/mtg /mtg
|
||||
|
||||
@@ -2,58 +2,41 @@ ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
IMAGE_NAME := mtg
|
||||
APP_NAME := $(IMAGE_NAME)
|
||||
|
||||
CC_BINARIES := $(shell bash -c "echo -n $(APP_NAME)-{linux,freebsd,openbsd}-{386,amd64} $(APP_NAME)-linux-{arm,arm64}")
|
||||
|
||||
GOLANGCI_LINT_VERSION := v1.21.0
|
||||
GOLANGCI_LINT_VERSION := v1.48.0
|
||||
|
||||
VERSION_GO := $(shell go version)
|
||||
VERSION_DATE := $(shell date -Ru)
|
||||
VERSION_TAG := $(shell git describe --tags --always)
|
||||
COMMON_BUILD_FLAGS := -ldflags="-s -w -X 'main.version=$(VERSION_TAG) ($(VERSION_GO)) [$(VERSION_DATE)]'"
|
||||
COMMON_BUILD_FLAGS := -trimpath -mod=readonly -ldflags="-s -w -X 'main.version=$(VERSION_TAG) ($(VERSION_GO)) [$(VERSION_DATE)]'"
|
||||
|
||||
MOD_ON := env GO111MODULE=on
|
||||
MOD_OFF := env GO111MODULE=auto
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
$(APP_NAME):
|
||||
@$(MOD_ON) 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)-%: 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)"
|
||||
|
||||
ccbuilds:
|
||||
@rm -rf ./ccbuilds && mkdir -p ./ccbuilds
|
||||
|
||||
vendor: go.mod go.sum
|
||||
@$(MOD_ON) go mod vendor
|
||||
GOBIN := $(ROOT_DIR)/.bin
|
||||
GOTOOL := env "GOBIN=$(GOBIN)" "PATH=$(ROOT_DIR)/.bin:$(PATH)"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
.PHONY: all
|
||||
all: $(APP_NAME)
|
||||
all: build
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
@go build $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
|
||||
|
||||
$(APP_NAME): build
|
||||
|
||||
.PHONY: static
|
||||
static: static-$(APP_NAME)
|
||||
static:
|
||||
@env CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
|
||||
|
||||
.PHONY: crosscompile
|
||||
crosscompile: $(CC_BINARIES)
|
||||
vendor: go.mod go.sum
|
||||
@$(MOD_ON) go mod vendor
|
||||
|
||||
.PHONY: crosscompile-dir
|
||||
crosscompile-dir:
|
||||
@rm -rf "$(CC_DIR)" && mkdir -p "$(CC_DIR)"
|
||||
.PHONY: test
|
||||
test:
|
||||
@go test -v ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: vendor
|
||||
@$(MOD_OFF) golangci-lint run
|
||||
.PHONY: citest
|
||||
citest:
|
||||
@go test -coverprofile=coverage.txt -covermode=atomic -race -v ./...
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@@ -61,14 +44,50 @@ 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: prepare
|
||||
prepare: install-lint
|
||||
.PHONY: doc
|
||||
doc:
|
||||
@$(GOTOOL) godoc -http 0.0.0.0:10000
|
||||
|
||||
.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)
|
||||
.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
|
||||
|
||||
@@ -159,6 +159,9 @@ by design and we have the negligible possibility of duplication
|
||||
(probability is 1/(2^64)) but it could be quite effective to prevent
|
||||
replays.
|
||||
|
||||
It is possible to disable this cache. To do that, please explicitly set
|
||||
its size to 0.
|
||||
|
||||
|
||||
## FakeTLS
|
||||
|
||||
@@ -186,16 +189,18 @@ 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` | | 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_ADDR` | `--statsd-addr` | | host:port of statsd service. No defaults, by default we do not send anything there. |
|
||||
| `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` | `65536` | The size of TCP write buffer in bytes. Write buffer is the buffer for messages which are going from client to Telegram. |
|
||||
| `MTG_BUFFER_READ` | `-r`, `--read-buffer` | `131072` | The size of TCP read buffer in bytes. Read buffer is the buffer for messages from Telegram to client. |
|
||||
| `MTG_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_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
@@ -0,0 +1,24 @@
|
||||
# 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
|
||||
+4
-4
@@ -11,19 +11,19 @@ type cache struct {
|
||||
data *fastcache.Cache
|
||||
}
|
||||
|
||||
func (c *cache) AddObfuscated2(data []byte) {
|
||||
func (c cache) AddObfuscated2(data []byte) {
|
||||
c.data.Set(keyObfuscated2(data), nil)
|
||||
}
|
||||
|
||||
func (c *cache) AddTLS(data []byte) {
|
||||
func (c cache) AddTLS(data []byte) {
|
||||
c.data.Set(keyTLS(data), nil)
|
||||
}
|
||||
|
||||
func (c *cache) HasObfuscated2(data []byte) bool {
|
||||
func (c cache) HasObfuscated2(data []byte) bool {
|
||||
return c.data.Has(keyObfuscated2(data))
|
||||
}
|
||||
|
||||
func (c *cache) HasTLS(data []byte) bool {
|
||||
func (c cache) HasTLS(data []byte) bool {
|
||||
return c.data.Has(keyTLS(data))
|
||||
}
|
||||
|
||||
|
||||
+14
-4
@@ -3,18 +3,28 @@ package antireplay
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/VictoriaMetrics/fastcache"
|
||||
|
||||
"mtg/config"
|
||||
)
|
||||
|
||||
type CacheInterface interface {
|
||||
AddObfuscated2([]byte)
|
||||
AddTLS([]byte)
|
||||
HasObfuscated2([]byte) bool
|
||||
HasTLS([]byte) bool
|
||||
}
|
||||
|
||||
var (
|
||||
Cache cache
|
||||
Cache CacheInterface
|
||||
initOnce sync.Once
|
||||
)
|
||||
|
||||
func Init() {
|
||||
initOnce.Do(func() {
|
||||
Cache.data = fastcache.New(config.C.AntiReplayMaxSize)
|
||||
if config.C.AntiReplayMaxSize == 0 {
|
||||
Cache = nilCache{}
|
||||
} else {
|
||||
Cache = cache{fastcache.New(config.C.AntiReplayMaxSize)}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package antireplay
|
||||
|
||||
type nilCache struct{}
|
||||
|
||||
func (n nilCache) AddObfuscated2(_ []byte) {}
|
||||
func (n nilCache) AddTLS(_ []byte) {}
|
||||
func (n nilCache) HasObfuscated2(_ []byte) bool { return false }
|
||||
func (n nilCache) HasTLS(_ []byte) bool { return false }
|
||||
@@ -0,0 +1,84 @@
|
||||
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)))
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"mtg/config"
|
||||
"github.com/9seconds/mtg/config"
|
||||
)
|
||||
|
||||
func Generate(secretType, hostname string) {
|
||||
|
||||
+13
-14
@@ -5,22 +5,21 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/antireplay"
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/faketls"
|
||||
"github.com/9seconds/mtg/hub"
|
||||
"github.com/9seconds/mtg/ntp"
|
||||
"github.com/9seconds/mtg/obfuscated2"
|
||||
"github.com/9seconds/mtg/proxy"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"github.com/9seconds/mtg/telegram"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"mtg/antireplay"
|
||||
"mtg/config"
|
||||
"mtg/faketls"
|
||||
"mtg/hub"
|
||||
"mtg/ntp"
|
||||
"mtg/obfuscated2"
|
||||
"mtg/proxy"
|
||||
"mtg/stats"
|
||||
"mtg/telegram"
|
||||
"mtg/utils"
|
||||
)
|
||||
|
||||
func Proxy() error { // nolint: funlen
|
||||
func Proxy() error { //nolint: funlen,cyclop
|
||||
ctx := utils.GetSignalContext()
|
||||
|
||||
atom := zap.NewAtomicLevel()
|
||||
@@ -42,7 +41,7 @@ func Proxy() error { // nolint: funlen
|
||||
))
|
||||
|
||||
zap.ReplaceGlobals(logger)
|
||||
defer logger.Sync() // nolint: errcheck
|
||||
defer logger.Sync() //nolint: errcheck
|
||||
|
||||
if err := config.InitPublicAddress(ctx); err != nil {
|
||||
Fatal(err)
|
||||
@@ -50,7 +49,7 @@ func Proxy() error { // nolint: funlen
|
||||
|
||||
zap.S().Debugw("Configuration", "config", config.Printable())
|
||||
|
||||
if len(config.C.AdTag) > 0 {
|
||||
if config.C.MiddleProxyMode() {
|
||||
zap.S().Infow("Use middle proxy connection to Telegram")
|
||||
|
||||
diff, err := ntp.Fetch()
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func Fatal(arg interface{}) {
|
||||
if value, ok := arg.(error); ok {
|
||||
arg = fmt.Errorf("fatal error: %+v", value)
|
||||
arg = fmt.Errorf("fatal error: %+v", value) //nolint: errorlint
|
||||
}
|
||||
|
||||
PrintStderr(arg)
|
||||
@@ -21,7 +21,7 @@ func PrintStderr(args ...interface{}) {
|
||||
}
|
||||
|
||||
func PrintStdout(args ...interface{}) {
|
||||
fmt.Println(args...)
|
||||
fmt.Println(args...) //nolint: forbidigo
|
||||
}
|
||||
|
||||
func PrintJSONStderr(data interface{}) {
|
||||
|
||||
+109
-32
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
|
||||
"github.com/alecthomas/units"
|
||||
@@ -21,6 +22,8 @@ func (s SecretMode) String() string {
|
||||
return "simple"
|
||||
case SecretModeSecured:
|
||||
return "secured"
|
||||
case SecretModeTLS:
|
||||
return "tls"
|
||||
}
|
||||
|
||||
return "tls"
|
||||
@@ -32,6 +35,13 @@ const (
|
||||
SecretModeTLS
|
||||
)
|
||||
|
||||
type PreferIP uint8
|
||||
|
||||
const (
|
||||
PreferIPv4 PreferIP = iota
|
||||
PreferIPv6
|
||||
)
|
||||
|
||||
const SimpleSecretLength = 16
|
||||
|
||||
type OptionType uint8
|
||||
@@ -40,6 +50,8 @@ const (
|
||||
OptionTypeDebug OptionType = iota
|
||||
OptionTypeVerbose
|
||||
|
||||
OptionTypePreferIP
|
||||
|
||||
OptionTypeBind
|
||||
OptionTypePublicIPv4
|
||||
OptionTypePublicIPv6
|
||||
@@ -59,38 +71,88 @@ const (
|
||||
|
||||
OptionTypeMultiplexPerConnection
|
||||
|
||||
OptionTypeNTPServers
|
||||
|
||||
OptionTypeSecret
|
||||
OptionTypeAdtag
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Bind *net.TCPAddr `json:"bind"`
|
||||
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"`
|
||||
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
|
||||
|
||||
StatsNamespace string `json:"stats_namespace"`
|
||||
CloakHost string `json:"cloak_host"`
|
||||
StatsdTags map[string]string `json:"statsd_tags"`
|
||||
StatsNamespace string `json:"stats_namespace"` //nolint: tagliatelle
|
||||
CloakHost string `json:"cloak_host"` //nolint: tagliatelle
|
||||
StatsdTags map[string]string `json:"statsd_tags"` //nolint: tagliatelle
|
||||
|
||||
WriteBuffer int `json:"write_buffer"`
|
||||
ReadBuffer int `json:"read_buffer"`
|
||||
CloakPort int `json:"cloak_port"`
|
||||
WriteBuffer int `json:"write_buffer"` //nolint: tagliatelle
|
||||
ReadBuffer int `json:"read_buffer"` //nolint: tagliatelle
|
||||
CloakPort int `json:"cloak_port"` //nolint: tagliatelle
|
||||
|
||||
AntiReplayMaxSize int `json:"anti_replay_max_size"`
|
||||
AntiReplayMaxSize int `json:"anti_replay_max_size"` //nolint: tagliatelle
|
||||
|
||||
MultiplexPerConnection int `json:"multiplex_per_connection"`
|
||||
MultiplexPerConnection int `json:"multiplex_per_connection"` //nolint: tagliatelle
|
||||
|
||||
Debug bool `json:"debug"`
|
||||
Verbose bool `json:"verbose"`
|
||||
SecretMode SecretMode `json:"secret_mode"`
|
||||
SecretMode SecretMode `json:"secret_mode"` //nolint: tagliatelle
|
||||
PreferIP PreferIP `json:"prefer_ip"` //nolint: tagliatelle
|
||||
NTPServers []string `json:"ntp_servers"` //nolint: tagliatelle
|
||||
|
||||
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{}
|
||||
@@ -98,33 +160,43 @@ type Opt struct {
|
||||
|
||||
var C = Config{}
|
||||
|
||||
func Init(options ...Opt) error { // nolint: gocyclo, funlen
|
||||
func Init(options ...Opt) error { //nolint: gocyclo, funlen, cyclop
|
||||
for _, opt := range options {
|
||||
switch opt.Option {
|
||||
case OptionTypeDebug:
|
||||
C.Debug = opt.Value.(bool)
|
||||
C.Debug = opt.Value.(bool) //nolint: forcetypeassert
|
||||
case OptionTypeVerbose:
|
||||
C.Verbose = opt.Value.(bool)
|
||||
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)
|
||||
}
|
||||
case OptionTypeBind:
|
||||
C.Bind = opt.Value.(*net.TCPAddr)
|
||||
C.Bind = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
|
||||
case OptionTypePublicIPv4:
|
||||
C.PublicIPv4 = opt.Value.(*net.TCPAddr)
|
||||
C.PublicIPv4 = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
|
||||
if C.PublicIPv4 == nil {
|
||||
C.PublicIPv4 = &net.TCPAddr{}
|
||||
}
|
||||
case OptionTypePublicIPv6:
|
||||
C.PublicIPv6 = opt.Value.(*net.TCPAddr)
|
||||
C.PublicIPv6 = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
|
||||
if C.PublicIPv6 == nil {
|
||||
C.PublicIPv6 = &net.TCPAddr{}
|
||||
}
|
||||
case OptionTypeStatsBind:
|
||||
C.StatsBind = opt.Value.(*net.TCPAddr)
|
||||
C.StatsBind = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
|
||||
case OptionTypeStatsNamespace:
|
||||
C.StatsNamespace = opt.Value.(string)
|
||||
C.StatsNamespace = opt.Value.(string) //nolint: forcetypeassert
|
||||
case OptionTypeStatsdAddress:
|
||||
C.StatsdAddr = opt.Value.(*net.TCPAddr)
|
||||
C.StatsdAddr = opt.Value.(*net.TCPAddr) //nolint: forcetypeassert
|
||||
case OptionTypeStatsdTagsFormat:
|
||||
value := opt.Value.(string)
|
||||
value := opt.Value.(string) //nolint: forcetypeassert
|
||||
switch value {
|
||||
case "datadog":
|
||||
C.StatsdTagsFormat = statsd.TagFormatDatadog
|
||||
@@ -134,21 +206,26 @@ func Init(options ...Opt) error { // nolint: gocyclo, funlen
|
||||
return fmt.Errorf("incorrect statsd tag %s", value)
|
||||
}
|
||||
case OptionTypeStatsdTags:
|
||||
C.StatsdTags = opt.Value.(map[string]string)
|
||||
C.StatsdTags = opt.Value.(map[string]string) //nolint: forcetypeassert
|
||||
case OptionTypeWriteBufferSize:
|
||||
C.WriteBuffer = int(opt.Value.(units.Base2Bytes))
|
||||
C.WriteBuffer = int(opt.Value.(units.Base2Bytes)) //nolint: forcetypeassert
|
||||
case OptionTypeReadBufferSize:
|
||||
C.ReadBuffer = int(opt.Value.(units.Base2Bytes))
|
||||
C.ReadBuffer = int(opt.Value.(units.Base2Bytes)) //nolint: forcetypeassert
|
||||
case OptionTypeCloakPort:
|
||||
C.CloakPort = int(opt.Value.(uint16))
|
||||
C.CloakPort = int(opt.Value.(uint16)) //nolint: forcetypeassert
|
||||
case OptionTypeAntiReplayMaxSize:
|
||||
C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes))
|
||||
C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes)) //nolint: forcetypeassert
|
||||
case OptionTypeMultiplexPerConnection:
|
||||
C.MultiplexPerConnection = int(opt.Value.(uint))
|
||||
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")
|
||||
}
|
||||
case OptionTypeSecret:
|
||||
C.Secret = opt.Value.([]byte)
|
||||
C.Secret = opt.Value.([]byte) //nolint: forcetypeassert
|
||||
case OptionTypeAdtag:
|
||||
C.AdTag = opt.Value.([]byte)
|
||||
C.AdTag = opt.Value.([]byte) //nolint: forcetypeassert
|
||||
default:
|
||||
return fmt.Errorf("unknown tag %v", opt.Option)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -41,12 +40,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)
|
||||
return dialer.DialContext(ctx, network, addr) //nolint: wrapcheck
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", ifconfigAddress, nil)
|
||||
req, err := http.NewRequest(http.MethodGet, ifconfigAddress, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create a request: %w", err)
|
||||
}
|
||||
@@ -54,15 +53,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(ioutil.Discard, resp.Body) // nolint: errcheck
|
||||
io.Copy(io.Discard, resp.Body) //nolint: errcheck
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cannot perform a request: %w", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close() // nolint: errcheck
|
||||
defer resp.Body.Close()
|
||||
|
||||
respDataBytes, err := ioutil.ReadAll(resp.Body)
|
||||
respDataBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read response body: %w", err)
|
||||
}
|
||||
|
||||
+26
-17
@@ -8,20 +8,21 @@ import (
|
||||
)
|
||||
|
||||
type URLs struct {
|
||||
TG string `json:"tg_url"`
|
||||
TMe string `json:"tme_url"`
|
||||
TGQRCode string `json:"tg_qrcode"`
|
||||
TMeQRCode string `json:"tme_qrcode"`
|
||||
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
|
||||
}
|
||||
|
||||
type IPURLs struct {
|
||||
IPv4 URLs `json:"ipv4"`
|
||||
IPv6 URLs `json:"ipv6"`
|
||||
BotSecret string `json:"secret_for_mtproxybot"`
|
||||
IPv4 *URLs `json:"ipv4,omitempty"`
|
||||
IPv6 *URLs `json:"ipv6,omitempty"`
|
||||
BotSecret string `json:"secret_for_mtproxybot"` //nolint: tagliatelle
|
||||
}
|
||||
|
||||
func GetURLs() (urls IPURLs) {
|
||||
func GetURLs() IPURLs {
|
||||
secret := ""
|
||||
urls := IPURLs{}
|
||||
|
||||
switch C.SecretMode {
|
||||
case SecretModeSimple:
|
||||
@@ -32,25 +33,33 @@ func GetURLs() (urls IPURLs) {
|
||||
secret = "ee" + hex.EncodeToString(C.Secret) + hex.EncodeToString([]byte(C.CloakHost))
|
||||
}
|
||||
|
||||
urls.IPv4 = makeURLs(C.PublicIPv4, secret)
|
||||
urls.IPv6 = makeURLs(C.PublicIPv6, secret)
|
||||
if C.PublicIPv4.IP != nil {
|
||||
urls.IPv4 = makeURLs(C.PublicIPv4, secret)
|
||||
}
|
||||
|
||||
if C.PublicIPv6.IP != nil {
|
||||
urls.IPv6 = makeURLs(C.PublicIPv6, secret)
|
||||
}
|
||||
|
||||
urls.BotSecret = hex.EncodeToString(C.Secret)
|
||||
|
||||
return urls
|
||||
}
|
||||
|
||||
func makeURLs(addr *net.TCPAddr, secret string) (urls URLs) {
|
||||
func makeURLs(addr *net.TCPAddr, secret string) *URLs {
|
||||
urls := &URLs{}
|
||||
|
||||
values := url.Values{}
|
||||
values.Set("server", addr.IP.String())
|
||||
values.Set("port", strconv.Itoa(addr.Port))
|
||||
values.Set("secret", secret)
|
||||
|
||||
urls.TG = makeTGURL(values)
|
||||
urls.TMe = makeTMeURL(values)
|
||||
urls.TGQRCode = makeQRCodeURL(urls.TG)
|
||||
urls.TMeQRCode = makeQRCodeURL(urls.TG)
|
||||
|
||||
return
|
||||
return &URLs{
|
||||
TG: makeTGURL(values),
|
||||
TMe: makeTMeURL(values),
|
||||
TGQRCode: makeQRCodeURL(urls.TG),
|
||||
TMeQRCode: makeQRCodeURL(urls.TMe),
|
||||
}
|
||||
}
|
||||
|
||||
func makeTGURL(values url.Values) string {
|
||||
|
||||
@@ -8,6 +8,8 @@ func (c ConnectionProtocol) String() string {
|
||||
return "any"
|
||||
case ConnectionProtocolIPv4:
|
||||
return "ipv4"
|
||||
case ConnectionProtocolIPv6:
|
||||
return "ipv6"
|
||||
}
|
||||
|
||||
return "ipv6"
|
||||
|
||||
+3
-1
@@ -21,7 +21,9 @@ func (t ConnectionType) Tag() []byte {
|
||||
return ConnectionTagAbridged
|
||||
case ConnectionTypeIntermediate:
|
||||
return ConnectionTagIntermediate
|
||||
default:
|
||||
case ConnectionTypeSecure, ConnectionTypeUnknown:
|
||||
return ConnectionTagSecure
|
||||
}
|
||||
|
||||
return ConnectionTagSecure
|
||||
}
|
||||
|
||||
+22
-34
@@ -2,23 +2,23 @@ package faketls
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"mtg/antireplay"
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
"mtg/obfuscated2"
|
||||
"mtg/protocol"
|
||||
"mtg/stats"
|
||||
"mtg/tlstypes"
|
||||
"mtg/wrappers/stream"
|
||||
"github.com/9seconds/mtg/antireplay"
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/obfuscated2"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"github.com/9seconds/mtg/tlstypes"
|
||||
"github.com/9seconds/mtg/wrappers/stream"
|
||||
)
|
||||
|
||||
type ClientProtocol struct {
|
||||
@@ -49,13 +49,13 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
|
||||
}
|
||||
|
||||
conn := stream.NewFakeTLS(socket)
|
||||
conn, err := c.ClientProtocol.Handshake(conn)
|
||||
|
||||
conn, err := c.ClientProtocol.Handshake(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
return conn, err
|
||||
return conn, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
|
||||
@@ -64,7 +64,10 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
|
||||
return fmt.Errorf("cannot read initial record: %w", err)
|
||||
}
|
||||
|
||||
clientHello, err := tlstypes.ParseClientHello(helloRecord.Data.Bytes())
|
||||
buf := &bytes.Buffer{}
|
||||
helloRecord.Data.WriteBytes(buf)
|
||||
|
||||
clientHello, err := tlstypes.ParseClientHello(buf.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse client hello: %w", err)
|
||||
}
|
||||
@@ -86,6 +89,7 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
|
||||
|
||||
if antireplay.Cache.HasTLS(clientHello.Random[:]) {
|
||||
stats.Stats.ReplayDetected()
|
||||
|
||||
return errors.New("replay attack is detected")
|
||||
}
|
||||
|
||||
@@ -101,32 +105,16 @@ func (c *ClientProtocol) tlsHandshake(conn io.ReadWriter) error {
|
||||
}
|
||||
|
||||
func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) {
|
||||
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort))
|
||||
hostConn, err := net.Dial("tcp", addr)
|
||||
stats.Stats.CloakedRequest()
|
||||
|
||||
addr := net.JoinHostPort(config.C.CloakHost, strconv.Itoa(config.C.CloakPort))
|
||||
|
||||
hostConn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer hostConn.Close()
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
go c.pipe(hostConn, clientConn, wg)
|
||||
|
||||
go c.pipe(clientConn, hostConn, wg)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (c *ClientProtocol) pipe(dst io.WriteCloser, src io.Reader, wg *sync.WaitGroup) {
|
||||
defer func() {
|
||||
wg.Done()
|
||||
dst.Close()
|
||||
}()
|
||||
|
||||
io.Copy(dst, src) // nolint: errcheck
|
||||
cloak(clientConn, hostConn)
|
||||
}
|
||||
|
||||
func MakeClientProtocol() protocol.ClientProtocol {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package faketls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/wrappers/rwc"
|
||||
)
|
||||
|
||||
const (
|
||||
cloakLastActivityTimeout = 5 * time.Second
|
||||
cloakMaxTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
func cloak(one, another io.ReadWriteCloser) {
|
||||
defer func() {
|
||||
one.Close()
|
||||
another.Close()
|
||||
}()
|
||||
|
||||
channelPing := make(chan struct{}, 1)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
one = rwc.NewPing(ctx, one, channelPing)
|
||||
another = rwc.NewPing(ctx, another, channelPing)
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
wg.Add(2) //nolint: gomnd
|
||||
|
||||
go cloakPipe(one, another, wg)
|
||||
|
||||
go cloakPipe(another, one, wg)
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
cancel()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
lastActivityTimer := time.NewTimer(cloakLastActivityTimeout)
|
||||
defer lastActivityTimer.Stop()
|
||||
|
||||
maxTimer := time.NewTimer(cloakMaxTimeout)
|
||||
defer maxTimer.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-channelPing:
|
||||
lastActivityTimer.Stop()
|
||||
lastActivityTimer = time.NewTimer(cloakLastActivityTimeout)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-lastActivityTimer.C:
|
||||
cancel()
|
||||
|
||||
return
|
||||
case <-maxTimer.C:
|
||||
cancel()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func cloakPipe(one io.Writer, another io.Reader, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
io.Copy(one, another) //nolint: errcheck
|
||||
}
|
||||
@@ -1,20 +1,31 @@
|
||||
module mtg
|
||||
module github.com/9seconds/mtg
|
||||
|
||||
go 1.13
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/VictoriaMetrics/fastcache v1.5.2
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
|
||||
github.com/beevik/ntp v0.2.0
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/prometheus/client_golang v1.2.1
|
||||
github.com/prometheus/procfs v0.0.7 // indirect
|
||||
github.com/smira/go-statsd v1.3.1
|
||||
go.uber.org/multierr v1.4.0 // indirect
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f
|
||||
golang.org/x/net v0.0.0-20191116160921-f9c825593386 // indirect
|
||||
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6
|
||||
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3 // indirect
|
||||
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
|
||||
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
|
||||
)
|
||||
|
||||
@@ -1,70 +1,159 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
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/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/VictoriaMetrics/fastcache v1.5.2 h1:Erd8iIuBAL9kke8JzM4+WxkKuFkHh3ktwLanJvDgR44=
|
||||
github.com/VictoriaMetrics/fastcache v1.5.2/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/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/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.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/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/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/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM=
|
||||
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
|
||||
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
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/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
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/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/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.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
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/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/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.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
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/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=
|
||||
@@ -72,107 +161,352 @@ 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/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
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.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
|
||||
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
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_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 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
|
||||
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/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ=
|
||||
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/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.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.0.7 h1:RS5GAlMbnkWkhs4+bPocMTmGjYkuCY5djjqEDdXOhcQ=
|
||||
github.com/prometheus/procfs v0.0.7/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/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/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/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/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/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/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=
|
||||
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/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=
|
||||
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=
|
||||
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-20191117063200-497ca9f6d64f h1:kz4KIr+xcPUsI3VMoqWfPMvtnJ6MGfiVwsWSVzphMO4=
|
||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
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/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/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/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-20191116160921-f9c825593386 h1:ktbWvQrW08Txdxno1PiDpSxPXG6ndGsfnJjRRtkM0LQ=
|
||||
golang.org/x/net v0.0.0-20191116160921-f9c825593386/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/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-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6 h1:8mlr2HX+lfl0eaQcjiHfVeM2FHxWkuYQ5a2Wcy8mE1s=
|
||||
golang.org/x/sys v0.0.0-20191118013547-6254a7c3cac6/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/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-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-20191118051429-5a76f03bc7c3 h1:3gzOmNy3PLCZ+3Ru/n5Gh7pPjsieiytYSDxFj6QY/oI=
|
||||
golang.org/x/tools v0.0.0-20191118051429-5a76f03bc7c3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
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/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/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=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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/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=
|
||||
|
||||
+16
-7
@@ -4,15 +4,17 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/mtproto"
|
||||
"github.com/9seconds/mtg/mtproto/rpc"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/mtproto"
|
||||
"mtg/mtproto/rpc"
|
||||
"mtg/protocol"
|
||||
)
|
||||
|
||||
const connectionTTL = time.Hour
|
||||
|
||||
type connection struct {
|
||||
conn conntypes.PacketReadWriteCloser
|
||||
proxyConns map[string]*ProxyConn
|
||||
@@ -28,9 +30,12 @@ type connection struct {
|
||||
channelConnDetach chan conntypes.ConnID
|
||||
}
|
||||
|
||||
func (c *connection) run() {
|
||||
func (c *connection) run() { //nolint: cyclop
|
||||
defer c.Close()
|
||||
|
||||
ttl := time.NewTimer(connectionTTL)
|
||||
defer ttl.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.channelDone:
|
||||
@@ -39,6 +44,9 @@ func (c *connection) run() {
|
||||
}
|
||||
|
||||
return
|
||||
case <-ttl.C:
|
||||
c.logger.Debugw("Closing connection by TTL")
|
||||
c.Close()
|
||||
case resp := <-c.channelRead:
|
||||
if channel, ok := c.proxyConns[string(resp.ConnID[:])]; ok {
|
||||
if resp.Type == rpc.ProxyResponseTypeCloseExt {
|
||||
@@ -81,6 +89,7 @@ func (c *connection) readLoop() {
|
||||
response, err := rpc.ParseProxyResponse(packet)
|
||||
if err != nil {
|
||||
c.logger.Debugw("Failed response", "error", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -139,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,
|
||||
|
||||
@@ -4,18 +4,14 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"mtg/config"
|
||||
"github.com/9seconds/mtg/config"
|
||||
)
|
||||
|
||||
type connectionList struct {
|
||||
connections []*connection
|
||||
}
|
||||
|
||||
func (c *connectionList) Get(conn *ProxyConn) (*connection, error) {
|
||||
if len(c.connections) > 0 {
|
||||
c.gc()
|
||||
}
|
||||
|
||||
func (c *connectionList) get(conn *ProxyConn) (*connection, error) {
|
||||
if len(c.connections) > 0 && c.connections[0].Len() < config.C.MultiplexPerConnection {
|
||||
if err := c.connections[0].Attach(conn); err == nil {
|
||||
return c.connections[0], nil
|
||||
@@ -29,6 +25,7 @@ func (c *connectionList) Get(conn *ProxyConn) (*connection, error) {
|
||||
|
||||
if err = newConn.Attach(conn); err != nil {
|
||||
newConn.Close()
|
||||
|
||||
return nil, fmt.Errorf("cannot attach to the newly created connection: %w", err)
|
||||
}
|
||||
|
||||
@@ -41,6 +38,9 @@ func (c *connectionList) Get(conn *ProxyConn) (*connection, error) {
|
||||
|
||||
func (c *connectionList) gc() {
|
||||
prevLen := len(c.connections)
|
||||
if prevLen == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for i := len(c.connections) - 1; i >= 0; i-- {
|
||||
lastIndex := len(c.connections) - 1
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"mtg/protocol"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
)
|
||||
|
||||
type hub struct {
|
||||
@@ -18,7 +18,7 @@ func (h *hub) Register(req *protocol.TelegramRequest) (*ProxyConn, error) {
|
||||
}
|
||||
|
||||
func (h *hub) getMux(req *protocol.TelegramRequest) *mux {
|
||||
var key int32 = 32767 + int32(req.ClientProtocol.DC()) + 100000*int32(req.ClientProtocol.ConnectionProtocol())
|
||||
key := 32767 + int32(req.ClientProtocol.DC()) + 100000*int32(req.ClientProtocol.ConnectionProtocol()) //nolint: gomnd
|
||||
|
||||
h.mutex.RLock()
|
||||
m, ok := h.muxes[key]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package hub
|
||||
|
||||
import "mtg/protocol"
|
||||
import "github.com/9seconds/mtg/protocol"
|
||||
|
||||
type Interface interface {
|
||||
Register(*protocol.TelegramRequest) (*ProxyConn, error)
|
||||
|
||||
+12
-3
@@ -2,11 +2,14 @@ package hub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/protocol"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
)
|
||||
|
||||
const muxGCEvery = time.Minute
|
||||
|
||||
type muxNewRequest struct {
|
||||
req *protocol.TelegramRequest
|
||||
resp chan<- muxNewResponse
|
||||
@@ -26,6 +29,9 @@ type mux struct {
|
||||
}
|
||||
|
||||
func (m *mux) run() {
|
||||
gcTicker := time.NewTicker(muxGCEvery)
|
||||
defer gcTicker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
@@ -34,9 +40,12 @@ func (m *mux) run() {
|
||||
}
|
||||
|
||||
return
|
||||
case <-gcTicker.C:
|
||||
m.connections.gc()
|
||||
case req := <-m.channelNew:
|
||||
m.connections.gc()
|
||||
proxyConn := newProxyConn(req.req, m.channelClosed)
|
||||
conn, err := m.connections.Get(proxyConn)
|
||||
conn, err := m.connections.get(proxyConn)
|
||||
|
||||
if err == nil {
|
||||
m.clients[string(req.req.ConnID[:])] = conn
|
||||
|
||||
+3
-3
@@ -4,9 +4,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/mtproto/rpc"
|
||||
"mtg/protocol"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/mtproto/rpc"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -5,15 +5,11 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/cli"
|
||||
"github.com/9seconds/mtg/config"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
"mtg/cli"
|
||||
"mtg/config"
|
||||
"mtg/utils"
|
||||
)
|
||||
|
||||
var version = "dev" // this has to be set by build ld flags
|
||||
|
||||
var (
|
||||
app = kingpin.New("mtg", "Simple MTPROTO proxy.")
|
||||
|
||||
@@ -41,6 +37,11 @@ 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').
|
||||
@@ -85,13 +86,13 @@ var (
|
||||
"Write buffer size. You can think about it as a buffer from client to Telegram.").
|
||||
Short('w').
|
||||
Envar("MTG_BUFFER_WRITE").
|
||||
Default("64KB").
|
||||
Default("32KB").
|
||||
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("128KB").
|
||||
Default("32KB").
|
||||
Bytes()
|
||||
runTLSCloakPort = runCommand.Flag("cloak-port",
|
||||
"Port which should be used for host cloaking.").
|
||||
@@ -108,19 +109,20 @@ 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()
|
||||
)
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
app.Version(version)
|
||||
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)
|
||||
@@ -128,6 +130,7 @@ 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},
|
||||
@@ -141,6 +144,7 @@ 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},
|
||||
)
|
||||
|
||||
+8
-8
@@ -3,12 +3,12 @@ package mtproto
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/mtproto/rpc"
|
||||
"mtg/protocol"
|
||||
"mtg/telegram"
|
||||
"mtg/wrappers/packet"
|
||||
"mtg/wrappers/stream"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/mtproto/rpc"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/telegram"
|
||||
"github.com/9seconds/mtg/wrappers/packet"
|
||||
"github.com/9seconds/mtg/wrappers/stream"
|
||||
)
|
||||
|
||||
func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.PacketReadWriteCloser, error) {
|
||||
@@ -19,8 +19,8 @@ func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.PacketReadWriteC
|
||||
}
|
||||
|
||||
rpcNonceConn := packet.NewMtprotoFrame(conn, rpc.SeqNoNonce)
|
||||
rpcNonceReq, err := doRPCNonceRequest(rpcNonceConn)
|
||||
|
||||
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
|
||||
return nil, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
return rpcNonceReq, nil
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -17,10 +17,10 @@ type HandshakeResponse struct {
|
||||
func (r *HandshakeResponse) Bytes() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
buf.Write(r.Type) // nolint: gosec
|
||||
buf.Write(r.Flags) // nolint: gosec
|
||||
buf.Write(r.SenderPID) // nolint: gosec
|
||||
buf.Write(r.PeerPID) // nolint: gosec
|
||||
buf.Write(r.Type)
|
||||
buf.Write(r.Flags)
|
||||
buf.Write(r.SenderPID)
|
||||
buf.Write(r.PeerPID)
|
||||
|
||||
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 {
|
||||
if len(data) != 32 { //nolint: gomnd
|
||||
return nil, fmt.Errorf("incorrect handshake response length %d", len(data))
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
keySelector := make([]byte, 4)
|
||||
cryptoTS := make([]byte, 4)
|
||||
nonce := make([]byte, 16) //nolint: gomnd
|
||||
keySelector := make([]byte, 4) //nolint: gomnd
|
||||
cryptoTS := make([]byte, 4) //nolint: gomnd
|
||||
|
||||
if _, err := rand.Read(nonce); err != nil {
|
||||
return nil, fmt.Errorf("cannot generate nonce: %w", err)
|
||||
}
|
||||
|
||||
copy(keySelector, proxySecret)
|
||||
|
||||
timestamp := time.Now().Truncate(time.Second).Unix() % 4294967296 // 256 ^ 4 - do not know how to name
|
||||
// 256 ^ 4 - do not know how to name
|
||||
timestamp := time.Now().Truncate(time.Second).Unix() % 4294967296 //nolint: gomnd
|
||||
binary.LittleEndian.PutUint32(cryptoTS, uint32(timestamp))
|
||||
|
||||
return &NonceRequest{
|
||||
|
||||
@@ -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) // 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
|
||||
buf.Write(r.Type)
|
||||
buf.Write(r.KeySelector)
|
||||
buf.Write(r.Crypto)
|
||||
buf.Write(r.CryptoTS)
|
||||
buf.Write(r.Nonce)
|
||||
|
||||
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 {
|
||||
if len(data) != 32 { //nolint: gomnd
|
||||
return nil, fmt.Errorf("unexpected message length %d", len(data))
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@ const (
|
||||
var ProxyRequestFlagsEncryptedPrefix [8]byte
|
||||
|
||||
func (r ProxyRequestFlags) Bytes() []byte {
|
||||
converted := make([]byte, 4)
|
||||
converted := make([]byte, 4) //nolint: gomnd
|
||||
binary.LittleEndian.PutUint32(converted, uint32(r))
|
||||
|
||||
return converted
|
||||
}
|
||||
|
||||
func (r ProxyRequestFlags) String() string {
|
||||
flags := make([]string, 0, 7)
|
||||
flags := make([]string, 0, 7) //nolint: gomnd
|
||||
|
||||
if r&ProxyRequestFlagsHasAdTag != 0 {
|
||||
flags = append(flags, "HAS_AD_TAG")
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"mtg/conntypes"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
type ProxyResponseType uint8
|
||||
@@ -24,7 +24,7 @@ type ProxyResponse struct {
|
||||
func ParseProxyResponse(packet conntypes.Packet) (*ProxyResponse, error) {
|
||||
var response ProxyResponse
|
||||
|
||||
if len(packet) < 4 {
|
||||
if len(packet) < 4 { //nolint: gomnd
|
||||
return nil, fmt.Errorf("incorrect packet length: %d", len(packet))
|
||||
}
|
||||
|
||||
|
||||
+3
-8
@@ -5,22 +5,16 @@ 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 := ntpEndpoints[rand.Intn(len(ntpEndpoints))]
|
||||
url := config.C.NTPServers[rand.Intn(len(config.C.NTPServers))] //nolint: gosec
|
||||
|
||||
resp, err := ntp.Query(url)
|
||||
if err != nil {
|
||||
@@ -45,6 +39,7 @@ func AutoUpdate() {
|
||||
diff, err := Fetch()
|
||||
if err != nil {
|
||||
logger.Debugw("Cannot fetch time from NTP", "error", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"mtg/antireplay"
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
"mtg/protocol"
|
||||
"mtg/stats"
|
||||
"mtg/utils"
|
||||
"mtg/wrappers/stream"
|
||||
"github.com/9seconds/mtg/antireplay"
|
||||
"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"
|
||||
)
|
||||
|
||||
const clientProtocolHandshakeTimeout = 10 * time.Second
|
||||
@@ -45,14 +45,14 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
|
||||
}
|
||||
|
||||
decHasher := sha256.New()
|
||||
decHasher.Write(fm.Key()) // nolint: errcheck
|
||||
decHasher.Write(config.C.Secret) // nolint: errcheck
|
||||
decHasher.Write(fm.Key())
|
||||
decHasher.Write(config.C.Secret)
|
||||
decryptor := utils.MakeStreamCipher(decHasher.Sum(nil), fm.IV())
|
||||
|
||||
invertedFrame := fm.Invert()
|
||||
encHasher := sha256.New()
|
||||
encHasher.Write(invertedFrame.Key()) // nolint: errcheck
|
||||
encHasher.Write(config.C.Secret) // nolint: errcheck
|
||||
encHasher.Write(invertedFrame.Key())
|
||||
encHasher.Write(config.C.Secret)
|
||||
encryptor := utils.MakeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
|
||||
|
||||
decryptedFrame := Frame{}
|
||||
@@ -84,6 +84,7 @@ 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")
|
||||
}
|
||||
|
||||
@@ -92,12 +93,14 @@ func (c *ClientProtocol) Handshake(socket conntypes.StreamReadWriteCloser) (conn
|
||||
return stream.NewObfuscated2(socket, encryptor, decryptor), nil
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
return
|
||||
return fm, nil
|
||||
}
|
||||
|
||||
type handshakeReader struct {
|
||||
@@ -105,7 +108,7 @@ type handshakeReader struct {
|
||||
}
|
||||
|
||||
func (h handshakeReader) Read(p []byte) (int, error) {
|
||||
return h.parent.ReadTimeout(p, clientProtocolHandshakeTimeout)
|
||||
return h.parent.ReadTimeout(p, clientProtocolHandshakeTimeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func MakeClientProtocol() protocol.ClientProtocol {
|
||||
|
||||
@@ -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() (nf Frame) {
|
||||
nf = *f
|
||||
func (f *Frame) Invert() Frame {
|
||||
nf := *f
|
||||
for i := 0; i < frameLenKey+frameLenIV; i++ {
|
||||
nf.data[frameOffsetFirst+i] = f.data[frameOffsetIV-1-i]
|
||||
}
|
||||
|
||||
return
|
||||
return nf
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/protocol"
|
||||
"mtg/telegram"
|
||||
"mtg/utils"
|
||||
"mtg/wrappers/stream"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/telegram"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"github.com/9seconds/mtg/wrappers/stream"
|
||||
)
|
||||
|
||||
func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.StreamReadWriteCloser, error) {
|
||||
@@ -39,7 +39,8 @@ func TelegramProtocol(req *protocol.TelegramRequest) (conntypes.StreamReadWriteC
|
||||
return stream.NewObfuscated2(conn, encryptor, decryptor), nil
|
||||
}
|
||||
|
||||
func generateFrame(cp protocol.ClientProtocol) (fm Frame) {
|
||||
func generateFrame(cp protocol.ClientProtocol) Frame {
|
||||
fm := Frame{}
|
||||
data := fm.Bytes()
|
||||
|
||||
for {
|
||||
@@ -47,22 +48,22 @@ func generateFrame(cp protocol.ClientProtocol) (fm Frame) {
|
||||
continue
|
||||
}
|
||||
|
||||
if data[0] == 0xef {
|
||||
if data[0] == 0xef { //nolint: gomnd
|
||||
continue
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
continue
|
||||
}
|
||||
|
||||
val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4])
|
||||
if val == 0x00000000 {
|
||||
val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4]) //nolint: gomnd
|
||||
if val == 0x00000000 { //nolint: gomnd
|
||||
continue
|
||||
}
|
||||
|
||||
copy(fm.Magic(), cp.ConnectionType().Tag())
|
||||
|
||||
return
|
||||
return fm
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package protocol
|
||||
|
||||
import "mtg/conntypes"
|
||||
import "github.com/9seconds/mtg/conntypes"
|
||||
|
||||
type ClientProtocol interface {
|
||||
Handshake(conntypes.StreamReadWriteCloser) (conntypes.StreamReadWriteCloser, error)
|
||||
|
||||
+1
-2
@@ -3,9 +3,8 @@ package protocol
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
type TelegramRequest struct {
|
||||
|
||||
+11
-14
@@ -4,31 +4,27 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/9seconds/mtg/obfuscated2"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/obfuscated2"
|
||||
"mtg/protocol"
|
||||
)
|
||||
|
||||
const directPipeBufferSize = 1024 * 1024
|
||||
const directPipeBufferSize = 1024
|
||||
|
||||
func directConnection(request *protocol.TelegramRequest) error {
|
||||
telegramConnRaw, err := obfuscated2.TelegramProtocol(request)
|
||||
if err != nil {
|
||||
return err
|
||||
return err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
telegramConn := telegramConnRaw.(conntypes.StreamReadWriteCloser)
|
||||
|
||||
defer telegramConn.Close()
|
||||
defer telegramConnRaw.Close()
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
wg.Add(2) //nolint: gomnd
|
||||
|
||||
go directPipe(telegramConn, request.ClientConn, wg, request.Logger)
|
||||
go directPipe(telegramConnRaw, request.ClientConn, wg, request.Logger)
|
||||
|
||||
go directPipe(request.ClientConn, telegramConn, wg, request.Logger)
|
||||
go directPipe(request.ClientConn, telegramConnRaw, wg, request.Logger)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
@@ -42,8 +38,9 @@ func directPipe(dst io.WriteCloser, src io.ReadCloser, wg *sync.WaitGroup, logge
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
buf := make([]byte, directPipeBufferSize)
|
||||
if _, err := io.CopyBuffer(dst, src, buf); err != nil {
|
||||
buf := [directPipeBufferSize]byte{}
|
||||
|
||||
if _, err := io.CopyBuffer(dst, src, buf[:]); err != nil {
|
||||
logger.Debugw("Cannot pump sockets", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -3,17 +3,17 @@ package proxy
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/wrappers/packetack"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/protocol"
|
||||
"mtg/wrappers/packetack"
|
||||
)
|
||||
|
||||
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)
|
||||
default:
|
||||
case conntypes.ConnectionTypeUnknown:
|
||||
panic("unknown connection type")
|
||||
}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
wg.Add(2) //nolint: gomnd
|
||||
|
||||
go middlePipe(telegramConn, clientConn, wg, request.Logger)
|
||||
|
||||
@@ -44,7 +44,8 @@ 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()
|
||||
@@ -53,15 +54,17 @@ func middlePipe(dst conntypes.PacketAckWriteCloser,
|
||||
|
||||
for {
|
||||
acks := conntypes.ConnectionAcks{}
|
||||
packet, err := src.Read(&acks)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+14
-12
@@ -4,14 +4,13 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"github.com/9seconds/mtg/wrappers/stream"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
"mtg/protocol"
|
||||
"mtg/stats"
|
||||
"mtg/utils"
|
||||
"mtg/wrappers/stream"
|
||||
)
|
||||
|
||||
type Proxy struct {
|
||||
@@ -30,8 +29,7 @@ func (p *Proxy) Serve(listener net.Listener) {
|
||||
case <-doneChan:
|
||||
return
|
||||
default:
|
||||
p.Logger.Errorw("Cannot allocate incoming connection", "error", err)
|
||||
continue
|
||||
p.Logger.Fatalw("Cannot allocate incoming connection", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +40,7 @@ func (p *Proxy) Serve(listener net.Listener) {
|
||||
func (p *Proxy) accept(conn net.Conn) {
|
||||
defer func() {
|
||||
conn.Close()
|
||||
|
||||
if err := recover(); err != nil {
|
||||
stats.Stats.Crash()
|
||||
p.Logger.Errorw("Crash of accept handler", "error", err)
|
||||
@@ -51,8 +50,9 @@ func (p *Proxy) accept(conn net.Conn) {
|
||||
connID := conntypes.NewConnID()
|
||||
logger := p.Logger.With("connection_id", connID)
|
||||
|
||||
if err := utils.InitTCP(conn); err != nil {
|
||||
if err := utils.InitTCP(conn, config.C.ClientReadBuffer(), config.C.ClientWriteBuffer()); err != nil {
|
||||
logger.Errorw("Cannot initialize client TCP connection", "error", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -66,10 +66,12 @@ func (p *Proxy) accept(conn net.Conn) {
|
||||
defer clientConn.Close()
|
||||
|
||||
clientProtocol := p.ClientProtocolMaker()
|
||||
clientConn, err := clientProtocol.Handshake(clientConn)
|
||||
|
||||
clientConn, err := clientProtocol.Handshake(clientConn)
|
||||
if err != nil {
|
||||
stats.Stats.AuthenticationFailed()
|
||||
logger.Warnw("Cannot perform client handshake", "error", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ func (p *Proxy) accept(conn net.Conn) {
|
||||
|
||||
err = nil
|
||||
|
||||
if len(config.C.AdTag) > 0 {
|
||||
if config.C.MiddleProxyMode() {
|
||||
middleConnection(req)
|
||||
} else {
|
||||
err = directConnection(req)
|
||||
|
||||
@@ -11,48 +11,58 @@
|
||||
# export MTG_IMAGENAME="nineseconds/mtg:latest"
|
||||
# curl -sfL --compressed https://raw.githubusercontent.com/9seconds/mtg/master/run.sh | bash
|
||||
|
||||
set -eu -o pipefail
|
||||
set -eu
|
||||
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export MTG_CONFIG="${MTG_CONFIG:-$XDG_CONFIG_HOME/mtg}"
|
||||
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo 'Error: docker is not installed.' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
id -Gn "$USER" | grep -qw 'docker' > /dev/null
|
||||
if [ $? -eq 0 ] || [ "$(id -u)" -eq '0' ]; then
|
||||
DOCKER_CMD="$(command -v docker)"
|
||||
else
|
||||
DOCKER_CMD="sudo $(command -v docker)"
|
||||
fi
|
||||
|
||||
mkdir -p "$MTG_CONFIG" || true
|
||||
|
||||
MTG_SECRET="$MTG_CONFIG/secret"
|
||||
MTG_ENV="$MTG_CONFIG/env"
|
||||
|
||||
if [ ! -f "$MTG_ENV" ]; then
|
||||
MTG_IMAGENAME="${MTG_IMAGENAME:-nineseconds/mtg:latest}"
|
||||
MTG_IMAGENAME="${MTG_IMAGENAME:-nineseconds/mtg:stable}"
|
||||
MTG_PORT="${MTG_PORT:-3128}"
|
||||
MTG_CONTAINER="${MTG_CONTAINER:-mtg}"
|
||||
|
||||
echo "MTG_IMAGENAME=${MTG_IMAGENAME}" > "$MTG_ENV"
|
||||
echo "MTG_PORT=${MTG_PORT}" >> "$MTG_ENV"
|
||||
echo "MTG_CONTAINER=${MTG_CONTAINER}" >> "$MTG_ENV"
|
||||
echo "MTG_IMAGENAME=$MTG_IMAGENAME" > "$MTG_ENV"
|
||||
echo "MTG_PORT=$MTG_PORT" >> "$MTG_ENV"
|
||||
echo "MTG_CONTAINER=$MTG_CONTAINER" >> "$MTG_ENV"
|
||||
fi
|
||||
|
||||
set -a
|
||||
source "$MTG_ENV"
|
||||
set +a
|
||||
|
||||
docker pull "$MTG_IMAGENAME"
|
||||
$DOCKER_CMD pull "$MTG_IMAGENAME" > /dev/null
|
||||
if [ ! -f "$MTG_SECRET" ]; then
|
||||
docker run \
|
||||
$DOCKER_CMD run \
|
||||
--rm \
|
||||
"$MTG_IMAGENAME" \
|
||||
generate-secret tls -c "$(openssl rand -hex 16).com" \
|
||||
> "$MTG_SECRET"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Proxy secret is $(cat "$MTG_SECRET"). Port is $MTG_PORT."
|
||||
echo
|
||||
|
||||
docker ps --filter "Name=$MTG_CONTAINER" -aq | xargs -r docker rm -fv
|
||||
docker run \
|
||||
$DOCKER_CMD ps --filter "Name=$MTG_CONTAINER" -aq | xargs -r $DOCKER_CMD rm -fv > /dev/null
|
||||
$DOCKER_CMD run \
|
||||
-d \
|
||||
--restart=unless-stopped \
|
||||
--name "$MTG_CONTAINER" \
|
||||
--ulimit nofile=51200:51200 \
|
||||
-p "$MTG_PORT:3128" \
|
||||
"$MTG_IMAGENAME" run "$(cat "$MTG_SECRET")"
|
||||
"$MTG_IMAGENAME" run "$(cat "$MTG_SECRET")" > /dev/null
|
||||
|
||||
+11
-1
@@ -3,7 +3,7 @@ package stats
|
||||
import (
|
||||
"net"
|
||||
|
||||
"mtg/conntypes"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
type IngressTrafficInterface interface {
|
||||
@@ -38,6 +38,14 @@ type ReplayDetectedInterface interface {
|
||||
ReplayDetected()
|
||||
}
|
||||
|
||||
type AuthenticationFailedInterface interface {
|
||||
AuthenticationFailed()
|
||||
}
|
||||
|
||||
type CloakedRequestInterface interface {
|
||||
CloakedRequest()
|
||||
}
|
||||
|
||||
type Interface interface {
|
||||
IngressTrafficInterface
|
||||
EgressTrafficInterface
|
||||
@@ -47,4 +55,6 @@ type Interface interface {
|
||||
TelegramDisconnectedInterface
|
||||
CrashInterface
|
||||
ReplayDetectedInterface
|
||||
AuthenticationFailedInterface
|
||||
CloakedRequestInterface
|
||||
}
|
||||
|
||||
+13
-1
@@ -3,7 +3,7 @@ package stats
|
||||
import (
|
||||
"net"
|
||||
|
||||
"mtg/conntypes"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
type multiStats []Interface
|
||||
@@ -55,3 +55,15 @@ func (m multiStats) ReplayDetected() {
|
||||
go m[i].ReplayDetected()
|
||||
}
|
||||
}
|
||||
|
||||
func (m multiStats) AuthenticationFailed() {
|
||||
for i := range m {
|
||||
go m[i].AuthenticationFailed()
|
||||
}
|
||||
}
|
||||
|
||||
func (m multiStats) CloakedRequest() {
|
||||
for i := range m {
|
||||
go m[i].CloakedRequest()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"mtg/config"
|
||||
"github.com/9seconds/mtg/config"
|
||||
)
|
||||
|
||||
var Stats Interface
|
||||
@@ -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)
|
||||
|
||||
+36
-10
@@ -5,19 +5,20 @@ 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"
|
||||
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
type statsPrometheus struct {
|
||||
connections *prometheus.GaugeVec
|
||||
telegramConnections *prometheus.GaugeVec
|
||||
traffic *prometheus.GaugeVec
|
||||
crashes prometheus.Counter
|
||||
replayAttacks prometheus.Counter
|
||||
connections *prometheus.GaugeVec
|
||||
telegramConnections *prometheus.GaugeVec
|
||||
traffic *prometheus.GaugeVec
|
||||
crashes prometheus.Counter
|
||||
replayAttacks prometheus.Counter
|
||||
authenticationFailed prometheus.Counter
|
||||
cloakedRequests prometheus.Counter
|
||||
}
|
||||
|
||||
func (s *statsPrometheus) IngressTraffic(traffic int) {
|
||||
@@ -38,7 +39,8 @@ 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",
|
||||
@@ -49,10 +51,14 @@ 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" // nolint: goconst
|
||||
labels[1] = "ipv6"
|
||||
}
|
||||
|
||||
s.connections.WithLabelValues(labels[:]...).Add(increment)
|
||||
@@ -87,6 +93,14 @@ func (s *statsPrometheus) ReplayDetected() {
|
||||
s.replayAttacks.Inc()
|
||||
}
|
||||
|
||||
func (s *statsPrometheus) AuthenticationFailed() {
|
||||
s.authenticationFailed.Inc()
|
||||
}
|
||||
|
||||
func (s *statsPrometheus) CloakedRequest() {
|
||||
s.cloakedRequests.Inc()
|
||||
}
|
||||
|
||||
func newStatsPrometheus(mux *http.ServeMux) Interface {
|
||||
registry := prometheus.NewPedanticRegistry()
|
||||
|
||||
@@ -116,6 +130,16 @@ func newStatsPrometheus(mux *http.ServeMux) Interface {
|
||||
Name: "replay_attacks",
|
||||
Help: "How many replay attacks were prevented.",
|
||||
}),
|
||||
authenticationFailed: prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: config.C.StatsNamespace,
|
||||
Name: "authentication_failed",
|
||||
Help: "How many authentication failed events we've seen.",
|
||||
}),
|
||||
cloakedRequests: prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: config.C.StatsNamespace,
|
||||
Name: "cloaked_requests",
|
||||
Help: "How many requests were proxified during cloaking.",
|
||||
}),
|
||||
}
|
||||
|
||||
registry.MustRegister(instance.connections)
|
||||
@@ -123,6 +147,8 @@ func newStatsPrometheus(mux *http.ServeMux) Interface {
|
||||
registry.MustRegister(instance.traffic)
|
||||
registry.MustRegister(instance.crashes)
|
||||
registry.MustRegister(instance.replayAttacks)
|
||||
registry.MustRegister(instance.authenticationFailed)
|
||||
registry.MustRegister(instance.cloakedRequests)
|
||||
|
||||
handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
|
||||
mux.Handle("/", handler)
|
||||
|
||||
+21
-11
@@ -8,11 +8,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
statsd "github.com/smira/go-statsd"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -84,15 +83,17 @@ func (s *statsStatsd) ClientDisconnected(connectionType conntypes.ConnectionType
|
||||
}
|
||||
|
||||
func (s *statsStatsd) changeConnections(connectionType conntypes.ConnectionType, addr *net.TCPAddr, increment int64) {
|
||||
tags := make([]*statsStatsdTag, 0, 2)
|
||||
tags := make([]*statsStatsdTag, 0, 2) //nolint: gomnd
|
||||
|
||||
switch connectionType {
|
||||
case conntypes.ConnectionTypeAbridged:
|
||||
tags = append(tags, tagConnectionTypeAbridged)
|
||||
case conntypes.ConnectionTypeIntermediate:
|
||||
tags = append(tags, tagConnectionTypeIntermediate)
|
||||
default:
|
||||
case conntypes.ConnectionTypeSecure:
|
||||
tags = append(tags, tagConnectionTypeSecured)
|
||||
case conntypes.ConnectionTypeUnknown:
|
||||
panic("Unknown connection type")
|
||||
}
|
||||
|
||||
if addr.IP.To4() == nil {
|
||||
@@ -137,6 +138,14 @@ func (s *statsStatsd) ReplayDetected() {
|
||||
s.gauge("replay_attacks", 1)
|
||||
}
|
||||
|
||||
func (s *statsStatsd) AuthenticationFailed() {
|
||||
s.gauge("authentication_failed", 1)
|
||||
}
|
||||
|
||||
func (s *statsStatsd) CloakedRequest() {
|
||||
s.gauge("cloaked_requests", 1)
|
||||
}
|
||||
|
||||
func (s *statsStatsd) gauge(metric string, value int64, tags ...*statsStatsdTag) {
|
||||
key, tagList := s.prepareVals(metric, tags)
|
||||
s.initGauge(metric, key, tagList)
|
||||
@@ -159,17 +168,18 @@ func (s *statsStatsd) prepareVals(metric string, tags []*statsStatsdTag) (string
|
||||
|
||||
func (s *statsStatsd) initGauge(metric, key string, tags []statsd.Tag) {
|
||||
s.seenMutex.RLock()
|
||||
_, ok := s.seen[key]
|
||||
s.seenMutex.RUnlock()
|
||||
if _, ok := s.seen[key]; ok {
|
||||
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...)
|
||||
}
|
||||
@@ -184,8 +194,8 @@ func newStatsStatsd() Interface {
|
||||
return &statsStatsd{
|
||||
seen: make(map[string]struct{}),
|
||||
client: statsd.NewClient(config.C.StatsdAddr.String(),
|
||||
statsd.SendLoopCount(2),
|
||||
statsd.ReconnectInterval(10*time.Second),
|
||||
statsd.SendLoopCount(2), //nolint: gomnd
|
||||
statsd.ReconnectInterval(10*time.Second), //nolint: gomnd
|
||||
statsd.Logger(logger),
|
||||
statsd.MetricPrefix(prefix),
|
||||
statsd.TagStyle(config.C.StatsdTagsFormat),
|
||||
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"mtg/conntypes"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
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)
|
||||
chunks := addressesProxyForSplitter.Split(text, 3) //nolint: gomnd
|
||||
if len(chunks) != 3 || chunks[0] != "proxy_for" {
|
||||
return "", 0, fmt.Errorf("incorrect config %s", text)
|
||||
}
|
||||
|
||||
dc, err := strconv.ParseInt(chunks[1], 10, 16)
|
||||
dc, err := strconv.ParseInt(chunks[1], 10, 16) //nolint: gomnd
|
||||
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)
|
||||
chunks := addressesProxyForSplitter.Split(text, 2) //nolint: gomnd
|
||||
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)
|
||||
dc, err := strconv.ParseInt(dcString, 10, 16) //nolint: gomnd
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||
}
|
||||
|
||||
+8
-5
@@ -1,15 +1,15 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
apiUserAgent = "mtg"
|
||||
apiUserAgent = "github.com/9seconds/mtg"
|
||||
apiHTTPTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
@@ -18,7 +18,10 @@ var httpClient = http.Client{
|
||||
}
|
||||
|
||||
func request(url string) (io.ReadCloser, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), apiHTTPTimeout)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -29,12 +32,12 @@ func request(url string) (io.ReadCloser, error) {
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
|
||||
io.Copy(io.Discard, resp.Body) //nolint: errcheck
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cannot perform a request: %w", err)
|
||||
}
|
||||
|
||||
return resp.Body, err
|
||||
return resp.Body, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
)
|
||||
|
||||
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 := ioutil.ReadAll(resp)
|
||||
secret, err := io.ReadAll(resp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read response: %w", err)
|
||||
}
|
||||
|
||||
+48
-20
@@ -1,21 +1,24 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/utils"
|
||||
"mtg/wrappers/stream"
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"github.com/9seconds/mtg/wrappers/stream"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type baseTelegram struct {
|
||||
dialer net.Dialer
|
||||
logger *zap.SugaredLogger
|
||||
|
||||
secret []byte
|
||||
v4DefaultDC conntypes.DC
|
||||
V6DefaultDC conntypes.DC
|
||||
v6DefaultDC conntypes.DC
|
||||
v4Addresses map[conntypes.DC][]string
|
||||
v6Addresses map[conntypes.DC][]string
|
||||
}
|
||||
@@ -25,30 +28,55 @@ func (b *baseTelegram) Secret() []byte {
|
||||
}
|
||||
|
||||
func (b *baseTelegram) dial(dc conntypes.DC,
|
||||
protocol conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error) {
|
||||
addr := ""
|
||||
protocol conntypes.ConnectionProtocol,
|
||||
) (conntypes.StreamReadWriteCloser, error) {
|
||||
for _, addr := range b.getAddresses(dc, protocol) {
|
||||
conn, err := b.dialer.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
b.logger.Infow("Cannot dial to Telegram", "address", addr, "error", err)
|
||||
|
||||
switch protocol {
|
||||
case conntypes.ConnectionProtocolIPv4:
|
||||
addr = b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC)
|
||||
default:
|
||||
addr = b.chooseAddress(b.v6Addresses, dc, b.V6DefaultDC)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := utils.InitTCP(conn, config.C.ProxyReadBuffer(), config.C.ProxyWriteBuffer()); err != nil {
|
||||
b.logger.Infow("Cannot initialize TCP socket", "address", addr, "error", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
return stream.NewTelegramConn(dc, conn), nil
|
||||
}
|
||||
|
||||
conn, err := b.dialer.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dial has failed: %w", err)
|
||||
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 err := utils.InitTCP(conn); err != nil {
|
||||
return nil, fmt.Errorf("cannot initialize tcp socket: %w", err)
|
||||
if config.C.PreferIP == config.PreferIPv4 {
|
||||
protos[0], protos[1] = protos[1], protos[0]
|
||||
}
|
||||
|
||||
return stream.NewTelegramConn(dc, conn), nil
|
||||
for _, proto := range protos {
|
||||
switch {
|
||||
case proto&protocol == 0:
|
||||
case proto&conntypes.ConnectionProtocolIPv6 != 0:
|
||||
addresses = append(addresses, b.chooseAddress(b.v6Addresses, dc, b.v6DefaultDC))
|
||||
case proto&conntypes.ConnectionProtocolIPv4 != 0:
|
||||
addresses = append(addresses, b.chooseAddress(b.v4Addresses, dc, b.v4DefaultDC))
|
||||
}
|
||||
}
|
||||
|
||||
return addresses
|
||||
}
|
||||
|
||||
func (b *baseTelegram) chooseAddress(addresses map[conntypes.DC][]string,
|
||||
dc, defaultDC conntypes.DC) string {
|
||||
dc, defaultDC conntypes.DC,
|
||||
) string {
|
||||
addrs, ok := addresses[dc]
|
||||
if !ok {
|
||||
addrs = addresses[defaultDC]
|
||||
@@ -58,7 +86,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))]
|
||||
return addrs[rand.Intn(len(addrs))] //nolint: gosec
|
||||
}
|
||||
|
||||
return ""
|
||||
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
package telegram
|
||||
|
||||
import "mtg/conntypes"
|
||||
import "github.com/9seconds/mtg/conntypes"
|
||||
|
||||
const (
|
||||
directV4DefaultIdx conntypes.DC = 1
|
||||
@@ -29,7 +29,8 @@ 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
|
||||
@@ -37,5 +38,5 @@ func (d *directTelegram) Dial(dc conntypes.DC,
|
||||
dc = conntypes.DCDefaultIdx
|
||||
}
|
||||
|
||||
return d.baseTelegram.dial(dc-1, protocol)
|
||||
return d.baseTelegram.dial(dc-1, conntypes.ConnectionProtocolAny)
|
||||
}
|
||||
|
||||
+7
-1
@@ -4,6 +4,8 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const telegramDialTimeout = 10 * time.Second
|
||||
@@ -17,11 +19,14 @@ var (
|
||||
|
||||
func Init() {
|
||||
initOnce.Do(func() {
|
||||
logger := zap.S().Named("telegram")
|
||||
|
||||
Direct = &directTelegram{
|
||||
baseTelegram: baseTelegram{
|
||||
dialer: net.Dialer{Timeout: telegramDialTimeout},
|
||||
logger: logger.Named("direct"),
|
||||
v4DefaultDC: directV4DefaultIdx,
|
||||
V6DefaultDC: directV6DefaultIdx,
|
||||
v6DefaultDC: directV6DefaultIdx,
|
||||
v4Addresses: directV4Addresses,
|
||||
v6Addresses: directV6Addresses,
|
||||
},
|
||||
@@ -30,6 +35,7 @@ func Init() {
|
||||
tg := &middleTelegram{
|
||||
baseTelegram: baseTelegram{
|
||||
dialer: net.Dialer{Timeout: telegramDialTimeout},
|
||||
logger: logger.Named("middle"),
|
||||
},
|
||||
}
|
||||
if err := tg.update(); err != nil {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package telegram
|
||||
|
||||
import "mtg/conntypes"
|
||||
import "github.com/9seconds/mtg/conntypes"
|
||||
|
||||
type Telegram interface {
|
||||
Dial(conntypes.DC, conntypes.ConnectionProtocol) (conntypes.StreamReadWriteCloser, error)
|
||||
|
||||
+5
-5
@@ -5,10 +5,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/telegram/api"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/telegram/api"
|
||||
)
|
||||
|
||||
const middleTelegramBackgroundUpdateEvery = time.Hour
|
||||
@@ -45,7 +44,7 @@ func (m *middleTelegram) update() error {
|
||||
m.mutex.Lock()
|
||||
m.secret = secret
|
||||
m.v4DefaultDC = v4DefaultDC
|
||||
m.V6DefaultDC = v6DefaultDC
|
||||
m.v6DefaultDC = v6DefaultDC
|
||||
m.v4Addresses = v4Addresses
|
||||
m.v6Addresses = v6Addresses
|
||||
m.mutex.Unlock()
|
||||
@@ -64,7 +63,8 @@ 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
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"mtg/config"
|
||||
"mtg/utils"
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
)
|
||||
|
||||
type ClientHello struct {
|
||||
@@ -25,7 +25,7 @@ func (c ClientHello) Digest() []byte {
|
||||
}
|
||||
|
||||
mac := hmac.New(sha256.New, config.C.Secret)
|
||||
mac.Write(rec.Bytes()) // nolint: errcheck
|
||||
rec.WriteBytes(mac)
|
||||
computedDigest := mac.Sum(nil)
|
||||
|
||||
for i := range computedDigest {
|
||||
|
||||
+25
-14
@@ -1,5 +1,7 @@
|
||||
package tlstypes
|
||||
|
||||
import "io"
|
||||
|
||||
type RecordType uint8
|
||||
|
||||
const (
|
||||
@@ -18,20 +20,22 @@ const (
|
||||
type CipherSuiteType uint8
|
||||
|
||||
const (
|
||||
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
|
||||
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
|
||||
)
|
||||
|
||||
func (c CipherSuiteType) Bytes() []byte {
|
||||
switch c {
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes
|
||||
return CipherSuiteType_TLS_CHACHA20_POLY1305_SHA256_Bytes //nolint: nosnakecase
|
||||
}
|
||||
|
||||
type Version uint8
|
||||
@@ -44,6 +48,8 @@ func (v Version) Bytes() []byte {
|
||||
return Version12Bytes
|
||||
case Version11:
|
||||
return Version11Bytes
|
||||
case Version10, VersionUnknown:
|
||||
return Version10Bytes
|
||||
}
|
||||
|
||||
return Version10Bytes
|
||||
@@ -63,17 +69,22 @@ var (
|
||||
Version12Bytes = []byte{0x03, 0x03}
|
||||
Version13Bytes = []byte{0x03, 0x04}
|
||||
|
||||
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
|
||||
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
|
||||
)
|
||||
|
||||
type Byter interface {
|
||||
Bytes() []byte
|
||||
WriteBytes(io.Writer)
|
||||
Len() int
|
||||
}
|
||||
|
||||
type RawBytes []byte
|
||||
|
||||
func (r RawBytes) Bytes() []byte {
|
||||
return []byte(r)
|
||||
func (r RawBytes) WriteBytes(writer io.Writer) {
|
||||
writer.Write(r) //nolint: errcheck
|
||||
}
|
||||
|
||||
func (r RawBytes) Len() int {
|
||||
return len(r)
|
||||
}
|
||||
|
||||
+14
-8
@@ -2,8 +2,9 @@ package tlstypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"mtg/utils"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
)
|
||||
|
||||
type Handshake struct {
|
||||
@@ -14,24 +15,29 @@ type Handshake struct {
|
||||
Tail Byter
|
||||
}
|
||||
|
||||
func (h *Handshake) Bytes() []byte {
|
||||
buf := bytes.Buffer{}
|
||||
func (h *Handshake) WriteBytes(writer io.Writer) {
|
||||
packetBuf := bytes.Buffer{}
|
||||
|
||||
buf.WriteByte(byte(h.Type))
|
||||
writer.Write([]byte{byte(h.Type)}) //nolint: errcheck
|
||||
|
||||
packetBuf.Write(h.Version.Bytes())
|
||||
packetBuf.Write(h.Random[:])
|
||||
packetBuf.WriteByte(byte(len(h.SessionID)))
|
||||
packetBuf.Write(h.SessionID)
|
||||
packetBuf.Write(h.Tail.Bytes())
|
||||
h.Tail.WriteBytes(&packetBuf)
|
||||
|
||||
sizeUint24 := utils.ToUint24(uint32(packetBuf.Len()))
|
||||
sizeUint24Bytes := sizeUint24[:]
|
||||
sizeUint24Bytes[0], sizeUint24Bytes[2] = sizeUint24Bytes[2], sizeUint24Bytes[0]
|
||||
|
||||
buf.Write(sizeUint24Bytes)
|
||||
packetBuf.WriteTo(&buf) // nolint: errcheck
|
||||
writer.Write(sizeUint24Bytes) //nolint: errcheck
|
||||
packetBuf.WriteTo(writer) //nolint: errcheck
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
func (h *Handshake) Len() int {
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
h.WriteBytes(&buf)
|
||||
|
||||
return buf.Len()
|
||||
}
|
||||
|
||||
+12
-11
@@ -15,16 +15,15 @@ type Record struct {
|
||||
Data Byter
|
||||
}
|
||||
|
||||
func (r Record) Bytes() []byte {
|
||||
buf := bytes.Buffer{}
|
||||
data := r.Data.Bytes()
|
||||
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)
|
||||
}
|
||||
|
||||
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 (r Record) Len() int {
|
||||
return 1 + 2 + 2 + r.Data.Len()
|
||||
}
|
||||
|
||||
func ReadRecord(reader io.Reader) (Record, error) {
|
||||
@@ -66,7 +65,9 @@ func ReadRecord(reader io.Reader) (Record, error) {
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
func MakeRecords(raw []byte) (arr []Record) {
|
||||
func MakeRecords(raw []byte) []Record {
|
||||
var arr []Record
|
||||
|
||||
for len(raw) > 0 {
|
||||
chunkSize := recordMaxChunkSize
|
||||
if chunkSize > len(raw) {
|
||||
@@ -81,5 +82,5 @@ func MakeRecords(raw []byte) (arr []Record) {
|
||||
raw = raw[chunkSize:]
|
||||
}
|
||||
|
||||
return
|
||||
return arr
|
||||
}
|
||||
|
||||
+17
-15
@@ -8,9 +8,8 @@ import (
|
||||
"io"
|
||||
mrand "math/rand"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
|
||||
"mtg/config"
|
||||
)
|
||||
|
||||
type ServerHello struct {
|
||||
@@ -20,35 +19,38 @@ type ServerHello struct {
|
||||
}
|
||||
|
||||
func (s ServerHello) WelcomePacket() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
s.Random = [32]byte{}
|
||||
rec := Record{
|
||||
Type: RecordTypeHandshake,
|
||||
Version: Version12,
|
||||
Data: &s,
|
||||
}
|
||||
buf := bytes.NewBuffer(rec.Bytes())
|
||||
rec.WriteBytes(buf)
|
||||
|
||||
recChangeCipher := Record{
|
||||
Type: RecordTypeChangeCipherSpec,
|
||||
Version: Version12,
|
||||
Data: RawBytes([]byte{0x01}),
|
||||
}
|
||||
buf.Write(recChangeCipher.Bytes())
|
||||
recChangeCipher.WriteBytes(buf)
|
||||
|
||||
hostCert := make([]byte, 1024+mrand.Intn(3092))
|
||||
rand.Read(hostCert) // nolint: errcheck
|
||||
hostCert := make([]byte, 1024+mrand.Intn(3092)) //nolint: gosec, gomnd
|
||||
rand.Read(hostCert) //nolint: errcheck
|
||||
|
||||
recData := Record{
|
||||
Type: RecordTypeApplicationData,
|
||||
Version: Version12,
|
||||
Data: RawBytes(hostCert),
|
||||
}
|
||||
buf.Write(recData.Bytes())
|
||||
recData.WriteBytes(buf)
|
||||
|
||||
packet := buf.Bytes()
|
||||
|
||||
mac := hmac.New(sha256.New, config.C.Secret)
|
||||
mac.Write(s.clientHello.Random[:]) // nolint: errcheck
|
||||
mac.Write(packet) // nolint: errcheck
|
||||
mac.Write(s.clientHello.Random[:])
|
||||
mac.Write(packet)
|
||||
copy(packet[11:], mac.Sum(nil))
|
||||
|
||||
return packet
|
||||
@@ -64,8 +66,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)
|
||||
tail.WriteByte(0x00) // no compression
|
||||
tail := bytes.NewBuffer(CipherSuiteType_TLS_AES_128_GCM_SHA256_Bytes) //nolint: nosnakecase
|
||||
tail.WriteByte(0x00) //nolint: gomnd // no compression
|
||||
makeTLSExtensions(tail)
|
||||
rv.Tail = RawBytes(tail.Bytes())
|
||||
|
||||
@@ -73,7 +75,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
|
||||
@@ -83,11 +85,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
|
||||
|
||||
+8
-6
@@ -3,24 +3,26 @@ package utils
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"mtg/config"
|
||||
)
|
||||
|
||||
func InitTCP(conn net.Conn) error {
|
||||
tcpConn := conn.(*net.TCPConn)
|
||||
func InitTCP(conn net.Conn, readBufferSize, writeBufferSize int) error {
|
||||
tcpConn := conn.(*net.TCPConn) //nolint: forcetypeassert
|
||||
|
||||
if err := tcpConn.SetNoDelay(true); err != nil {
|
||||
return fmt.Errorf("cannot set TCP_NO_DELAY: %w", err)
|
||||
}
|
||||
|
||||
if err := tcpConn.SetReadBuffer(config.C.ReadBuffer); err != nil {
|
||||
if err := tcpConn.SetReadBuffer(readBufferSize); err != nil {
|
||||
return fmt.Errorf("cannot set read buffer size: %w", err)
|
||||
}
|
||||
|
||||
if err := tcpConn.SetWriteBuffer(config.C.WriteBuffer); err != nil {
|
||||
if err := tcpConn.SetWriteBuffer(writeBufferSize); err != nil {
|
||||
return fmt.Errorf("cannot set write buffer size: %w", err)
|
||||
}
|
||||
|
||||
if err := tcpConn.SetKeepAlive(true); err != nil {
|
||||
return fmt.Errorf("cannot enable keep-alive: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+4
-3
@@ -4,14 +4,15 @@ import "io"
|
||||
|
||||
const readFullBufferSize = 1024 + 1 // +1 because telegram opreates with blocks mod 4
|
||||
|
||||
func ReadFull(src io.Reader) (rv []byte, err error) {
|
||||
func ReadFull(src io.Reader) ([]byte, 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
|
||||
return nil, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
rv = append(rv, buf[:n]...)
|
||||
|
||||
@@ -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-- {
|
||||
for i := dataLen/2 - 1; i >= 0; i-- { //nolint: gomnd
|
||||
opp := dataLen - i - 1
|
||||
rv[i], rv[opp] = data[opp], data[i]
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// +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,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package utils
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package utils
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package utils
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func MakeStreamCipher(key, iv []byte) cipher.Stream {
|
||||
block, _ := aes.NewCipher(key) // nolint: gosec
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
return cipher.NewCTR(block, iv)
|
||||
}
|
||||
|
||||
+2
-2
@@ -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)}
|
||||
return Uint24{byte(number), byte(number >> 8), byte(number >> 16)} //nolint: gomnd
|
||||
}
|
||||
|
||||
func FromUint24(number Uint24) uint32 {
|
||||
return uint32(number[0]) + (uint32(number[1]) << 8) + (uint32(number[2]) << 16)
|
||||
return uint32(number[0]) + (uint32(number[1]) << 8) + (uint32(number[2]) << 16) //nolint: gomnd
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@ import (
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -29,11 +27,14 @@ 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
|
||||
@@ -41,8 +42,9 @@ type wrapperMtprotoFrame struct {
|
||||
writeSeqNo int32
|
||||
}
|
||||
|
||||
func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funlen
|
||||
func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { //nolint: funlen, cyclop
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
sum := crc32.NewIEEE()
|
||||
writer := io.MultiWriter(buf, sum)
|
||||
|
||||
@@ -50,7 +52,7 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funl
|
||||
buf.Reset()
|
||||
sum.Reset()
|
||||
|
||||
if _, err := io.CopyN(writer, w.parent, 4); err != nil {
|
||||
if _, err := io.CopyN(writer, w.parent, 4); err != nil { //nolint: gomnd
|
||||
return nil, fmt.Errorf("cannot read frame padding: %w", err)
|
||||
}
|
||||
|
||||
@@ -71,25 +73,24 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funl
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
buf.Grow(int(messageLength) - 4 - 4)
|
||||
|
||||
if _, err := io.CopyN(writer, w.parent, int64(messageLength)-4-4); err != nil {
|
||||
if _, err := io.CopyN(writer, w.parent, int64(messageLength)-4-4); err != nil { //nolint: gomnd
|
||||
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, _ := ioutil.ReadAll(buf) // nolint: gosec
|
||||
data, _ := io.ReadAll(buf)
|
||||
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 {
|
||||
if _, err := io.CopyN(buf, w.parent, 4); err != nil { //nolint: gomnd
|
||||
return nil, fmt.Errorf("cannot read checksum: %w", err)
|
||||
}
|
||||
|
||||
@@ -110,19 +111,18 @@ func (w *wrapperMtprotoFrame) Read() (conntypes.Packet, error) { // nolint: funl
|
||||
}
|
||||
|
||||
func (w *wrapperMtprotoFrame) Write(p conntypes.Packet) error {
|
||||
messageLength := 4 + 4 + len(p) + 4
|
||||
messageLength := 4 + 4 + len(p) + 4 //nolint: gomnd
|
||||
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))
|
||||
binary.Write(buf, binary.LittleEndian, checksum) //nolint: errcheck
|
||||
buf.Write(bytes.Repeat(mtprotoFramePadding, paddingLength/4)) //nolint: gomnd
|
||||
|
||||
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
|
||||
return err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperMtprotoFrame) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperMtprotoFrame) Conn() net.Conn {
|
||||
|
||||
@@ -6,10 +6,9 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,9 +39,9 @@ func (w *wrapperClientAbridged) Read(acks *conntypes.ConnectionAcks) (conntypes.
|
||||
}
|
||||
|
||||
if msgLength == clientAbridgedSmallPacketLength {
|
||||
buf.Grow(3)
|
||||
buf.Grow(3) //nolint: gomnd
|
||||
|
||||
if _, err := io.CopyN(&buf, w.parent, 3); err != nil {
|
||||
if _, err := io.CopyN(&buf, w.parent, 3); err != nil { //nolint: gomnd
|
||||
return nil, fmt.Errorf("cannot read correct message length: %w", err)
|
||||
}
|
||||
|
||||
@@ -76,7 +75,7 @@ func (w *wrapperClientAbridged) Write(packet conntypes.Packet, acks *conntypes.C
|
||||
return nil
|
||||
}
|
||||
|
||||
packetLength := len(packet) / 4
|
||||
packetLength := len(packet) / 4 //nolint: gomnd
|
||||
|
||||
switch {
|
||||
case packetLength < clientAbridgedSmallPacketLength:
|
||||
@@ -105,7 +104,7 @@ func (w *wrapperClientAbridged) Write(packet conntypes.Packet, acks *conntypes.C
|
||||
}
|
||||
|
||||
func (w *wrapperClientAbridged) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperClientAbridged) Conn() net.Conn {
|
||||
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
const clientIntermediateQuickAckLength = 0x80000000
|
||||
@@ -21,9 +20,9 @@ type wrapperClientIntermediate struct {
|
||||
func (w *wrapperClientIntermediate) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, error) {
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
buf.Grow(4)
|
||||
buf.Grow(4) //nolint: gomnd
|
||||
|
||||
if _, err := io.CopyN(&buf, w.parent, 4); err != nil {
|
||||
if _, err := io.CopyN(&buf, w.parent, 4); err != nil { //nolint: gomnd
|
||||
return nil, fmt.Errorf("cannot read message length: %w", err)
|
||||
}
|
||||
|
||||
@@ -64,7 +63,7 @@ func (w *wrapperClientIntermediate) Write(packet conntypes.Packet, acks *conntyp
|
||||
}
|
||||
|
||||
func (w *wrapperClientIntermediate) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperClientIntermediate) Conn() net.Conn {
|
||||
|
||||
@@ -6,9 +6,8 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
type wrapperClientIntermediateSecure struct {
|
||||
@@ -21,7 +20,7 @@ func (w *wrapperClientIntermediateSecure) Read(acks *conntypes.ConnectionAcks) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
length := len(data) - (len(data) % 4)
|
||||
length := len(data) - (len(data) % 4) //nolint: gomnd
|
||||
|
||||
return data[:length], nil
|
||||
}
|
||||
@@ -35,11 +34,12 @@ func (w *wrapperClientIntermediateSecure) Write(packet conntypes.Packet, acks *c
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
paddingLength := rand.Intn(4)
|
||||
buf := &bytes.Buffer{}
|
||||
paddingLength := rand.Intn(4) //nolint: gosec, gomnd
|
||||
|
||||
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))
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
"mtg/hub"
|
||||
"mtg/mtproto/rpc"
|
||||
"mtg/protocol"
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/hub"
|
||||
"github.com/9seconds/mtg/mtproto/rpc"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
)
|
||||
|
||||
type wrapperProxy struct {
|
||||
@@ -23,8 +23,8 @@ type wrapperProxy struct {
|
||||
|
||||
func (w *wrapperProxy) Write(packet conntypes.Packet, acks *conntypes.ConnectionAcks) error {
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
flags := w.flags
|
||||
|
||||
if acks.Quick {
|
||||
flags |= rpc.ProxyRequestFlagsQuickAck
|
||||
}
|
||||
@@ -42,10 +42,11 @@ 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))
|
||||
buf.Write(make([]byte, (4-buf.Len()%4)%4)) //nolint: gomnd
|
||||
buf.Grow(len(packet))
|
||||
buf.Write(packet)
|
||||
|
||||
return w.proxy.Write(buf.Bytes())
|
||||
return w.proxy.Write(buf.Bytes()) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperProxy) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, error) {
|
||||
@@ -63,6 +64,7 @@ func (w *wrapperProxy) Read(acks *conntypes.ConnectionAcks) (conntypes.Packet, e
|
||||
|
||||
func (w *wrapperProxy) Close() error {
|
||||
w.proxy.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -76,7 +78,7 @@ func NewProxy(request *protocol.TelegramRequest) (conntypes.PacketAckReadWriteCl
|
||||
flags |= rpc.ProxyRequestFlagsIntermediate
|
||||
case conntypes.ConnectionTypeSecure:
|
||||
flags |= rpc.ProxyRequestFlagsIntermediate | rpc.ProxyRequestFlagsPad
|
||||
default:
|
||||
case conntypes.ConnectionTypeUnknown:
|
||||
panic("unknown connection type")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package rwc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
type wrapperPing struct {
|
||||
parent io.ReadWriteCloser
|
||||
ctx context.Context
|
||||
channelPing chan<- struct{}
|
||||
}
|
||||
|
||||
func (w *wrapperPing) Read(p []byte) (int, error) {
|
||||
n, err := w.parent.Read(p)
|
||||
if err == nil {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
case w.channelPing <- struct{}{}:
|
||||
}
|
||||
}
|
||||
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperPing) Write(p []byte) (int, error) {
|
||||
n, err := w.parent.Write(p)
|
||||
if err == nil {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
case w.channelPing <- struct{}{}:
|
||||
}
|
||||
}
|
||||
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperPing) Close() error {
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func NewPing(ctx context.Context, parent io.ReadWriteCloser, channelPing chan<- struct{}) io.ReadWriteCloser {
|
||||
return &wrapperPing{
|
||||
parent: parent,
|
||||
ctx: ctx,
|
||||
channelPing: channelPing,
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package stream
|
||||
import (
|
||||
"net"
|
||||
|
||||
"mtg/conntypes"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
func NewClientConn(parent net.Conn, connID conntypes.ConnID) conntypes.StreamReadWriteCloser {
|
||||
|
||||
@@ -7,10 +7,9 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/utils"
|
||||
)
|
||||
|
||||
type wrapperBlockCipher struct {
|
||||
@@ -27,7 +26,7 @@ func (w *wrapperBlockCipher) Write(p []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return w.parent.Write(encrypted)
|
||||
return w.parent.Write(encrypted) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperBlockCipher) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
@@ -36,7 +35,7 @@ func (w *wrapperBlockCipher) WriteTimeout(p []byte, timeout time.Duration) (int,
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return w.parent.WriteTimeout(encrypted, timeout)
|
||||
return w.parent.WriteTimeout(encrypted, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperBlockCipher) encrypt(p []byte) ([]byte, error) {
|
||||
@@ -51,7 +50,7 @@ func (w *wrapperBlockCipher) encrypt(p []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (w *wrapperBlockCipher) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperBlockCipher) Conn() net.Conn {
|
||||
@@ -71,7 +70,8 @@ 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,
|
||||
|
||||
@@ -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)
|
||||
return b.buf.Read(p) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
sizeToReturn := b.buf.Len()
|
||||
|
||||
+14
-11
@@ -5,10 +5,9 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/config"
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
type connPurpose uint8
|
||||
@@ -29,6 +28,7 @@ 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,15 +40,16 @@ func (w *wrapperConn) Write(p []byte) (int, error) {
|
||||
w.logger.Debugw("write to stream", "bytes", n, "error", err)
|
||||
|
||||
if err != nil {
|
||||
w.Close() // nolint: gosec
|
||||
w.Close()
|
||||
}
|
||||
|
||||
return n, err
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -63,12 +64,13 @@ func (w *wrapperConn) Read(p []byte) (int, error) {
|
||||
w.Close()
|
||||
}
|
||||
|
||||
return n, err
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperConn) Close() error {
|
||||
w.logger.Debugw("Close connection")
|
||||
return w.parent.Close()
|
||||
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperConn) Conn() net.Conn {
|
||||
@@ -89,10 +91,11 @@ func (w *wrapperConn) RemoteAddr() *net.TCPAddr {
|
||||
|
||||
func newConn(parent net.Conn,
|
||||
connID conntypes.ConnID,
|
||||
purpose connPurpose) conntypes.StreamReadWriteCloser {
|
||||
localAddr := *parent.LocalAddr().(*net.TCPAddr)
|
||||
purpose connPurpose,
|
||||
) conntypes.StreamReadWriteCloser {
|
||||
localAddr := *parent.LocalAddr().(*net.TCPAddr) //nolint: forcetypeassert
|
||||
|
||||
if parent.RemoteAddr().(*net.TCPAddr).IP.To4() != nil {
|
||||
if parent.RemoteAddr().(*net.TCPAddr).IP.To4() != nil { //nolint: forcetypeassert
|
||||
if config.C.PublicIPv4.IP != nil {
|
||||
localAddr.IP = config.C.PublicIPv4.IP
|
||||
}
|
||||
@@ -115,7 +118,7 @@ func newConn(parent net.Conn,
|
||||
parent: parent,
|
||||
connID: connID,
|
||||
logger: logger,
|
||||
remoteAddr: parent.RemoteAddr().(*net.TCPAddr),
|
||||
remoteAddr: parent.RemoteAddr().(*net.TCPAddr), //nolint: forcetypeassert
|
||||
localAddr: &localAddr,
|
||||
}
|
||||
}
|
||||
|
||||
+13
-8
@@ -6,9 +6,8 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
type wrapperCtx struct {
|
||||
@@ -21,9 +20,10 @@ 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)
|
||||
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,10 @@ 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)
|
||||
return w.parent.Write(p) //nolint: wrapcheck
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,9 +42,10 @@ 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)
|
||||
return w.parent.ReadTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,15 +53,17 @@ 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)
|
||||
return w.parent.Read(p) //nolint: wrapcheck
|
||||
}
|
||||
}
|
||||
|
||||
func (w *wrapperCtx) Close() error {
|
||||
w.cancel()
|
||||
return w.parent.Close()
|
||||
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperCtx) Conn() net.Conn {
|
||||
@@ -80,7 +84,8 @@ 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,
|
||||
|
||||
+20
-10
@@ -1,15 +1,15 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/tlstypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/tlstypes"
|
||||
)
|
||||
|
||||
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)
|
||||
return w.parent.Write(b) //nolint: wrapcheck
|
||||
})
|
||||
}
|
||||
|
||||
@@ -30,22 +30,27 @@ 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)
|
||||
return w.parent.WriteTimeout(b, timeout-elapsed) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
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) {
|
||||
_, err := writeFunc(v.Bytes())
|
||||
buf.Reset()
|
||||
v.WriteBytes(&buf)
|
||||
|
||||
_, err := writeFunc(buf.Bytes())
|
||||
if err != nil {
|
||||
return sum, err
|
||||
}
|
||||
|
||||
sum += len(v.Data.Bytes())
|
||||
sum += v.Data.Len()
|
||||
}
|
||||
|
||||
return sum, nil
|
||||
@@ -68,7 +73,7 @@ func (w *wrapperFakeTLS) RemoteAddr() *net.TCPAddr {
|
||||
}
|
||||
|
||||
func (w *wrapperFakeTLS) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func NewFakeTLS(socket conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
|
||||
@@ -80,13 +85,18 @@ func NewFakeTLS(socket conntypes.StreamReadWriteCloser) conntypes.StreamReadWrit
|
||||
for {
|
||||
rec, err := tlstypes.ReadRecord(faketls.parent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
switch rec.Type {
|
||||
case tlstypes.RecordTypeChangeCipherSpec:
|
||||
case tlstypes.RecordTypeApplicationData:
|
||||
return rec.Data.Bytes(), nil
|
||||
buf := &bytes.Buffer{}
|
||||
rec.Data.WriteBytes(buf)
|
||||
|
||||
return buf.Bytes(), nil
|
||||
case tlstypes.RecordTypeHandshake:
|
||||
return nil, errors.New("unsupported record type handshake")
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported record type %v", rec.Type)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5" // nolint: gosec
|
||||
"crypto/sha1" // nolint: gosec
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/mtproto/rpc"
|
||||
"mtg/utils"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/mtproto/rpc"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
)
|
||||
|
||||
type mtprotoCipherPurpose uint8
|
||||
@@ -26,7 +26,8 @@ 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()
|
||||
|
||||
@@ -53,11 +54,13 @@ 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) // nolint: gosec
|
||||
message.Write(req.Nonce) // nolint: gosec
|
||||
message.Write(req.CryptoTS) // nolint: gosec
|
||||
|
||||
message.Write(resp.Nonce)
|
||||
message.Write(req.Nonce)
|
||||
message.Write(req.CryptoTS)
|
||||
|
||||
clientIPv4 := mtprotoEmptyIP[:]
|
||||
serverIPv4 := mtprotoEmptyIP[:]
|
||||
@@ -67,41 +70,41 @@ func mtprotoDeriveKeys(purpose mtprotoCipherPurpose,
|
||||
serverIPv4 = utils.ReverseBytes(remote.IP.To4())
|
||||
}
|
||||
|
||||
message.Write(serverIPv4) // nolint: gosec
|
||||
message.Write(serverIPv4)
|
||||
|
||||
var port [2]byte
|
||||
|
||||
binary.LittleEndian.PutUint16(port[:], uint16(client.Port))
|
||||
message.Write(port[:]) // nolint: gosec
|
||||
message.Write(port[:])
|
||||
|
||||
switch purpose {
|
||||
case mtprotoCipherPurposeClient:
|
||||
message.WriteString("CLIENT") // nolint: gosec
|
||||
message.WriteString("CLIENT")
|
||||
case mtprotoCipherPurposeServer:
|
||||
message.WriteString("SERVER") // nolint: gosec
|
||||
message.WriteString("SERVER")
|
||||
default:
|
||||
panic("Unexpected cipher purpose")
|
||||
}
|
||||
|
||||
message.Write(clientIPv4) // nolint: gosec
|
||||
message.Write(clientIPv4)
|
||||
binary.LittleEndian.PutUint16(port[:], uint16(remote.Port))
|
||||
message.Write(port[:]) // nolint: gosec
|
||||
message.Write(secret) // nolint: gosec
|
||||
message.Write(resp.Nonce) // nolint: gosec
|
||||
message.Write(port[:])
|
||||
message.Write(secret)
|
||||
message.Write(resp.Nonce)
|
||||
|
||||
if client.IP.To4() == nil {
|
||||
message.Write(client.IP.To16()) // nolint: gosec
|
||||
message.Write(remote.IP.To16()) // nolint: gosec
|
||||
message.Write(client.IP.To16())
|
||||
message.Write(remote.IP.To16())
|
||||
}
|
||||
|
||||
message.Write(req.Nonce) // nolint: gosec
|
||||
message.Write(req.Nonce)
|
||||
|
||||
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[:]
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"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
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
w.decryptor.XORKeyStream(p, p[:n])
|
||||
@@ -40,19 +40,27 @@ func (w *wrapperObfuscated2) Read(p []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (w *wrapperObfuscated2) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
buf := make([]byte, len(p))
|
||||
copy(buf, p)
|
||||
buffer := bytes.Buffer{}
|
||||
|
||||
buffer.Write(p)
|
||||
|
||||
buf := buffer.Bytes()
|
||||
|
||||
w.encryptor.XORKeyStream(buf, buf)
|
||||
|
||||
return w.parent.WriteTimeout(buf, timeout)
|
||||
return w.parent.WriteTimeout(buf, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperObfuscated2) Write(p []byte) (int, error) {
|
||||
buf := make([]byte, len(p))
|
||||
copy(buf, p)
|
||||
buffer := bytes.Buffer{}
|
||||
|
||||
buffer.Write(p)
|
||||
|
||||
buf := buffer.Bytes()
|
||||
|
||||
w.encryptor.XORKeyStream(buf, buf)
|
||||
|
||||
return w.parent.Write(buf)
|
||||
return w.parent.Write(buf) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperObfuscated2) Conn() net.Conn {
|
||||
@@ -72,11 +80,12 @@ func (w *wrapperObfuscated2) RemoteAddr() *net.TCPAddr {
|
||||
}
|
||||
|
||||
func (w *wrapperObfuscated2) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func NewObfuscated2(socket conntypes.StreamReadWriteCloser,
|
||||
encryptor, decryptor cipher.Stream) conntypes.StreamReadWriteCloser {
|
||||
encryptor, decryptor cipher.Stream,
|
||||
) conntypes.StreamReadWriteCloser {
|
||||
return &wrapperObfuscated2{
|
||||
parent: socket,
|
||||
encryptor: encryptor,
|
||||
|
||||
+17
-38
@@ -7,9 +7,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
type ReadWriteCloseRewinder interface {
|
||||
@@ -18,56 +17,32 @@ type ReadWriteCloseRewinder interface {
|
||||
}
|
||||
|
||||
type wrapperRewind struct {
|
||||
parent conntypes.StreamReadWriteCloser
|
||||
buf bytes.Buffer
|
||||
mutex sync.Mutex
|
||||
rewinded bool
|
||||
parent conntypes.StreamReadWriteCloser
|
||||
activeReader io.Reader
|
||||
buf bytes.Buffer
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (w *wrapperRewind) Write(p []byte) (int, error) {
|
||||
return w.parent.Write(p)
|
||||
return w.parent.Write(p) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperRewind) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
return w.parent.WriteTimeout(p, timeout)
|
||||
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperRewind) Read(p []byte) (int, error) {
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
|
||||
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
|
||||
return w.activeReader.Read(p) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperRewind) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
func (w *wrapperRewind) ReadTimeout(p []byte, _ time.Duration) (int, error) {
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
|
||||
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
|
||||
return w.activeReader.Read(p) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperRewind) Conn() net.Conn {
|
||||
@@ -88,17 +63,21 @@ func (w *wrapperRewind) RemoteAddr() *net.TCPAddr {
|
||||
|
||||
func (w *wrapperRewind) Close() error {
|
||||
w.buf.Reset()
|
||||
return w.parent.Close()
|
||||
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperRewind) Rewind() {
|
||||
w.mutex.Lock()
|
||||
w.rewinded = true
|
||||
w.activeReader = io.MultiReader(&w.buf, w.parent)
|
||||
w.mutex.Unlock()
|
||||
}
|
||||
|
||||
func NewRewind(parent conntypes.StreamReadWriteCloser) ReadWriteCloseRewinder {
|
||||
return &wrapperRewind{
|
||||
rv := &wrapperRewind{
|
||||
parent: parent,
|
||||
}
|
||||
rv.activeReader = io.TeeReader(parent, &rv.buf)
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/stats"
|
||||
)
|
||||
|
||||
type wrapperTelegramStats struct {
|
||||
@@ -18,19 +17,19 @@ type wrapperTelegramStats struct {
|
||||
}
|
||||
|
||||
func (w *wrapperTelegramStats) Write(p []byte) (int, error) {
|
||||
return w.parent.Write(p)
|
||||
return w.parent.Write(p) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTelegramStats) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
return w.parent.WriteTimeout(p, timeout)
|
||||
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTelegramStats) Read(p []byte) (int, error) {
|
||||
return w.parent.Read(p)
|
||||
return w.parent.Read(p) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTelegramStats) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
return w.parent.ReadTimeout(p, timeout)
|
||||
return w.parent.ReadTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTelegramStats) Conn() net.Conn {
|
||||
@@ -57,7 +56,7 @@ func (w *wrapperTelegramStats) Close() error {
|
||||
stats.Stats.TelegramDisconnected(w.dc, w.RemoteAddr())
|
||||
})
|
||||
|
||||
return err
|
||||
return err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func NewTelegramStats(dc conntypes.DC, parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
|
||||
|
||||
@@ -4,10 +4,9 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
"mtg/stats"
|
||||
)
|
||||
|
||||
type wrapperTrafficStats struct {
|
||||
@@ -18,28 +17,28 @@ func (w *wrapperTrafficStats) Write(p []byte) (int, error) {
|
||||
n, err := w.parent.Write(p)
|
||||
stats.Stats.EgressTraffic(n)
|
||||
|
||||
return n, err
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
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
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTrafficStats) Read(p []byte) (int, error) {
|
||||
n, err := w.parent.Read(p)
|
||||
stats.Stats.IngressTraffic(n)
|
||||
|
||||
return n, err
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
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
|
||||
return n, err //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTrafficStats) Conn() net.Conn {
|
||||
@@ -59,7 +58,7 @@ func (w *wrapperTrafficStats) RemoteAddr() *net.TCPAddr {
|
||||
}
|
||||
|
||||
func (w *wrapperTrafficStats) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func NewTrafficStats(parent conntypes.StreamReadWriteCloser) conntypes.StreamReadWriteCloser {
|
||||
|
||||
@@ -4,9 +4,8 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"mtg/conntypes"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -19,23 +18,23 @@ type wrapperTimeout struct {
|
||||
}
|
||||
|
||||
func (w *wrapperTimeout) WriteTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
return w.parent.WriteTimeout(p, timeout)
|
||||
return w.parent.WriteTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTimeout) Write(p []byte) (int, error) {
|
||||
return w.parent.WriteTimeout(p, timeoutWrite)
|
||||
return w.parent.WriteTimeout(p, timeoutWrite) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTimeout) ReadTimeout(p []byte, timeout time.Duration) (int, error) {
|
||||
return w.parent.ReadTimeout(p, timeout)
|
||||
return w.parent.ReadTimeout(p, timeout) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTimeout) Read(p []byte) (int, error) {
|
||||
return w.parent.ReadTimeout(p, timeoutRead)
|
||||
return w.parent.ReadTimeout(p, timeoutRead) //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTimeout) Close() error {
|
||||
return w.parent.Close()
|
||||
return w.parent.Close() //nolint: wrapcheck
|
||||
}
|
||||
|
||||
func (w *wrapperTimeout) Conn() net.Conn {
|
||||
|
||||
Reference in New Issue
Block a user