REPOSITORY / ScuroNeko/mtg

Compare commits

DIFF REPOSITORY

Compare commits

..
72 Commits
Author SHA1 Message Date
9seconds b854b16e1a Merge branch 'stable' into v2 2026-02-19 14:37:52 +01:00
9seconds f4b296d1e0 Merge branch 'master' into stable 2026-02-19 14:37:36 +01:00
Sergei ArkhipovandGitHub 432e530f68 Adjust formatting in readme 2026-02-19 14:35:04 +01:00
Sergei ArkhipovandGitHub a2bf9a269a Merge pull request #333 from 9seconds/proxyproto
Add support of proxy protocol
2026-02-19 14:27:43 +01:00
9seconds cf3437bb63 Add support of proxy protocol 2026-02-19 14:22:00 +01:00
Sergei ArkhipovandGitHub d0e99dda2b Update README.md 2026-02-18 11:16:04 +01:00
Sergei ArkhipovandGitHub ac3bd16e83 Merge pull request #332 from 9seconds/telemt-recommend
Recommend to use telemt for adtag carvings
2026-02-18 11:14:22 +01:00
9seconds 222cef8c41 Recommend to use telemt for adtag carvings 2026-02-18 11:13:55 +01:00
Sergei ArkhipovandGitHub ed5da2864a Merge pull request #331 from 9seconds/go1.26
Chore updates for golang 1.26
2026-02-18 11:04:23 +01:00
9seconds 08393e426a Update mise dependencies 2026-02-18 10:37:41 +01:00
9seconds 0440ccf4ff Rewrite to WaitGroup.Go 2026-02-18 10:34:31 +01:00
9seconds a0aabf2391 Switch to rand/v2 2026-02-18 10:34:31 +01:00
9seconds 3b03c4a90a More idioms related to go 1.26 2026-02-17 23:38:12 +01:00
Sergei ArkhipovandGitHub 80b9159ce9 Merge pull request #330 from 9seconds/telemt
Mention telemt project in README
2026-02-17 22:19:50 +01:00
Sergei ArkhipovandGitHub bdabb0e59a Merge pull request #329 from 9seconds/tools
Tell about mise in readme
2026-02-17 22:19:32 +01:00
9seconds 543f5cde9c Mention telemt project in README 2026-02-17 21:46:15 +01:00
9seconds 1a247d18b1 Tell about mise in README 2026-02-17 21:43:16 +01:00
9seconds 5a63c7d5b4 Lock all mise dependencies 2026-02-17 21:39:12 +01:00
9seconds e7fdb02a29 Merge branch 'v2' into stable 2026-02-16 19:23:45 +01:00
9seconds 7a6ba6d8c6 Merge branch 'master' into v2 2026-02-16 19:23:28 +01:00
9seconds be398f9c79 Use mise lock 2026-02-16 19:22:37 +01:00
9seconds 4c029fc683 Use gofumpt from github 2026-02-16 19:22:37 +01:00
9seconds 3066672353 Add permissions for Docker job to write into packages 2026-02-16 18:01:27 +00:00
9seconds ae88c0cab0 More tags for relevant branches 2026-02-16 17:17:52 +00:00
9seconds 816b7f72b6 Change secret to Github token 2026-02-16 17:17:47 +00:00
Sergei ArkhipovandGitHub 1f7584c108 Merge pull request #326 from 9seconds/dc203
Correctly connect to DC203/CDN
2026-02-16 18:01:26 +01:00
Sergei ArkhipovandGitHub 2fb025bbfd Merge pull request #327 from 9seconds/workflow
Correctly build and push images into registry
2026-02-16 18:01:09 +01:00
Sergey Arkhipov c7ab53134a Correctly build and push images into registry 2026-02-16 16:39:29 +00:00
9seconds f83ee17361 Fix test 2026-02-16 17:30:11 +01:00
9seconds 36546cec2f Change default DOH to cloudflarte 2026-02-16 17:18:31 +01:00
9seconds 074c4017f5 Formatting by gofumpt 2026-02-16 17:10:06 +01:00
9seconds 8e87405d3e Remove integration with gotd 2026-02-16 16:30:10 +01:00
9seconds 82679ec20f Update config 2026-02-16 15:22:03 +01:00
9seconds 308e372a5d Propagate DcUpdateEach setting 2026-02-16 15:07:56 +01:00
9seconds 836a481026 Propagate DCOverrides 2026-02-16 14:58:41 +01:00
9seconds 0a5a45b32d Create internal DC package 2026-02-16 14:15:38 +01:00
9seconds 852ca713c8 Fetch DC ips from Telegram 2026-02-15 23:56:53 +01:00
9seconds 301bde88ac Add gopls to mise 2026-02-11 15:09:43 +01:00
9seconds 25bca76da5 Merge remote-tracking branch 'origin/stable' into v2 2026-02-11 14:26:31 +01:00
9seconds 76109f6204 Merge remote-tracking branch 'origin/master' into stable 2026-02-11 14:25:54 +01:00
9seconds 6db6415798 Enable tests back 2026-02-11 14:25:00 +01:00
9seconds 0faf482e52 Update dockerfile 2026-02-11 13:55:11 +01:00
9seconds 3e4faf6ba6 Test docker 2026-02-11 12:13:55 +01:00
9seconds f7f6a7637c Update for tag semver 2026-02-11 12:09:57 +01:00
9seconds 130b02013b More CI updates 2026-02-11 12:07:45 +01:00
9seconds 1b4c777ed3 Use mise for fuzzing 2026-02-11 11:58:30 +01:00
9seconds 60b4b5ad8f Fix lint issues 2026-02-11 11:54:47 +01:00
9seconds a4930a596a Update linter job 2026-02-11 11:49:51 +01:00
9seconds fb3e921bc6 Update linter job 2026-02-11 11:48:09 +01:00
9seconds afbf4f6f74 Disable push to docker hub 2026-02-11 11:44:59 +01:00
9seconds 592b7c5b87 Update setup-go actions 2026-02-11 11:44:52 +01:00
9seconds c170887499 Update checkouts 2026-02-11 11:44:44 +01:00
9seconds ad76304b43 Correct argument for coverage 2026-02-11 11:43:01 +01:00
9seconds 5e38819506 Update codecov action 2026-02-11 11:42:01 +01:00
9seconds f06fd5ca77 Update CI 2026-02-11 11:21:27 +01:00
9seconds ad88afeecd Remove makefile 2026-02-11 11:13:36 +01:00
9seconds c74c0c92c6 Update CI 2026-02-11 11:13:25 +01:00
9seconds e3dc03b4db Update dependencies 2026-02-11 10:46:07 +01:00
9seconds ecba88d2e3 Update to the latest golangci-lint 2026-02-11 10:20:04 +01:00
9seconds 37de052feb Disable failing real request test for a while 2026-02-11 10:02:39 +01:00
9seconds 2041f3154b Add tests into mise 2026-02-11 09:58:26 +01:00
9seconds b1728c3474 Add task for building image 2026-02-11 09:47:11 +01:00
9seconds b72af2b953 Add task for formatting source code 2026-02-11 09:45:40 +01:00
9seconds 75c317f35e Add task for static build 2026-02-11 09:45:40 +01:00
9seconds 795dabb80b Add docs task 2026-02-11 09:38:36 +01:00
9seconds 01b0166995 Add release mise task 2026-02-11 09:38:36 +01:00
9seconds e9a147c836 Add build task 2026-02-11 09:26:46 +01:00
9seconds de66835657 Update goreleaser 2026-02-11 08:59:17 +01:00
9seconds 75f11965d8 Switch to mise 2026-02-11 08:52:45 +01:00
Sergey ArkhipovandGitHub e68d0c7da5 Merge pull request #289 from arashnm80/arashnm80-fix-docker-command
edit docker command in README.md
2022-11-21 17:53:10 +01:00
Arash Nemat ZadehandGitHub 051180a170 edit docker command in README.md
added the missing slash mentioned in issue #287
2022-11-17 03:42:09 +03:30
9seconds b4e0143cb7 Merge remote-tracking branch 'origin/stable' 2022-08-09 17:57:09 +03:00
90 changed files with 1110 additions and 1423 deletions
+41 -62
View File
@@ -39,35 +39,22 @@ jobs:
name: Test name: Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 10 timeout-minutes: 10
strategy:
matrix:
go_version:
- ^1.19
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- name: Setup Go - uses: jdx/mise-action@v3
uses: actions/setup-go@v2 name: Install mise
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 - name: Run tests
run: go test -coverprofile=./coverage.txt -covermode=atomic -v ./... run: mise tasks run covtest
- name: Collect coverage - name: Collect coverage
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v5
with: with:
file: ./coverage.txt files: ./coverage.txt
fuzz: fuzz:
name: Fuzzing name: Fuzzing
@@ -75,31 +62,16 @@ jobs:
timeout-minutes: 20 timeout-minutes: 20
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- name: Setup Go - uses: jdx/mise-action@v3
uses: actions/setup-go@v2 name: Install mise
with:
go-version: ^1.18
- name: Cache fuzz results
uses: actions/cache@v2
with:
path: ~/.cache/go-build/fuzz
key: ${{ runner.os }}-go-${{ hashFiles('**/*_fuzz_test.go', '**/*_fuzz_internal_test.go') }}
restore-keys: ${{ runner.os }}-go-
- 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 fuzzing - name: Run fuzzing
run: make -j4 fuzz run: mise tasks run 'test:fuzz:*'
lint: lint:
name: Lint name: Lint
@@ -107,45 +79,52 @@ jobs:
timeout-minutes: 5 timeout-minutes: 5
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- name: Setup Go - uses: jdx/mise-action@v3
uses: actions/setup-go@v2 name: Install mise
with:
go-version: ^1.19
- name: Run linter - name: Run linter
uses: golangci/golangci-lint-action@v3 run: mise tasks run lint
with:
version: v1.48.0
docker: docker:
name: Docker name: Docker
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20 timeout-minutes: 20
permissions:
contents: read
packages: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- name: Get Docker meta - name: Get Docker meta
id: docker_meta id: meta
uses: crazy-max/ghaction-docker-meta@v1 uses: docker/metadata-action@v5
with: with:
images: nineseconds/mtg,ghcr.io/9seconds/mtg images: |
tag-semver: "{{version}},{{major}},{{major}}.{{minor}}" nineseconds/mtg
ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=master,enable=${{ github.ref == 'refs/heads/master' }}
type=raw,value=stable,enable=${{ github.ref == 'refs/heads/stable' }}
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v3
- name: Setup BuildX - name: Setup BuildX
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v3
- name: Setup cache - name: Setup cache
uses: actions/cache@v2 uses: actions/cache@v5
with: with:
path: /tmp/buildx-cache path: /tmp/buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }} key: ${{ runner.os }}-buildx-${{ github.sha }}
@@ -154,18 +133,18 @@ jobs:
- name: Login to DockerHub - name: Login to DockerHub
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v1 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }} password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GHCR.io - name: Login to GitHub Container Registry
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v1 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.actor }}
password: ${{ secrets.GH_PAT }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
@@ -174,7 +153,7 @@ jobs:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7,linux/arm/v6 platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7,linux/arm/v6
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker_meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/buildx-cache cache-from: type=local,src=/tmp/buildx-cache
cache-to: type=local,dest=/tmp/buildx-cache cache-to: type=local,dest=/tmp/buildx-cache
-3
View File
@@ -6,8 +6,5 @@
*.test *.test
*.out *.out
mtg mtg
vendor/
ccbuilds/
.bin/
coverage.txt coverage.txt
dist/ dist/
+17 -18
View File
@@ -1,22 +1,21 @@
# https://golangci-lint.run/docs/configuration/file/
version = '2'
[run] [run]
concurrency = 4 concurrency = 4
deadline = "2m"
tests = true tests = true
skip-dirs = ["vendor"]
[output] # [linters]
format = "colored-line-number" # enable-all = true
# disable = [
[linters] # "containedctx",
enable-all = true # "exhaustivestruct",
disable = [ # "exhaustruct",
"containedctx", # "gas",
"exhaustivestruct", # "gochecknoglobals",
"exhaustruct", # "goerr113",
"gas", # "ireturn",
"gochecknoglobals", # "thelper",
"goerr113", # "varnamelen",
"ireturn", # ]
"thelper",
"varnamelen",
]
+7 -3
View File
@@ -1,5 +1,7 @@
--- ---
version: 2
project_name: mtg project_name: mtg
before: before:
@@ -41,11 +43,13 @@ builds:
archives: archives:
- name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' - name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
format: tar.gz formats:
- tar.gz
wrap_in_directory: true wrap_in_directory: true
format_overrides: format_overrides:
- goos: windows - goos: windows
format: zip formats:
- zip
files: files:
- LICENSE - LICENSE
- README.md - README.md
@@ -55,7 +59,7 @@ gomod:
proxy: true proxy: true
snapshot: snapshot:
name_template: '{{ .Version }}' version_template: '{{ .Version }}'
checksum: checksum:
name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt' name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'
+101
View File
@@ -0,0 +1,101 @@
[tools]
"go:golang.org/x/pkgsite/cmd/pkgsite" = "latest"
"go:golang.org/x/tools/gopls" = "latest"
"go:mvdan.cc/gofumpt" = "latest"
go = "latest"
golangci-lint = "latest"
goreleaser = "latest"
[vars]
fuzzflags = "-fuzztime=120s"
[tasks.build]
description = "Build binary"
sources = ["**/*.go", "go.mod", "go.sum"]
outputs = ["mtg"]
run = "go build"
[tasks.update]
description = "Update dependencies"
run = [
"go get -u",
"go mod tidy -go=1.25"
]
[tasks.lint]
description = "Run linter"
run = "golangci-lint run"
[tasks.test]
description = "Run tests"
run = "go test -v ./..."
[tasks.covtest]
description = "Run tests with code coverage"
run = "go test -coverprofile=coverage.txt -covermode=atomic -parallel 2 -race -v ./..."
[tasks.test-all]
description = "Run all tests"
depends = [
"test",
"test:fuzz:*"
]
[tasks."test:fuzz:client-hello"]
description = "Run fuzzy test for ClientHello"
run = "go test -v {{ vars.fuzzflags }} -fuzz=FuzzClientHello ./mtglib/internal/faketls"
[tasks."test:fuzz:client-handshake"]
description = "Run fuzzy test for ClientHandshake"
run = "go test -v {{ vars.fuzzflags }} -fuzz=FuzzClientHandshake ./mtglib/internal/obfuscated2"
[tasks."test:fuzz:server-generate-handshake-frame"]
description = "Run fuzzy test for ServerGenerateHandshakeFrame"
run = "go test -v {{ vars.fuzzflags }} -fuzz=FuzzServerGenerateHandshakeFrame ./mtglib/internal/obfuscated2"
[tasks."test:fuzz:server-receive"]
description = "Run fuzzy test for ServerReceive"
run = "go test -v {{ vars.fuzzflags }} -fuzz=FuzzServerReceive ./mtglib/internal/obfuscated2"
[tasks."test:fuzz:server-send"]
description = "Run fuzzy test for ServerSend"
run = "go test -v {{ vars.fuzzflags }} -fuzz=FuzzServerSend ./mtglib/internal/obfuscated2"
[tasks.static]
description = "Build static binary"
sources = ["**/*.go", "go.mod", "go.sum"]
outputs = ["mtg"]
run = """
#!/bin/bash
version="$(git describe --exact-match HEAD 2>/dev/null || git describe --tags --always)"
go build \
-trimpath \
-mod=readonly \
-ldflags="-extldflags '-static' -s -w -X 'main.version=$version'" \
-a \
-tags netgo
"""
[tasks.release]
description = "Create release tarballs"
sources = ["**/*.go", "go.mod", "go.sum", ".goreleaser.yml"]
run = [
"goreleaser --snapshot --clean",
"find dist -depth 1 -type d | xargs -r rm -r",
"rm ./dist/config.yaml"
]
[tasks.image]
description = "Build docker image"
sources = ["**/*.go", "go.mod", "go.sum", "Dockerfile"]
run = "docker buildx build --pull -t mtg ."
[tasks.docs]
description = "Run doc server"
run = "pkgsite -http 0.0.0.0:10000"
[tasks.fmt]
description = "Reformat source code"
sources = ["**/*.go"]
run = "gofumpt -w --extra ."
+11 -5
View File
@@ -1,21 +1,27 @@
############################################################################### ###############################################################################
# BUILD STAGE # BUILD STAGE
FROM golang:1.19-alpine AS build FROM golang:1.26-alpine AS build
ENV CGO_ENABLED=0
RUN set -x \ RUN set -x \
&& apk --no-cache --update add \ && apk --no-cache --update add \
bash \ bash \
ca-certificates \ ca-certificates \
curl \ git
git \
make
COPY . /app COPY . /app
WORKDIR /app WORKDIR /app
RUN set -x \ RUN set -x \
&& make -j 4 static && version="$(git describe --exact-match HEAD 2>/dev/null || git describe --tags --always)" \
&& go build \
-trimpath \
-mod=readonly \
-ldflags="-extldflags '-static' -s -w -X 'main.version=$version'" \
-a \
-tags netgo
############################################################################### ###############################################################################
-121
View File
@@ -1,121 +0,0 @@
ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
IMAGE_NAME := mtg
APP_NAME := $(IMAGE_NAME)
GOLANGCI_LINT_VERSION := v1.48.0
VERSION := $(shell git describe --exact-match HEAD 2>/dev/null || git describe --tags --always)
COMMON_BUILD_FLAGS := -trimpath -mod=readonly -ldflags="-extldflags '-static' -s -w -X 'main.version=$(VERSION)'"
FUZZ_FLAGS := -fuzztime=120s
GOBIN := $(ROOT_DIR)/.bin
GOTOOL := env "GOBIN=$(GOBIN)" "PATH=$(ROOT_DIR)/.bin:$(PATH)"
# -----------------------------------------------------------------------------
.PHONY: all
all: build
.PHONY: build
build:
@go build $(COMMON_BUILD_FLAGS) -o "$(APP_NAME)"
$(APP_NAME): build
.PHONY: static
static:
@env CGO_ENABLED=0 GOOS=linux go build \
$(COMMON_BUILD_FLAGS) \
-tags netgo \
-a \
-o "$(APP_NAME)"
vendor: go.mod go.sum
@$(MOD_ON) go mod vendor
.bin:
@mkdir -p "$(GOBIN)" || true
.PHONY: fmt
fmt:
@$(GOTOOL) gofumpt -w -extra "$(ROOT_DIR)"
.PHONY: test
test:
@go test -v ./...
.PHONY: citest
citest:
@go test -coverprofile=coverage.txt -covermode=atomic -parallel 2 -race -v ./...
.PHONY: clean
clean:
@git clean -xfd && \
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: 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: docker
docker:
@docker build --pull -t "$(IMAGE_NAME)" "$(ROOT_DIR)"
.PHONY: doc
doc:
@$(GOTOOL) godoc -http 0.0.0.0:10000
.PHONY: install-tools
install-tools: install-tools-lint install-tools-godoc install-tools-gofumpt install-tools-goreleaser
.PHONY: install-tools-lint
install-tools-lint: .bin
@curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \
| bash -s -- -b "$(GOBIN)" "$(GOLANGCI_LINT_VERSION)"
.PHONY: install-tools-godoc
install-tools-godoc: .bin
@$(GOTOOL) go install golang.org/x/tools/cmd/godoc@latest
.PHONY: install-tools-gofumpt
install-tools-gofumpt: .bin
@$(GOTOOL) go install mvdan.cc/gofumpt@latest
.PHONY: goreleaser
install-tools-goreleaser: .bin
@$(GOTOOL) go install github.com/goreleaser/goreleaser@latest
.PHONY: update-deps
update-deps:
@go get -u && go mod tidy -go=1.18
.PHONY: fuzz
fuzz: fuzz-ClientHello fuzz-ServerGenerateHandshakeFrame fuzz-ClientHandshake fuzz-ServerReceive fuzz-ServerSend
.PHONY: fuzz-ClientHello
fuzz-ClientHello:
@go test -fuzz=FuzzClientHello $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/faketls"
.PHONY: fuzz-ServerGenerateHandshakeFrame
fuzz-ServerGenerateHandshakeFrame:
@go test -fuzz=FuzzServerGenerateHandshakeFrame $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
.PHONY: fuzz-ClientHandshake
fuzz-ClientHandshake:
@go test -fuzz=FuzzClientHandshake $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
.PHONY: fuzz-ServerReceive
fuzz-ServerReceive:
@go test -fuzz=FuzzServerReceive $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
.PHONY: fuzz-ServerSend
fuzz-ServerSend:
@go test -fuzz=FuzzServerSend $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
+29 -4
View File
@@ -10,6 +10,17 @@ Highly-opinionated (ex-bullshit-free) MTPROTO proxy for
**If you use v1.0 or upgrade broke you proxy, please read the chapter **If you use v1.0 or upgrade broke you proxy, please read the chapter
[Version 2](#version-2)** [Version 2](#version-2)**
If you want to have a proxy that _supports adtag_ (possibility to promote a
channel with a special Telegram bot), I recommend to use
[telemt](https://github.com/telemt/telemt) project. v1 of mtg supports it
but I do not see any reasonable point of using it: adtag requires communication
via a fragile set of middle proxies, requires complex setup that must expose
a public IPs, has lower bandwidth and latency.
mtg idea is simple: minimal unbloated proxy that can handle a reasonable scale
~10-20k simultaneous connections, has no user management, but ticks all
checkboxes related to its main intent: provide a way to use Telegram.
## Rationale ## Rationale
There are several available proxies for Telegram MTPROTO available. Here There are several available proxies for Telegram MTPROTO available. Here
@@ -18,6 +29,7 @@ are the most notable:
* [Official](https://github.com/TelegramMessenger/MTProxy) * [Official](https://github.com/TelegramMessenger/MTProxy)
* [Python](https://github.com/alexbers/mtprotoproxy) * [Python](https://github.com/alexbers/mtprotoproxy)
* [Erlang](https://github.com/seriyps/mtproto_proxy) * [Erlang](https://github.com/seriyps/mtproto_proxy)
* [Telemt (Rust)](https://github.com/telemt/telemt)
You can use any of these. They work great and all implementations have You can use any of these. They work great and all implementations have
feature parity now. This includes support of adtag, replay attack feature parity now. This includes support of adtag, replay attack
@@ -40,6 +52,12 @@ that probably matter.
way of doing business I suppose. I think the only viable way is to way of doing business I suppose. I think the only viable way is to
have a proxy that can be restored anywhere easily. have a proxy that can be restored anywhere easily.
* **Supports proxy protocol v1/v2**
This makes integration with loadbalancers like HAProxy and ELB a first class
citizen by supporting their
[commuication protocols](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt).
* **A single secret** * **A single secret**
I think that multiple secrets solve no problems and just complex I think that multiple secrets solve no problems and just complex
@@ -162,6 +180,12 @@ This project has several main branches
## Getting started ## Getting started
### Download mise
mtg uses [mise](https://mise.jdx.dev/) to maintain its development
dependencies + replaces a make for building things. Please
[install](https://mise.jdx.dev/getting-started.html) it first.
### Download a tool ### Download a tool
#### Download binaries #### Download binaries
@@ -198,13 +222,14 @@ go install github.com/9seconds/mtg/v2@latest
```console ```console
git clone https://github.com/9seconds/mtg.git git clone https://github.com/9seconds/mtg.git
cd mtg cd mtg
make static mise install
mise tasks run build
``` ```
or for the docker image: or for the docker image:
```console ```console
make docker mise tasks run image
``` ```
### Generate secret ### Generate secret
@@ -275,7 +300,7 @@ Flags:
-b, --tcp-buffer="4KB" Size of TCP buffer to use. -b, --tcp-buffer="4KB" Size of TCP buffer to use.
-i, --prefer-ip="prefer-ipv6" IP preference. By default we prefer IPv6 with fallback to IPv4. -i, --prefer-ip="prefer-ipv6" IP preference. By default we prefer IPv6 with fallback to IPv4.
-p, --domain-fronting-port=443 A port to access for domain fronting. -p, --domain-fronting-port=443 A port to access for domain fronting.
-n, --doh-ip=9.9.9.9 IP address of DNS-over-HTTP to use. -n, --doh-ip=1.1.1.1 IP address of DNS-over-HTTP to use.
-t, --timeout=10s Network timeout to use -t, --timeout=10s Network timeout to use
-a, --antireplay-cache-size="1MB" A size of anti-replay cache to use. -a, --antireplay-cache-size="1MB" A size of anti-replay cache to use.
``` ```
@@ -338,7 +363,7 @@ $ sudo systemctl start mtg
or you can run a docker image or you can run a docker image
```console ```console
docker run -d -v $PWD/config.toml:config.toml -p 443:3128 --name mtg-proxy --restart=unless-stopped nineseconds/mtg:2 docker run -d -v $PWD/config.toml:/config.toml -p 443:3128 --name mtg-proxy --restart=unless-stopped nineseconds/mtg:2
``` ```
where _443_ is a host port (a port you want to connect to from a where _443_ is a host port (a port you want to connect to from a
+1 -1
View File
@@ -42,7 +42,7 @@ func NewStableBloomFilter(byteSize uint, errorRate float64) mtglib.AntiReplayCac
errorRate = DefaultStableBloomFilterErrorRate errorRate = DefaultStableBloomFilterErrorRate
} }
sf := boom.NewDefaultStableBloomFilter(byteSize*8, errorRate) //nolint: gomnd sf := boom.NewDefaultStableBloomFilter(byteSize*8, errorRate)
sf.SetHash(xxhash.New64()) sf.SetHash(xxhash.New64())
return &stableBloomFilter{ return &stableBloomFilter{
+2 -2
View File
@@ -2,7 +2,7 @@ package events
import ( import (
"context" "context"
"math/rand" "math/rand/v2"
"runtime" "runtime"
"github.com/9seconds/mtg/v2/mtglib" "github.com/9seconds/mtg/v2/mtglib"
@@ -64,7 +64,7 @@ func NewEventStream(observerFactories []ObserverFactory) EventStream {
chans: make([]chan mtglib.Event, runtime.NumCPU()), chans: make([]chan mtglib.Event, runtime.NumCPU()),
} }
for i := 0; i < runtime.NumCPU(); i++ { for i := range runtime.NumCPU() {
rv.chans[i] = make(chan mtglib.Event, 1) rv.chans[i] = make(chan mtglib.Event, 1)
if len(observerFactories) == 1 { if len(observerFactories) == 1 {
+27 -54
View File
@@ -12,14 +12,11 @@ type multiObserver struct {
func (m multiObserver) EventStart(evt mtglib.EventStart) { func (m multiObserver) EventStart(evt mtglib.EventStart) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventStart(evt)
})
obs.EventStart(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -27,14 +24,11 @@ func (m multiObserver) EventStart(evt mtglib.EventStart) {
func (m multiObserver) EventConnectedToDC(evt mtglib.EventConnectedToDC) { func (m multiObserver) EventConnectedToDC(evt mtglib.EventConnectedToDC) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventConnectedToDC(evt)
})
obs.EventConnectedToDC(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -42,14 +36,11 @@ func (m multiObserver) EventConnectedToDC(evt mtglib.EventConnectedToDC) {
func (m multiObserver) EventDomainFronting(evt mtglib.EventDomainFronting) { func (m multiObserver) EventDomainFronting(evt mtglib.EventDomainFronting) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventDomainFronting(evt)
})
obs.EventDomainFronting(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -57,14 +48,11 @@ func (m multiObserver) EventDomainFronting(evt mtglib.EventDomainFronting) {
func (m multiObserver) EventTraffic(evt mtglib.EventTraffic) { func (m multiObserver) EventTraffic(evt mtglib.EventTraffic) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventTraffic(evt)
})
obs.EventTraffic(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -72,14 +60,11 @@ func (m multiObserver) EventTraffic(evt mtglib.EventTraffic) {
func (m multiObserver) EventFinish(evt mtglib.EventFinish) { func (m multiObserver) EventFinish(evt mtglib.EventFinish) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventFinish(evt)
})
obs.EventFinish(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -87,14 +72,11 @@ func (m multiObserver) EventFinish(evt mtglib.EventFinish) {
func (m multiObserver) EventConcurrencyLimited(evt mtglib.EventConcurrencyLimited) { func (m multiObserver) EventConcurrencyLimited(evt mtglib.EventConcurrencyLimited) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventConcurrencyLimited(evt)
})
obs.EventConcurrencyLimited(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -102,14 +84,11 @@ func (m multiObserver) EventConcurrencyLimited(evt mtglib.EventConcurrencyLimite
func (m multiObserver) EventIPBlocklisted(evt mtglib.EventIPBlocklisted) { func (m multiObserver) EventIPBlocklisted(evt mtglib.EventIPBlocklisted) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventIPBlocklisted(evt)
})
obs.EventIPBlocklisted(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -117,14 +96,11 @@ func (m multiObserver) EventIPBlocklisted(evt mtglib.EventIPBlocklisted) {
func (m multiObserver) EventReplayAttack(evt mtglib.EventReplayAttack) { func (m multiObserver) EventReplayAttack(evt mtglib.EventReplayAttack) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventReplayAttack(evt)
})
obs.EventReplayAttack(evt)
}(v)
} }
wg.Wait() wg.Wait()
@@ -132,14 +108,11 @@ func (m multiObserver) EventReplayAttack(evt mtglib.EventReplayAttack) {
func (m multiObserver) EventIPListSize(evt mtglib.EventIPListSize) { func (m multiObserver) EventIPListSize(evt mtglib.EventIPListSize) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers { for _, v := range m.observers {
go func(obs Observer) { wg.Go(func() {
defer wg.Done() v.EventIPListSize(evt)
})
obs.EventIPListSize(evt)
}(v)
} }
wg.Wait() wg.Wait()
+20 -2
View File
@@ -23,6 +23,15 @@ secret = "ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c6561706973
# Host:port pair to run proxy on. # Host:port pair to run proxy on.
bind-to = "0.0.0.0:3128" bind-to = "0.0.0.0:3128"
# This defines what types of traffic mtg listens to. If you are not sure,
# then definitely keep it disable. Enable it only and only if incoming traffic
# is coming from some sort of load-balancer like HAProxy or ELB.
# https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt
#
# mtg uses a library that supports v1 and v2 versions of ProxyProtocol.
# default value is false.
# proxy-protocol-listener = false
# Defines how many concurrent connections are allowed to this proxy. # Defines how many concurrent connections are allowed to this proxy.
# All other incoming connections are going to be dropped. # All other incoming connections are going to be dropped.
concurrency = 8192 concurrency = 8192
@@ -71,6 +80,15 @@ tolerate-time-skewness = "5s"
# Otherwise, chose a new DC. # Otherwise, chose a new DC.
allow-fallback-on-unknown-dc = false allow-fallback-on-unknown-dc = false
# Telegram uses different DCs for different purposes. Unfortunately, most of
# DCs are not public, and dependent on a location of the current user, so
# mtg cannot know upfront about all of them, and how to access them. It has
# a default list of DCs, including some CDN IPs, but it is possible that some
# of them are not working for you. In this case, you can override them here.
[[dc-overrides]]
dc = 101
ips = ["127.0.0.1:443"]
# network defines different network-related settings # network defines different network-related settings
[network] [network]
# please be aware that mtg needs to do some external requests. For # please be aware that mtg needs to do some external requests. For
@@ -84,8 +102,8 @@ allow-fallback-on-unknown-dc = false
# resolver of the operating system and uses DOH instead. This is a host # resolver of the operating system and uses DOH instead. This is a host
# it has to access. # it has to access.
# #
# By default we use Quad9. # By default we use Cloudflare.
doh-ip = "9.9.9.9" doh-ip = "1.1.1.1"
# mtg can work via proxies (for now, we support only socks5). Proxy # mtg can work via proxies (for now, we support only socks5). Proxy
# configuration is done via list. So, you can specify many proxies # configuration is done via list. So, you can specify many proxies
+31 -35
View File
@@ -1,58 +1,54 @@
module github.com/9seconds/mtg/v2 module github.com/9seconds/mtg/v2
go 1.18 go 1.25
require ( require (
github.com/OneOfOne/xxhash v1.2.8 github.com/OneOfOne/xxhash v1.2.8
github.com/alecthomas/kong v0.6.1 github.com/alecthomas/kong v1.14.0
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6
github.com/d4l3k/messagediff v1.2.1 // indirect github.com/d4l3k/messagediff v1.2.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/gotd/td v0.34.0
github.com/jarcoal/httpmock v1.0.8 github.com/jarcoal/httpmock v1.0.8
github.com/mccutchen/go-httpbin v1.1.1 github.com/mccutchen/go-httpbin v1.1.1
github.com/panjf2000/ants/v2 v2.5.0 github.com/panjf2000/ants/v2 v2.11.5
github.com/pelletier/go-toml v1.9.5 github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_golang v1.13.0 github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.19.2 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/rs/zerolog v1.34.0
github.com/rs/zerolog v1.27.0 github.com/smira/go-statsd v1.3.4
github.com/smira/go-statsd v1.3.2 github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/testify v1.11.1
github.com/stretchr/testify v1.7.2 github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43 golang.org/x/crypto v0.48.0
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa golang.org/x/net v0.49.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.41.0
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 google.golang.org/protobuf v1.36.11 // indirect
google.golang.org/protobuf v1.28.1 // indirect
) )
require ( require (
github.com/txthinking/socks5 v0.0.0-20220615051428-39268faee3e6 github.com/pelletier/go-toml/v2 v2.2.4
github.com/pires/go-proxyproto v0.11.0
github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e
github.com/yl2chen/cidranger v1.0.2 github.com/yl2chen/cidranger v1.0.2
) )
require ( require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gotd/ige v0.1.5 // indirect github.com/klauspost/compress v1.18.3 // indirect
github.com/gotd/xor v0.1.1 // indirect github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/txthinking/runnergroup v0.0.0-20220212043759-8da8edb7dae8 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe // indirect github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae // indirect
go.uber.org/atomic v1.7.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect
go.uber.org/multierr v1.6.0 // indirect golang.org/x/sync v0.19.0 // indirect
go.uber.org/zap v1.16.0 // indirect golang.org/x/tools v0.41.0 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
+111 -550
View File
@@ -1,597 +1,158 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/kong v0.6.1 h1:1kNhcFepkR+HmasQpbiKDLylIL8yh5B5y1zPp5bJimA= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v0.6.1/go.mod h1:JfHWDzLmbh/puW6I3V7uWenoh56YNVONW+w8eKeUr9I= github.com/alecthomas/kong v1.14.0 h1:gFgEUZWu2ZmZ+UhyZ1bDhuutbKN1nTtJTwh19Wsn21s=
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48= github.com/alecthomas/kong v1.14.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
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/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0=
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/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-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/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/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/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/gotd/getdoc v0.6.2/go.mod h1:6Ul8cyaq+Aw0gVyuU+TKZPCmNjdlylzSIWVxjzI5t/U=
github.com/gotd/ige v0.1.5 h1:qITql4hZpqPM/DSeO5IVlxzXJxrs4ZZiKRwPif2K76U=
github.com/gotd/ige v0.1.5/go.mod h1:LbvqjUuGELVuHcKjfJZ2NPNzegICQU4eqrPAkXy0nTs=
github.com/gotd/neo v0.1.2 h1:hayFfKNSH5RP/L+KKKnsKMdDNCdhSfzVuo5TF4wvpa8=
github.com/gotd/neo v0.1.2/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ=
github.com/gotd/td v0.34.0 h1:BLIdpv2sxbCuWI2fyXCECRQuLJdnYk3VMZDRKNog/E8=
github.com/gotd/td v0.34.0/go.mod h1:4s/7cuEscdvZIecM/pVi5L3nTK+djSoVLAhgfk40OE4=
github.com/gotd/tl v0.4.0/go.mod h1:CMIcjPWFS4qxxJ+1Ce7U/ilbtPrkoVo/t8uhN5Y/D7c=
github.com/gotd/xor v0.1.0/go.mod h1:ZTmdgqf6SOHder8/MFp9CNkXIadzID5lIiaZxRZICH0=
github.com/gotd/xor v0.1.1 h1:LSPEeuf7noTo4fi4PrEsAaWXOSwjsY2e+IINPiR+c7s=
github.com/gotd/xor v0.1.1/go.mod h1:ZTmdgqf6SOHder8/MFp9CNkXIadzID5lIiaZxRZICH0=
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/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k=
github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/k0kubun/pp v2.4.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mccutchen/go-httpbin v1.1.1 h1:aEws49HEJEyXHLDnshQVswfUlCVoS8g6h9YaDyaW7RE= github.com/mccutchen/go-httpbin v1.1.1 h1:aEws49HEJEyXHLDnshQVswfUlCVoS8g6h9YaDyaW7RE=
github.com/mccutchen/go-httpbin v1.1.1/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I= github.com/mccutchen/go-httpbin v1.1.1/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/panjf2000/ants/v2 v2.11.5 h1:a7LMnMEeux/ebqTux140tRiaqcFTV0q2bEHF03nl6Rg=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/panjf2000/ants/v2 v2.11.5/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q=
github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/smira/go-statsd v1.3.4 h1:kBYWcLSGT+qC6JVbvfz48kX7mQys32fjDOPrfmsSx2c=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/smira/go-statsd v1.3.4/go.mod h1:RjdsESPgDODtg1VpVVf9MJrEW2Hw0wtRNbmB1CAhu6A=
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/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/quasilyte/go-ruleguard/dsl v0.3.2/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smira/go-statsd v1.3.2 h1:1EeuzxNZ/TD9apbTOFSM9nulqfcsQFmT4u1A2DREabI=
github.com/smira/go-statsd v1.3.2/go.mod h1:1srXJ9/pbnN04G8f4F1jUzsGOnwkPKXciyqpewGlkC4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM= github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM=
github.com/txthinking/runnergroup v0.0.0-20220212043759-8da8edb7dae8 h1:iYc+JnXtzv6sdMx9Q7OTKkDAn7FhDPDogcjeSfEQcLY= github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae h1:ArVM1jICfm7g4E4dBet+KHUFMLuxmj1Nxdp/tr3ByCU=
github.com/txthinking/runnergroup v0.0.0-20220212043759-8da8edb7dae8/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM= github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae/go.mod h1:cldYm15/XHcGt7ndItnEWHwFZo7dinU+2QoyjfErhsI=
github.com/txthinking/socks5 v0.0.0-20220615051428-39268faee3e6 h1:8DkPbOq/EPxbD5VJajKuvssiYZJSrlpeetcGfrBoBVE= github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e h1:xA7GVlbz6teIF4FdvuqwbX6C4tiqNk2PH7FRPIDerao=
github.com/txthinking/socks5 v0.0.0-20220615051428-39268faee3e6/go.mod h1:7NloQcrxaZYKURWph5HLxVDlIwMHJXCPkeWPtpftsIg= github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e/go.mod h1:ntmMHL/xPq1WLeKiw8p/eRATaae6PiVRNipHFJxI8PM=
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe h1:gMWxZxBFRAXqoGkwkYlPX2zvyyKNWJpxOxCrjqJkm5A= github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b h1:p+bJ3v5uUdEVMCoeFUs+BNJPsqt+Y6BLbDaPfTcbcH8=
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe/go.mod h1:WgqbSEmUYSjEV3B1qmee/PpP2NYEz4bL9/+mF1ma+s4= github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b/go.mod h1:OYRfF6eb5wY9VRFkXJH8FFBi3plw2v+giaIu7P054pM=
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43 h1:QEePdg0ty2r0t1+qwfZmQ4OOl/MB2UXIeJSpIZv56lg=
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43/go.mod h1:OYRfF6eb5wY9VRFkXJH8FFBi3plw2v+giaIu7P054pM=
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
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.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
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 h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
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 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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 h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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.1.0/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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 h1:9vYwv7OjYaky/tlAeD7C4oC9EsPTlaFl1H2jS++V+ME= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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/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/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.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.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/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/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-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-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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
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-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k=
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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
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/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
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=
+5 -11
View File
@@ -61,11 +61,8 @@ func (a *Access) Run(cli *CLI, version string) error {
} }
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(2) //nolint: gomnd
go func() {
defer wg.Done()
wg.Go(func() {
ip := a.PublicIPv4 ip := a.PublicIPv4
if ip == nil { if ip == nil {
ip = a.getIP(ntw, "tcp4") ip = a.getIP(ntw, "tcp4")
@@ -76,11 +73,8 @@ func (a *Access) Run(cli *CLI, version string) error {
} }
resp.IPv4 = a.makeURLs(conf, ip) resp.IPv4 = a.makeURLs(conf, ip)
}() })
wg.Go(func() {
go func() {
defer wg.Done()
ip := a.PublicIPv6 ip := a.PublicIPv6
if ip == nil { if ip == nil {
ip = a.getIP(ntw, "tcp6") ip = a.getIP(ntw, "tcp6")
@@ -91,7 +85,7 @@ func (a *Access) Run(cli *CLI, version string) error {
} }
resp.IPv6 = a.makeURLs(conf, ip) resp.IPv6 = a.makeURLs(conf, ip)
}() })
wg.Wait() wg.Wait()
@@ -129,7 +123,7 @@ func (a *Access) getIP(ntw mtglib.Network, protocol string) net.IP {
defer func() { defer func() {
io.Copy(io.Discard, resp.Body) //nolint: errcheck io.Copy(io.Discard, resp.Body) //nolint: errcheck
resp.Body.Close() resp.Body.Close() //nolint: errcheck
}() }()
data, err := io.ReadAll(resp.Body) data, err := io.ReadAll(resp.Body)
+21 -2
View File
@@ -10,6 +10,7 @@ import (
"github.com/9seconds/mtg/v2/antireplay" "github.com/9seconds/mtg/v2/antireplay"
"github.com/9seconds/mtg/v2/events" "github.com/9seconds/mtg/v2/events"
"github.com/9seconds/mtg/v2/internal/config" "github.com/9seconds/mtg/v2/internal/config"
"github.com/9seconds/mtg/v2/internal/proxyprotocol"
"github.com/9seconds/mtg/v2/internal/utils" "github.com/9seconds/mtg/v2/internal/utils"
"github.com/9seconds/mtg/v2/ipblocklist" "github.com/9seconds/mtg/v2/ipblocklist"
"github.com/9seconds/mtg/v2/ipblocklist/files" "github.com/9seconds/mtg/v2/ipblocklist/files"
@@ -17,6 +18,7 @@ import (
"github.com/9seconds/mtg/v2/mtglib" "github.com/9seconds/mtg/v2/mtglib"
"github.com/9seconds/mtg/v2/network" "github.com/9seconds/mtg/v2/network"
"github.com/9seconds/mtg/v2/stats" "github.com/9seconds/mtg/v2/stats"
"github.com/pires/go-proxyproto"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/yl2chen/cidranger" "github.com/yl2chen/cidranger"
) )
@@ -164,7 +166,7 @@ func makeIPAllowlist(conf config.ListConfig,
} }
func makeEventStream(conf *config.Config, logger mtglib.Logger) (mtglib.EventStream, error) { func makeEventStream(conf *config.Config, logger mtglib.Logger) (mtglib.EventStream, error) {
factories := make([]events.ObserverFactory, 0, 2) //nolint: gomnd factories := make([]events.ObserverFactory, 0, 2)
if conf.Stats.StatsD.Enabled.Get(false) { if conf.Stats.StatsD.Enabled.Get(false) {
statsdFactory, err := stats.NewStatsd( statsdFactory, err := stats.NewStatsd(
@@ -240,6 +242,14 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen
return fmt.Errorf("cannot build ip allowlist: %w", err) return fmt.Errorf("cannot build ip allowlist: %w", err)
} }
dcOverrides := map[int][]string{}
for _, override := range conf.DCOverrides {
dcid := override.DC.Get()
for _, addr := range override.IPs {
dcOverrides[dcid] = append(dcOverrides[dcid], addr.Get(""))
}
}
opts := mtglib.ProxyOpts{ opts := mtglib.ProxyOpts{
Logger: logger, Logger: logger,
Network: ntw, Network: ntw,
@@ -254,6 +264,7 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen
AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false), AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false),
TolerateTimeSkewness: conf.TolerateTimeSkewness.Value, TolerateTimeSkewness: conf.TolerateTimeSkewness.Value,
DCOverrides: dcOverrides,
} }
proxy, err := mtglib.NewProxy(opts) proxy, err := mtglib.NewProxy(opts)
@@ -266,12 +277,20 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen
return fmt.Errorf("cannot start proxy: %w", err) return fmt.Errorf("cannot start proxy: %w", err)
} }
if conf.ProxyProtocolListener.Get(false) {
listener = &proxyprotocol.ListenerAdapter{
Listener: proxyproto.Listener{
Listener: listener,
},
}
}
ctx := utils.RootContext() ctx := utils.RootContext()
go proxy.Serve(listener) //nolint: errcheck go proxy.Serve(listener) //nolint: errcheck
<-ctx.Done() <-ctx.Done()
listener.Close() listener.Close() //nolint: errcheck
proxy.Shutdown() proxy.Shutdown()
return nil return nil
+3 -3
View File
@@ -18,7 +18,7 @@ type SimpleRun struct {
TCPBuffer string `kong:"name='tcp-buffer',short='b',default='4KB',help='Deprecated and ignored'"` //nolint: lll TCPBuffer string `kong:"name='tcp-buffer',short='b',default='4KB',help='Deprecated and ignored'"` //nolint: lll
PreferIP string `kong:"name='prefer-ip',short='i',default='prefer-ipv6',help='IP preference. By default we prefer IPv6 with fallback to IPv4.'"` //nolint: lll PreferIP string `kong:"name='prefer-ip',short='i',default='prefer-ipv6',help='IP preference. By default we prefer IPv6 with fallback to IPv4.'"` //nolint: lll
DomainFrontingPort uint64 `kong:"name='domain-fronting-port',short='p',default='443',help='A port to access for domain fronting.'"` //nolint: lll DomainFrontingPort uint64 `kong:"name='domain-fronting-port',short='p',default='443',help='A port to access for domain fronting.'"` //nolint: lll
DOHIP net.IP `kong:"name='doh-ip',short='n',default='9.9.9.9',help='IP address of DNS-over-HTTP to use.'"` //nolint: lll DOHIP net.IP `kong:"name='doh-ip',short='n',default='1.1.1.1',help='IP address of DNS-over-HTTP to use.'"` //nolint: lll
Timeout time.Duration `kong:"name='timeout',short='t',default='10s',help='Network timeout to use'"` //nolint: lll Timeout time.Duration `kong:"name='timeout',short='t',default='10s',help='Network timeout to use'"` //nolint: lll
Socks5Proxies []string `kong:"name='socks5-proxy',short='s',help='Socks5 proxies to use for network access.'"` //nolint: lll Socks5Proxies []string `kong:"name='socks5-proxy',short='s',help='Socks5 proxies to use for network access.'"` //nolint: lll
AntiReplayCacheSize string `kong:"name='antireplay-cache-size',short='a',default='1MB',help='A size of anti-replay cache to use.'"` //nolint: lll AntiReplayCacheSize string `kong:"name='antireplay-cache-size',short='a',default='1MB',help='A size of anti-replay cache to use.'"` //nolint: lll
@@ -35,7 +35,7 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { //nolint: cyclop,funle
return fmt.Errorf("incorrect secret: %w", err) return fmt.Errorf("incorrect secret: %w", err)
} }
if err := conf.Concurrency.Set(strconv.FormatUint(s.Concurrency, 10)); err != nil { //nolint: gomnd if err := conf.Concurrency.Set(strconv.FormatUint(s.Concurrency, 10)); err != nil {
return fmt.Errorf("incorrect concurrency: %w", err) return fmt.Errorf("incorrect concurrency: %w", err)
} }
@@ -43,7 +43,7 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { //nolint: cyclop,funle
return fmt.Errorf("incorrect prefer-ip: %w", err) return fmt.Errorf("incorrect prefer-ip: %w", err)
} }
if err := conf.DomainFrontingPort.Set(strconv.FormatUint(s.DomainFrontingPort, 10)); err != nil { //nolint: gomnd if err := conf.DomainFrontingPort.Set(strconv.FormatUint(s.DomainFrontingPort, 10)); err != nil {
return fmt.Errorf("incorrect domain-fronting-port: %w", err) return fmt.Errorf("incorrect domain-fronting-port: %w", err)
} }
+5
View File
@@ -25,6 +25,7 @@ type Config struct {
AllowFallbackOnUnknownDC TypeBool `json:"allowFallbackOnUnknownDc"` AllowFallbackOnUnknownDC TypeBool `json:"allowFallbackOnUnknownDc"`
Secret mtglib.Secret `json:"secret"` Secret mtglib.Secret `json:"secret"`
BindTo TypeHostPort `json:"bindTo"` BindTo TypeHostPort `json:"bindTo"`
ProxyProtocolListener TypeBool `json:"proxyProtocolListener"`
PreferIP TypePreferIP `json:"preferIp"` PreferIP TypePreferIP `json:"preferIp"`
DomainFrontingPort TypePort `json:"domainFrontingPort"` DomainFrontingPort TypePort `json:"domainFrontingPort"`
TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"` TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"`
@@ -64,6 +65,10 @@ type Config struct {
MetricPrefix TypeMetricPrefix `json:"metricPrefix"` MetricPrefix TypeMetricPrefix `json:"metricPrefix"`
} `json:"prometheus"` } `json:"prometheus"`
} `json:"stats"` } `json:"stats"`
DCOverrides []struct {
DC TypeDC `json:"dc"`
IPs []TypeHostPort `json:"ips"`
} `json:"dcOverrides"`
} }
func (c *Config) Validate() error { func (c *Config) Validate() error {
+6 -1
View File
@@ -5,7 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml/v2"
) )
type tomlConfig struct { type tomlConfig struct {
@@ -13,6 +13,7 @@ type tomlConfig struct {
AllowFallbackOnUnknownDC bool `toml:"allow-fallback-on-unknown-dc" json:"allowFallbackOnUnknownDc,omitempty"` AllowFallbackOnUnknownDC bool `toml:"allow-fallback-on-unknown-dc" json:"allowFallbackOnUnknownDc,omitempty"`
Secret string `toml:"secret" json:"secret"` Secret string `toml:"secret" json:"secret"`
BindTo string `toml:"bind-to" json:"bindTo"` BindTo string `toml:"bind-to" json:"bindTo"`
ProxyProtocolListener bool `toml:"proxy-protocol-listener" json:"proxyProtocolListener"`
PreferIP string `toml:"prefer-ip" json:"preferIp,omitempty"` PreferIP string `toml:"prefer-ip" json:"preferIp,omitempty"`
DomainFrontingPort uint `toml:"domain-fronting-port" json:"domainFrontingPort,omitempty"` DomainFrontingPort uint `toml:"domain-fronting-port" json:"domainFrontingPort,omitempty"`
TolerateTimeSkewness string `toml:"tolerate-time-skewness" json:"tolerateTimeSkewness,omitempty"` TolerateTimeSkewness string `toml:"tolerate-time-skewness" json:"tolerateTimeSkewness,omitempty"`
@@ -59,6 +60,10 @@ type tomlConfig struct {
MetricPrefix string `toml:"metric-prefix" json:"metricPrefix,omitempty"` MetricPrefix string `toml:"metric-prefix" json:"metricPrefix,omitempty"`
} `toml:"prometheus" json:"prometheus,omitempty"` } `toml:"prometheus" json:"prometheus,omitempty"`
} `toml:"stats" json:"stats,omitempty"` } `toml:"stats" json:"stats,omitempty"`
DCOverrides []struct {
DC uint `toml:"dc" json:"dc"`
IPs []string `toml:"ips" json:"ips"`
} `toml:"dc-overrides" json:"dcOverrides,omitempty"`
} }
func Parse(rawData []byte) (*Config, error) { func Parse(rawData []byte) (*Config, error) {
+2 -2
View File
@@ -20,7 +20,7 @@ type TypeBoolTestSuite struct {
} }
func (suite *TypeBoolTestSuite) TestUnmarshalFail() { func (suite *TypeBoolTestSuite) TestUnmarshalFail() {
testData := []interface{}{ testData := []any{
"", "",
"np", "np",
"нет", "нет",
@@ -29,7 +29,7 @@ func (suite *TypeBoolTestSuite) TestUnmarshalFail() {
} }
for _, v := range testData { for _, v := range testData {
data, err := json.Marshal(map[string]interface{}{ data, err := json.Marshal(map[string]any{
"value": v, "value": v,
}) })
suite.NoError(err) suite.NoError(err)
+2 -2
View File
@@ -10,7 +10,7 @@ type TypeConcurrency struct {
} }
func (t *TypeConcurrency) Set(value string) error { func (t *TypeConcurrency) Set(value string) error {
concurrencyValue, err := strconv.ParseUint(value, 10, 16) //nolint: gomnd concurrencyValue, err := strconv.ParseUint(value, 10, 16)
if err != nil { if err != nil {
return fmt.Errorf("value is not uint (%s): %w", value, err) return fmt.Errorf("value is not uint (%s): %w", value, err)
} }
@@ -41,5 +41,5 @@ func (t TypeConcurrency) MarshalJSON() ([]byte, error) {
} }
func (t TypeConcurrency) String() string { func (t TypeConcurrency) String() string {
return strconv.FormatUint(uint64(t.Value), 10) //nolint: gomnd return strconv.FormatUint(uint64(t.Value), 10)
} }
+41
View File
@@ -0,0 +1,41 @@
package config
import (
"fmt"
"strconv"
)
type TypeDC struct {
Value int
}
func (t *TypeDC) Set(value string) error {
parsed, err := strconv.ParseInt(value, 10, 16)
if err != nil {
return fmt.Errorf("cannot parse dc: %w", err)
}
if parsed < 0 {
parsed = -parsed
}
t.Value = int(parsed)
return nil
}
func (t *TypeDC) UnmarshalJSON(data []byte) error {
return t.Set(string(data))
}
func (t TypeDC) MarshalJSON() ([]byte, error) {
return []byte(t.String()), nil
}
func (t TypeDC) String() string {
return strconv.Itoa(t.Value)
}
func (t TypeDC) Get() int {
return t.Value
}
+96
View File
@@ -0,0 +1,96 @@
package config_test
import (
"encoding/json"
"strconv"
"testing"
"github.com/9seconds/mtg/v2/internal/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type typeDCTestStruct struct {
Value config.TypeDC `json:"value"`
}
type TypeDCTestSuite struct {
suite.Suite
}
func (suite *TypeDCTestSuite) TestUnmarshalFail() {
testData := []string{
"-1s",
"1202002020202",
"xxx",
"-11111111111111",
"",
}
for _, v := range testData {
data, err := json.Marshal(map[string]string{
"value": v,
})
suite.NoError(err)
suite.T().Run(v, func(t *testing.T) {
assert.Error(t, json.Unmarshal(data, &typeDCTestStruct{}))
})
}
}
func (suite *TypeDCTestSuite) TestUnmarshalOk() {
testData := map[int]int{
1: 1,
-1: 1,
203: 203,
}
for value, expected := range testData {
data, err := json.Marshal(map[string]int{
"value": value,
})
suite.NoError(err)
suite.T().Run(strconv.Itoa(value), func(t *testing.T) {
testStruct := &typeDCTestStruct{}
assert.NoError(t, json.Unmarshal(data, testStruct))
assert.Equal(t, expected, testStruct.Value.Value)
assert.Equal(t, expected, testStruct.Value.Get())
})
}
}
func (suite *TypeDCTestSuite) TestMarshalOk() {
testData := map[string]int{
"1": 1,
"203": 203,
}
for k, v := range testData {
value := k
expected := v
suite.T().Run(value, func(t *testing.T) {
testStruct := &typeDCTestStruct{}
assert.NoError(t, testStruct.Value.Set(value))
data, err := json.Marshal(testStruct)
assert.NoError(t, err)
expectedJSON, err := json.Marshal(map[string]int{
"value": expected,
})
assert.NoError(t, err)
assert.JSONEq(t, string(expectedJSON), string(data))
})
}
}
func TestTypeDC(t *testing.T) {
t.Parallel()
suite.Run(t, &TypeDCTestSuite{})
}
+2 -2
View File
@@ -12,7 +12,7 @@ type TypeErrorRate struct {
} }
func (t *TypeErrorRate) Set(value string) error { func (t *TypeErrorRate) Set(value string) error {
parsedValue, err := strconv.ParseFloat(value, 64) //nolint: gomnd parsedValue, err := strconv.ParseFloat(value, 64)
if err != nil { if err != nil {
return fmt.Errorf("value is not a float (%s): %w", value, err) return fmt.Errorf("value is not a float (%s): %w", value, err)
} }
@@ -43,5 +43,5 @@ func (t TypeErrorRate) MarshalJSON() ([]byte, error) {
} }
func (t TypeErrorRate) String() string { func (t TypeErrorRate) String() string {
return strconv.FormatFloat(t.Value, 'f', -1, 64) //nolint: gomnd return strconv.FormatFloat(t.Value, 'f', -1, 64)
} }
+1 -1
View File
@@ -18,7 +18,7 @@ func (t *TypeHostPort) Set(value string) error {
return fmt.Errorf("incorrect host:port value (%v): %w", value, err) return fmt.Errorf("incorrect host:port value (%v): %w", value, err)
} }
portValue, err := strconv.ParseUint(port, 10, 16) //nolint: gomnd portValue, err := strconv.ParseUint(port, 10, 16)
if err != nil { if err != nil {
return fmt.Errorf("incorrect port number (%v): %w", value, err) return fmt.Errorf("incorrect port number (%v): %w", value, err)
} }
+1 -1
View File
@@ -10,7 +10,7 @@ type TypePort struct {
} }
func (t *TypePort) Set(value string) error { func (t *TypePort) Set(value string) error {
portValue, err := strconv.ParseUint(value, 10, 16) //nolint: gomnd portValue, err := strconv.ParseUint(value, 10, 16)
if err != nil { if err != nil {
return fmt.Errorf("incorrect port number (%v): %w", value, err) return fmt.Errorf("incorrect port number (%v): %w", value, err)
} }
+20
View File
@@ -0,0 +1,20 @@
package proxyprotocol
import (
"net"
"github.com/pires/go-proxyproto"
)
type ListenerAdapter struct {
proxyproto.Listener
}
func (l *ListenerAdapter) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return connWrapper{conn.(*proxyproto.Conn)}, nil
}
+25
View File
@@ -0,0 +1,25 @@
package proxyprotocol
import "github.com/pires/go-proxyproto"
type connWrapper struct {
*proxyproto.Conn
}
func (c connWrapper) CloseRead() error {
tcpConn, ok := c.TCPConn()
if !ok {
panic("we support only tcp connections")
}
return tcpConn.CloseRead()
}
func (c connWrapper) CloseWrite() error {
tcpConn, ok := c.TCPConn()
if !ok {
panic("we support only tcp connections")
}
return tcpConn.CloseWrite()
}
+1 -1
View File
@@ -35,7 +35,7 @@ func captureOutput(filefp **os.File, callback func()) string {
callback() callback()
writer.Close() writer.Close() //nolint: errcheck
<-closeChan <-closeChan
return strings.TrimSpace(buf.String()) return strings.TrimSpace(buf.String())
+1 -1
View File
@@ -18,7 +18,7 @@ func (l Listener) Accept() (net.Conn, error) {
} }
if err := network.SetClientSocketOptions(conn, 0); err != nil { if err := network.SetClientSocketOptions(conn, 0); err != nil {
conn.Close() conn.Close() //nolint: errcheck
return nil, fmt.Errorf("cannot set TCP options: %w", err) return nil, fmt.Errorf("cannot set TCP options: %w", err)
} }
+1 -1
View File
@@ -23,7 +23,7 @@ func (h httpFile) Open(ctx context.Context) (io.ReadCloser, error) {
if err != nil { if err != nil {
if response != nil { if response != nil {
io.Copy(io.Discard, response.Body) //nolint: errcheck io.Copy(io.Discard, response.Body) //nolint: errcheck
response.Body.Close() response.Body.Close() //nolint: errcheck
} }
return nil, fmt.Errorf("cannot get url %s: %w", h.url, err) return nil, fmt.Errorf("cannot get url %s: %w", h.url, err)
+1 -1
View File
@@ -77,7 +77,7 @@ func (suite *HTTPTestSuite) TestOk() {
readCloser, err := file.Open(suite.ctx) readCloser, err := file.Open(suite.ctx)
suite.NoError(err) suite.NoError(err)
defer readCloser.Close() defer readCloser.Close() //nolint: errcheck
data, err := io.ReadAll(readCloser) data, err := io.ReadAll(readCloser)
suite.NoError(err) suite.NoError(err)
+7 -10
View File
@@ -19,8 +19,8 @@ import (
var ( var (
fireholRegexpComment = regexp.MustCompile(`\s*#.*?$`) fireholRegexpComment = regexp.MustCompile(`\s*#.*?$`)
fireholIPv4DefaultCIDR = net.CIDRMask(32, 32) //nolint: gomnd fireholIPv4DefaultCIDR = net.CIDRMask(32, 32)
fireholIPv6DefaultCIDR = net.CIDRMask(128, 128) //nolint: gomnd fireholIPv6DefaultCIDR = net.CIDRMask(128, 128)
) )
// FireholUpdateCallback defines a signature of the callback that has to be // FireholUpdateCallback defines a signature of the callback that has to be
@@ -112,30 +112,27 @@ func (f *Firehol) update() {
defer cancel() defer cancel()
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(len(f.blocklists))
mutex := &sync.Mutex{} mutex := &sync.Mutex{}
ranger := cidranger.NewPCTrieRanger() ranger := cidranger.NewPCTrieRanger()
for _, v := range f.blocklists { for _, v := range f.blocklists {
go func(file files.File) { wg.Go(func() {
defer wg.Done() logger := f.logger.BindStr("filename", v.String())
logger := f.logger.BindStr("filename", file.String()) fileContent, err := v.Open(ctx)
fileContent, err := file.Open(ctx)
if err != nil { if err != nil {
logger.WarningError("update has failed", err) logger.WarningError("update has failed", err)
return return
} }
defer fileContent.Close() defer fileContent.Close() //nolint: errcheck
if err := f.updateFromFile(mutex, ranger, bufio.NewScanner(fileContent)); err != nil { if err := f.updateFromFile(mutex, ranger, bufio.NewScanner(fileContent)); err != nil {
logger.WarningError("update has failed", err) logger.WarningError("update has failed", err)
} }
}(v) })
} }
wg.Wait() wg.Wait()
+1 -1
View File
@@ -35,7 +35,7 @@ func (suite *FireholTestSuite) SetupSuite() {
panic(err) panic(err)
} }
defer filefp.Close() defer filefp.Close() //nolint: errcheck
io.Copy(w, filefp) //nolint: errcheck io.Copy(w, filefp) //nolint: errcheck
}) })
+1 -1
View File
@@ -8,5 +8,5 @@ package logger
// commonly used by many 3pp tools. While mtglib itself does not need it, it is // commonly used by many 3pp tools. While mtglib itself does not need it, it is
// always a good idea to support it and have a transient end to end logging. // always a good idea to support it and have a transient end to end logging.
type StdLikeLogger interface { type StdLikeLogger interface {
Printf(format string, args ...interface{}) Printf(format string, args ...any)
} }
+1 -1
View File
@@ -8,7 +8,7 @@ func (n noopLogger) Named(_ string) mtglib.Logger { return n }
func (n noopLogger) BindInt(_ string, _ int) mtglib.Logger { return n } func (n noopLogger) BindInt(_ string, _ int) mtglib.Logger { return n }
func (n noopLogger) BindStr(_, _ string) mtglib.Logger { return n } func (n noopLogger) BindStr(_, _ string) mtglib.Logger { return n }
func (n noopLogger) BindJSON(_, _ string) mtglib.Logger { return n } func (n noopLogger) BindJSON(_, _ string) mtglib.Logger { return n }
func (n noopLogger) Printf(_ string, _ ...interface{}) {} func (n noopLogger) Printf(_ string, _ ...any) {}
func (n noopLogger) Info(_ string) {} func (n noopLogger) Info(_ string) {}
func (n noopLogger) Warning(_ string) {} func (n noopLogger) Warning(_ string) {}
func (n noopLogger) Debug(_ string) {} func (n noopLogger) Debug(_ string) {}
+1 -1
View File
@@ -78,7 +78,7 @@ func (z *zeroLogContext) BindJSON(name, value string) mtglib.Logger {
} }
} }
func (z *zeroLogContext) Printf(format string, args ...interface{}) { func (z *zeroLogContext) Printf(format string, args ...any) {
z.Debug(fmt.Sprintf(format, args...)) z.Debug(fmt.Sprintf(format, args...))
} }
-5
View File
@@ -9,16 +9,11 @@
package main package main
import ( import (
"math/rand"
"time"
"github.com/9seconds/mtg/v2/internal/cli" "github.com/9seconds/mtg/v2/internal/cli"
"github.com/alecthomas/kong" "github.com/alecthomas/kong"
) )
func main() { func main() {
rand.Seed(time.Now().UTC().UnixNano())
cli := &cli.CLI{} cli := &cli.CLI{}
ctx := kong.Parse(cli, kong.Vars{ ctx := kong.Parse(cli, kong.Vars{
"version": getVersion(), "version": getVersion(),
+38
View File
@@ -0,0 +1,38 @@
[[tools.go]]
version = "1.26.0"
backend = "core:go"
"platforms.linux-arm64" = { checksum = "sha256:bd03b743eb6eb4193ea3c3fd3956546bf0e3ca5b7076c8226334afe6b75704cd", url = "https://dl.google.com/go/go1.26.0.linux-arm64.tar.gz"}
"platforms.linux-x64" = { checksum = "sha256:aac1b08a0fb0c4e0a7c1555beb7b59180b05dfc5a3d62e40e9de90cd42f88235", url = "https://dl.google.com/go/go1.26.0.linux-amd64.tar.gz"}
"platforms.macos-arm64" = { checksum = "sha256:b1640525dfe68f066d56f200bef7bf4dce955a1a893bd061de6754c211431023", url = "https://dl.google.com/go/go1.26.0.darwin-arm64.tar.gz"}
"platforms.macos-x64" = { checksum = "sha256:1ca28b7703cbea05a65b2a1d92d6b308610ef92f8824578a0874f2e60c9d5a22", url = "https://dl.google.com/go/go1.26.0.darwin-amd64.tar.gz"}
"platforms.windows-x64" = { checksum = "sha256:9bbe0fc64236b2b51f6255c05c4232532b8ecc0e6d2e00950bd3021d8a4d07d4", url = "https://dl.google.com/go/go1.26.0.windows-amd64.zip"}
[[tools."go:golang.org/x/pkgsite/cmd/pkgsite"]]
version = "latest"
backend = "go:golang.org/x/pkgsite/cmd/pkgsite"
[[tools."go:golang.org/x/tools/gopls"]]
version = "0.21.1"
backend = "go:golang.org/x/tools/gopls"
[[tools."go:mvdan.cc/gofumpt"]]
version = "0.9.2"
backend = "go:mvdan.cc/gofumpt"
[[tools.golangci-lint]]
version = "2.10.1"
backend = "aqua:golangci/golangci-lint"
"platforms.linux-arm64" = { checksum = "sha256:6652b42ae02915eb2f9cb2a2e0cac99514c8eded8388d88ae3e06e1a52c00de8", url = "https://github.com/golangci/golangci-lint/releases/download/v2.10.1/golangci-lint-2.10.1-linux-arm64.tar.gz"}
"platforms.linux-x64" = { checksum = "sha256:dfa775874cf0561b404a02a8f4481fc69b28091da95aa697259820d429b09c99", url = "https://github.com/golangci/golangci-lint/releases/download/v2.10.1/golangci-lint-2.10.1-linux-amd64.tar.gz"}
"platforms.macos-arm64" = { checksum = "sha256:03bfadf67e52b441b7ec21305e501c717df93c959836d66c7f97312654acb297", url = "https://github.com/golangci/golangci-lint/releases/download/v2.10.1/golangci-lint-2.10.1-darwin-arm64.tar.gz"}
"platforms.macos-x64" = { checksum = "sha256:66fb0da81b8033b477f97eea420d4b46b230ca172b8bb87c6610109f3772b6b6", url = "https://github.com/golangci/golangci-lint/releases/download/v2.10.1/golangci-lint-2.10.1-darwin-amd64.tar.gz"}
"platforms.windows-x64" = { checksum = "sha256:c60c87695e79db8e320f0e5be885059859de52bb5ee5f11be5577828570bc2a3", url = "https://github.com/golangci/golangci-lint/releases/download/v2.10.1/golangci-lint-2.10.1-windows-amd64.zip"}
[[tools.goreleaser]]
version = "2.13.3"
backend = "aqua:goreleaser/goreleaser"
"platforms.linux-arm64" = { checksum = "sha256:156656d0f874542d618568bd50afd3d33ced2e8aab2c60cc7c21e1b9fa52031e", url = "https://github.com/goreleaser/goreleaser/releases/download/v2.13.3/goreleaser_Linux_arm64.tar.gz"}
"platforms.linux-x64" = { checksum = "sha256:4b66f2f78f78561330350651ade557b70328664718490f37834749073af21d20", url = "https://github.com/goreleaser/goreleaser/releases/download/v2.13.3/goreleaser_Linux_x86_64.tar.gz"}
"platforms.macos-arm64" = { checksum = "sha256:5516c37779efb3935d5b213cda3b0b9025ae94ddbcb51df6919acbcdef4194b0", url = "https://github.com/goreleaser/goreleaser/releases/download/v2.13.3/goreleaser_Darwin_all.tar.gz"}
"platforms.macos-x64" = { checksum = "sha256:5516c37779efb3935d5b213cda3b0b9025ae94ddbcb51df6919acbcdef4194b0", url = "https://github.com/goreleaser/goreleaser/releases/download/v2.13.3/goreleaser_Darwin_all.tar.gz"}
"platforms.windows-x64" = { checksum = "sha256:c5586c4ed749ca358ad61ed73ee4b8039cfa68daae8c23e69fb086d549dfb31d", url = "https://github.com/goreleaser/goreleaser/releases/download/v2.13.3/goreleaser_Windows_x86_64.zip"}
+1 -1
View File
@@ -249,7 +249,7 @@ type Logger interface {
BindJSON(name, value string) Logger BindJSON(name, value string) Logger
// Printf is to support log.Logger behavior. // Printf is to support log.Logger behavior.
Printf(format string, args ...interface{}) Printf(format string, args ...any)
// Info puts a message about some normal situation. // Info puts a message about some normal situation.
Info(msg string) Info(msg string)
+11 -11
View File
@@ -8,17 +8,17 @@ import (
type NoopLogger struct{} type NoopLogger struct{}
func (n NoopLogger) Named(_ string) Logger { return n } func (n NoopLogger) Named(_ string) Logger { return n }
func (n NoopLogger) BindInt(_ string, _ int) Logger { return n } func (n NoopLogger) BindInt(_ string, _ int) Logger { return n }
func (n NoopLogger) BindStr(_, _ string) Logger { return n } func (n NoopLogger) BindStr(_, _ string) Logger { return n }
func (n NoopLogger) BindJSON(_, _ string) Logger { return n } func (n NoopLogger) BindJSON(_, _ string) Logger { return n }
func (n NoopLogger) Printf(_ string, _ ...interface{}) {} func (n NoopLogger) Printf(_ string, _ ...any) {}
func (n NoopLogger) Info(_ string) {} func (n NoopLogger) Info(_ string) {}
func (n NoopLogger) Warning(_ string) {} func (n NoopLogger) Warning(_ string) {}
func (n NoopLogger) Debug(_ string) {} func (n NoopLogger) Debug(_ string) {}
func (n NoopLogger) InfoError(_ string, _ error) {} func (n NoopLogger) InfoError(_ string, _ error) {}
func (n NoopLogger) WarningError(_ string, _ error) {} func (n NoopLogger) WarningError(_ string, _ error) {}
func (n NoopLogger) DebugError(_ string, _ error) {} func (n NoopLogger) DebugError(_ string, _ error) {}
type EventStreamMock struct { type EventStreamMock struct {
mock.Mock mock.Mock
+10
View File
@@ -0,0 +1,10 @@
package dc
type Addr struct {
Network string
Address string
}
func (d Addr) String() string {
return d.Address
}
+33
View File
@@ -0,0 +1,33 @@
package dc
import "math/rand/v2"
type dcAddrSet struct {
v4 map[int][]Addr
v6 map[int][]Addr
}
func (d dcAddrSet) getV4(dc int) []Addr {
if d.v4 == nil {
return nil
}
return d.get(d.v4[dc])
}
func (d dcAddrSet) getV6(dc int) []Addr {
if d.v6 == nil {
return nil
}
return d.get(d.v6[dc])
}
func (d dcAddrSet) get(addrs []Addr) []Addr {
otherSet := make([]Addr, 0, len(addrs))
otherSet = append(otherSet, addrs...)
rand.Shuffle(len(otherSet), func(i, j int) {
otherSet[i], otherSet[j] = otherSet[j], otherSet[i]
})
return otherSet
}
+16
View File
@@ -0,0 +1,16 @@
package dc_test
import (
"testing"
"github.com/9seconds/mtg/v2/mtglib/internal/dc"
"github.com/stretchr/testify/assert"
)
func TestAddr(t *testing.T) {
t.Parallel()
addr := dc.Addr{Network: "tcp4", Address: "127.0.0.1:443"}
assert.Equal(t, "127.0.0.1:443", addr.String())
}
+73
View File
@@ -0,0 +1,73 @@
package dc
type preferIP uint8
const (
preferIPOnlyIPv4 preferIP = iota
preferIPOnlyIPv6
preferIPPreferIPv4
preferIPPreferIPv6
)
const (
DefaultDC = 2
)
type Logger interface {
Info(msg string)
WarningError(msg string, err error)
}
var (
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30
defaultDCAddrSet = dcAddrSet{
v4: map[int][]Addr{
1: {
{Network: "tcp4", Address: "149.154.175.50:443"},
},
2: {
{Network: "tcp4", Address: "149.154.167.51:443"},
{Network: "tcp4", Address: "95.161.76.100:443"},
},
3: {
{Network: "tcp4", Address: "149.154.175.100:443"},
},
4: {
{Network: "tcp4", Address: "149.154.167.91:443"},
},
5: {
{Network: "tcp4", Address: "149.154.171.5:443"},
},
},
v6: map[int][]Addr{
1: {
{Network: "tcp6", Address: "[2001:b28:f23d:f001::a]:443"},
},
2: {
{Network: "tcp6", Address: "[2001:67c:04e8:f002::a]:443"},
},
3: {
{Network: "tcp6", Address: "[2001:b28:f23d:f003::a]:443"},
},
4: {
{Network: "tcp6", Address: "[2001:67c:04e8:f004::a]:443"},
},
5: {
{Network: "tcp6", Address: "[2001:b28:f23f:f005::a]:443"},
},
},
}
defaultDCOverridesAddrSet = dcAddrSet{
v4: map[int][]Addr{
203: {
{Network: "tcp4", Address: "91.105.192.100:443"},
},
},
v6: map[int][]Addr{
203: {
{Network: "tcp6", Address: "[2a0a:f280:0203:000a:5000:0000:0000:0100]:443"},
},
},
}
)
+79
View File
@@ -0,0 +1,79 @@
package dc
import (
"fmt"
"net"
"strings"
)
type Telegram struct {
view dcView
preferIP preferIP
}
func (t *Telegram) GetAddresses(dc int) []Addr {
switch t.preferIP {
case preferIPOnlyIPv4:
return t.view.getV4(dc)
case preferIPOnlyIPv6:
return t.view.getV4(dc)
case preferIPPreferIPv4:
return append(t.view.getV4(dc), t.view.getV6(dc)...)
}
return append(t.view.getV6(dc), t.view.getV4(dc)...)
}
func New(ipPreference string, userOverrides map[int][]string) (*Telegram, error) {
var pref preferIP
switch strings.ToLower(ipPreference) {
case "prefer-ipv4":
pref = preferIPPreferIPv4
case "prefer-ipv6":
pref = preferIPPreferIPv6
case "only-ipv4":
pref = preferIPOnlyIPv4
case "only-ipv6":
pref = preferIPOnlyIPv6
default:
return nil, fmt.Errorf("unknown ip preference %s", ipPreference)
}
overrides := dcAddrSet{
v4: map[int][]Addr{},
v6: map[int][]Addr{},
}
for dc, addrs := range userOverrides {
for _, addr := range addrs {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, fmt.Errorf("incorrect host %s: %w", addr, err)
}
parsed := net.ParseIP(host)
if parsed == nil {
return nil, fmt.Errorf("incorrect host %s", addr)
}
if parsed.To4() != nil {
overrides.v4[dc] = append(overrides.v4[dc], Addr{
Network: "tcp4",
Address: addr,
})
} else {
overrides.v6[dc] = append(overrides.v6[dc], Addr{
Network: "tcp6",
Address: addr,
})
}
}
}
return &Telegram{
view: dcView{
overrides: overrides,
},
preferIP: pref,
}, nil
}
+21
View File
@@ -0,0 +1,21 @@
package dc
type dcView struct {
overrides dcAddrSet
}
func (d dcView) getV4(dc int) []Addr {
addrs := d.overrides.getV4(dc)
addrs = append(addrs, defaultDCOverridesAddrSet.getV4(dc)...)
addrs = append(addrs, defaultDCAddrSet.getV4(dc)...)
return addrs
}
func (d dcView) getV6(dc int) []Addr {
addrs := d.overrides.getV6(dc)
addrs = append(addrs, defaultDCOverridesAddrSet.getV6(dc)...)
addrs = append(addrs, defaultDCAddrSet.getV6(dc)...)
return addrs
}
+81
View File
@@ -0,0 +1,81 @@
package dc
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type ViewTestSuite struct {
suite.Suite
view dcView
}
func (suite *ViewTestSuite) SetupSuite() {
suite.view = dcView{
overrides: dcAddrSet{
v4: map[int][]Addr{
111: {
{Network: "tcp4", Address: "127.0.0.1:443"},
},
203: {
{Network: "tcp4", Address: "127.0.0.2:443"},
},
},
v6: map[int][]Addr{
203: {
{Network: "tcp6", Address: "xxx"},
},
},
},
}
}
func (suite *ViewTestSuite) TestGetV4() {
testData := map[int][]Addr{
111: {
{"tcp4", "127.0.0.1:443"},
},
203: {
{"tcp4", "127.0.0.2:443"},
{"tcp4", "91.105.192.100:443"},
},
2: {
{"tcp4", "149.154.167.51:443"},
{"tcp4", "95.161.76.100:443"},
},
}
for dc, addresses := range testData {
suite.T().Run(fmt.Sprintf("dc%d", dc), func(t *testing.T) {
assert.ElementsMatch(t, addresses, suite.view.getV4(dc))
})
}
}
func (suite *ViewTestSuite) TestGetV6() {
testData := map[int][]Addr{
111: {},
203: {
{"tcp6", "xxx"},
{"tcp6", "[2a0a:f280:0203:000a:5000:0000:0000:0100]:443"},
},
1: {
{"tcp6", "[2001:b28:f23d:f001::a]:443"},
},
}
for dc, addresses := range testData {
suite.T().Run(fmt.Sprintf("dc%d", dc), func(t *testing.T) {
assert.ElementsMatch(t, addresses, suite.view.getV6(dc))
})
}
}
func TestView(t *testing.T) {
t.Parallel()
suite.Run(t, &ViewTestSuite{})
}
+3 -3
View File
@@ -56,7 +56,7 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
if len(handshake)-4 != int(handshakeLength) { if len(handshake)-4 != int(handshakeLength) {
return hello, return hello,
fmt.Errorf("incorrect handshake size. manifested=%d, real=%d", fmt.Errorf("incorrect handshake size. manifested=%d, real=%d",
handshakeLength, len(handshake)-4) //nolint: gomnd handshakeLength, len(handshake)-4)
} }
copy(hello.Random[:], handshake[ClientHelloRandomOffset:]) copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
@@ -76,7 +76,7 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
computedRandom := mac.Sum(nil) computedRandom := mac.Sum(nil)
for i := 0; i < RandomLen; i++ { for i := range RandomLen {
computedRandom[i] ^= hello.Random[i] computedRandom[i] ^= hello.Random[i]
} }
@@ -100,7 +100,7 @@ func parseSessionID(hello *ClientHello, handshake []byte) {
} }
func parseCipherSuite(hello *ClientHello, handshake []byte) { func parseCipherSuite(hello *ClientHello, handshake []byte) {
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 //nolint: gomnd cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3
hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2]) hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
} }
+2 -2
View File
@@ -3,7 +3,7 @@ package faketls
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"math/rand" "math/rand/v2"
"github.com/9seconds/mtg/v2/essentials" "github.com/9seconds/mtg/v2/essentials"
"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record" "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
@@ -53,7 +53,7 @@ func (c *Conn) Write(p []byte) (int, error) {
lenP := len(p) lenP := len(p)
for len(p) > 0 { for len(p) > 0 {
chunkSize := rand.Intn(record.TLSMaxRecordSize) chunkSize := rand.IntN(record.TLSMaxRecordSize)
if chunkSize > len(p) || chunkSize == 0 { if chunkSize > len(p) || chunkSize == 0 {
chunkSize = len(p) chunkSize = len(p)
} }
+2 -2
View File
@@ -2,9 +2,9 @@ package faketls_test
import ( import (
"bytes" "bytes"
"crypto/rand"
"errors" "errors"
"io" "io"
"math/rand"
"testing" "testing"
"github.com/9seconds/mtg/v2/internal/testlib" "github.com/9seconds/mtg/v2/internal/testlib"
@@ -123,7 +123,7 @@ func (suite *ConnTestSuite) TestWrite() {
suite.connMock.On("Write", mock.Anything).Return(0, nil) suite.connMock.On("Write", mock.Anything).Return(0, nil)
dataToRec := make([]byte, record.TLSMaxRecordSize*2) dataToRec := make([]byte, record.TLSMaxRecordSize*2)
rand.Read(dataToRec) rand.Read(dataToRec) //nolint: staticcheck, errcheck
n, err := suite.c.Write(dataToRec) n, err := suite.c.Write(dataToRec)
suite.NoError(err) suite.NoError(err)
+1 -1
View File
@@ -6,7 +6,7 @@ import (
) )
var bytesBufferPool = sync.Pool{ var bytesBufferPool = sync.Pool{
New: func() interface{} { New: func() any {
return &bytes.Buffer{} return &bytes.Buffer{}
}, },
} }
+1 -1
View File
@@ -5,7 +5,7 @@ import (
) )
var recordPool = sync.Pool{ var recordPool = sync.Pool{
New: func() interface{} { New: func() any {
return &Record{} return &Record{}
}, },
} }
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"io" "io"
mrand "math/rand" mrand "math/rand/v2"
"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record" "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
@@ -36,7 +36,7 @@ func SendWelcomePacket(writer io.Writer, secret []byte, clientHello ClientHello)
rec.Type = record.TypeApplicationData rec.Type = record.TypeApplicationData
rec.Version = record.Version12 rec.Version = record.Version12
if _, err := io.CopyN(&rec.Payload, rand.Reader, int64(1024+mrand.Intn(3092))); err != nil { //nolint: gomnd if _, err := io.CopyN(&rec.Payload, rand.Reader, int64(1024+mrand.IntN(3092))); err != nil {
panic(err) panic(err)
} }
+3 -3
View File
@@ -3,8 +3,8 @@ package faketls_test
import ( import (
"bytes" "bytes"
"crypto/hmac" "crypto/hmac"
"crypto/rand"
"crypto/sha256" "crypto/sha256"
"math/rand"
"testing" "testing"
"time" "time"
@@ -30,10 +30,10 @@ func (suite *WelcomeTestSuite) SetupTest() {
SessionID: make([]byte, 32), SessionID: make([]byte, 32),
} }
_, err := rand.Read(suite.h.SessionID) _, err := rand.Read(suite.h.SessionID) //nolint: staticcheck
suite.NoError(err) suite.NoError(err)
_, err = rand.Read(suite.h.Random[:]) _, err = rand.Read(suite.h.Random[:]) //nolint: staticcheck
suite.NoError(err) suite.NoError(err)
suite.buf = &bytes.Buffer{} suite.buf = &bytes.Buffer{}
@@ -36,7 +36,7 @@ type handshakeFrame struct {
} }
func (h *handshakeFrame) dc() int { func (h *handshakeFrame) dc() int {
idx := int16(h.data[handshakeFrameOffsetDC]) | int16(h.data[handshakeFrameOffsetDC+1])<<8 //nolint: gomnd, lll // little endian for int16 is here idx := int16(h.data[handshakeFrameOffsetDC]) | int16(h.data[handshakeFrameOffsetDC+1])<<8 //nolint: lll // little endian for int16 is here
switch { switch {
case idx > 0: case idx > 0:
@@ -63,7 +63,7 @@ func (h *handshakeFrame) connectionType() []byte {
func (h *handshakeFrame) invert() handshakeFrame { func (h *handshakeFrame) invert() handshakeFrame {
copyFrame := *h copyFrame := *h
for i := 0; i < handshakeFrameLenKey+handshakeFrameLenIV; i++ { for i := range handshakeFrameLenKey + handshakeFrameLenIV {
copyFrame.data[handshakeFrameOffsetKey+i] = h.data[handshakeFrameOffsetConnectionType-1-i] copyFrame.data[handshakeFrameOffsetKey+i] = h.data[handshakeFrameOffsetConnectionType-1-i]
} }
+1 -1
View File
@@ -117,7 +117,7 @@ func NewServerHandshakeTestData(t *testing.T) ServerHandshakeTestData {
serverEncryptedReverted := make([]byte, len(serverEncrypted)) serverEncryptedReverted := make([]byte, len(serverEncrypted))
for i := 0; i < 32+16; i++ { for i := range 32 + 16 {
serverEncryptedReverted[8+i] = serverEncrypted[8+32+16-1-i] serverEncryptedReverted[8+i] = serverEncrypted[8+32+16-1-i]
} }
+2 -2
View File
@@ -9,12 +9,12 @@ import (
var ( var (
sha256HasherPool = sync.Pool{ sha256HasherPool = sync.Pool{
New: func() interface{} { New: func() any {
return sha256.New() return sha256.New()
}, },
} }
bytesBufferPool = sync.Pool{ bytesBufferPool = sync.Pool{
New: func() interface{} { New: func() any {
return &bytes.Buffer{} return &bytes.Buffer{}
}, },
} }
@@ -47,12 +47,12 @@ func generateServerHanshakeFrame() serverHandshakeFrame {
panic(err) panic(err)
} }
if frame.data[0] == 0xef { //nolint: gomnd // taken from tg sources if frame.data[0] == 0xef { // taken from tg sources
continue continue
} }
switch binary.LittleEndian.Uint32(frame.data[:4]) { switch binary.LittleEndian.Uint32(frame.data[:4]) {
case 0x44414548, 0x54534f50, 0x20544547, 0x4954504f, 0xeeeeeeee: //nolint: gomnd // taken from tg sources case 0x44414548, 0x54534f50, 0x20544547, 0x4954504f, 0xeeeeeeee: // taken from tg sources
continue continue
} }
+1 -1
View File
@@ -5,5 +5,5 @@ const (
) )
type Logger interface { type Logger interface {
Printf(msg string, args ...interface{}) Printf(msg string, args ...any)
} }
+1 -1
View File
@@ -2,4 +2,4 @@ package relay_test
type loggerMock struct{} type loggerMock struct{}
func (l loggerMock) Printf(format string, args ...interface{}) {} func (l loggerMock) Printf(format string, args ...any) {}
+1 -1
View File
@@ -3,7 +3,7 @@ package relay
import "sync" import "sync"
var copyBufferPool = sync.Pool{ var copyBufferPool = sync.Pool{
New: func() interface{} { New: func() any {
rv := make([]byte, copyBufferSize) rv := make([]byte, copyBufferSize)
return &rv return &rv
+4 -4
View File
@@ -9,16 +9,16 @@ import (
) )
func Relay(ctx context.Context, log Logger, telegramConn, clientConn essentials.Conn) { func Relay(ctx context.Context, log Logger, telegramConn, clientConn essentials.Conn) {
defer telegramConn.Close() defer telegramConn.Close() //nolint: errcheck
defer clientConn.Close() defer clientConn.Close() //nolint: errcheck
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
go func() { go func() {
<-ctx.Done() <-ctx.Done()
telegramConn.Close() telegramConn.Close() //nolint: errcheck
clientConn.Close() clientConn.Close() //nolint: errcheck
}() }()
closeChan := make(chan struct{}) closeChan := make(chan struct{})
-41
View File
@@ -1,41 +0,0 @@
package telegram
import "math/rand"
type addressPool struct {
v4 [][]tgAddr
v6 [][]tgAddr
}
func (a addressPool) isValidDC(dc int) bool {
return dc > 0 && dc <= len(a.v4) && dc <= len(a.v6)
}
func (a addressPool) getRandomDC() int {
return 1 + rand.Intn(len(a.v4))
}
func (a addressPool) getV4(dc int) []tgAddr {
return a.get(a.v4, dc-1)
}
func (a addressPool) getV6(dc int) []tgAddr {
return a.get(a.v6, dc-1)
}
func (a addressPool) get(addresses [][]tgAddr, dc int) []tgAddr {
if dc < 0 || dc >= len(addresses) {
return nil
}
rv := make([]tgAddr, len(addresses[dc]))
copy(rv, addresses[dc])
if len(rv) > 1 {
rand.Shuffle(len(rv), func(i, j int) {
rv[i], rv[j] = rv[j], rv[i]
})
}
return rv
}
-90
View File
@@ -1,90 +0,0 @@
package telegram
import (
"context"
"errors"
"github.com/9seconds/mtg/v2/essentials"
)
var errNoAddresses = errors.New("no addresses")
type preferIP uint8
const (
preferIPOnlyIPv4 preferIP = iota
preferIPOnlyIPv6
preferIPPreferIPv4
preferIPPreferIPv6
)
type tgAddr struct {
network string
address string
}
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30
var (
productionV4Addresses = [][]tgAddr{
{ // dc1
{network: "tcp4", address: "149.154.175.50:443"},
},
{ // dc2
{network: "tcp4", address: "149.154.167.51:443"},
{network: "tcp4", address: "95.161.76.100:443"},
},
{ // dc3
{network: "tcp4", address: "149.154.175.100:443"},
},
{ // dc4
{network: "tcp4", address: "149.154.167.91:443"},
},
{ // dc5
{network: "tcp4", address: "149.154.171.5:443"},
},
}
productionV6Addresses = [][]tgAddr{
{ // dc1
{network: "tcp6", address: "[2001:b28:f23d:f001::a]:443"},
},
{ // dc2
{network: "tcp6", address: "[2001:67c:04e8:f002::a]:443"},
},
{ // dc3
{network: "tcp6", address: "[2001:b28:f23d:f003::a]:443"},
},
{ // dc4
{network: "tcp6", address: "[2001:67c:04e8:f004::a]:443"},
},
{ // dc5
{network: "tcp6", address: "[2001:b28:f23f:f005::a]:443"},
},
}
testV4Addresses = [][]tgAddr{
{ // dc1
{network: "tcp4", address: "149.154.175.10:443"},
},
{ // dc2
{network: "tcp4", address: "149.154.167.40:443"},
},
{ // dc3
{network: "tcp4", address: "149.154.175.117:443"},
},
}
testV6Addresses = [][]tgAddr{
{ // dc1
{network: "tcp6", address: "[2001:b28:f23d:f001::e]:443"},
},
{ // dc2
{network: "tcp6", address: "[2001:67c:04e8:f002::e]:443"},
},
{ // dc3
{network: "tcp6", address: "[2001:b28:f23d:f003::e]:443"},
},
}
)
type Dialer interface {
DialContext(ctx context.Context, network, address string) (essentials.Conn, error)
}
-83
View File
@@ -1,83 +0,0 @@
package telegram
import (
"context"
"fmt"
"strings"
"github.com/9seconds/mtg/v2/essentials"
)
type Telegram struct {
dialer Dialer
preferIP preferIP
pool addressPool
}
func (t Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) {
var addresses []tgAddr
switch t.preferIP {
case preferIPOnlyIPv4:
addresses = t.pool.getV4(dc)
case preferIPOnlyIPv6:
addresses = t.pool.getV6(dc)
case preferIPPreferIPv4:
addresses = append(t.pool.getV4(dc), t.pool.getV6(dc)...)
case preferIPPreferIPv6:
addresses = append(t.pool.getV6(dc), t.pool.getV4(dc)...)
}
var conn essentials.Conn
err := errNoAddresses
for _, v := range addresses {
conn, err = t.dialer.DialContext(ctx, v.network, v.address)
if err == nil {
return conn, nil
}
}
return nil, fmt.Errorf("cannot dial to %d dc: %w", dc, err)
}
func (t Telegram) IsKnownDC(dc int) bool {
return t.pool.isValidDC(dc)
}
func (t Telegram) GetFallbackDC() int {
return t.pool.getRandomDC()
}
func New(dialer Dialer, ipPreference string, useTestDCs bool) (*Telegram, error) {
var pref preferIP
switch strings.ToLower(ipPreference) {
case "prefer-ipv4":
pref = preferIPPreferIPv4
case "prefer-ipv6":
pref = preferIPPreferIPv6
case "only-ipv4":
pref = preferIPOnlyIPv4
case "only-ipv6":
pref = preferIPOnlyIPv6
default:
return nil, fmt.Errorf("unknown ip preference %s", ipPreference)
}
pool := addressPool{
v4: productionV4Addresses,
v6: productionV6Addresses,
}
if useTestDCs {
pool.v4 = testV4Addresses
pool.v6 = testV6Addresses
}
return &Telegram{
dialer: dialer,
preferIP: pref,
pool: pool,
}, nil
}
@@ -1,159 +0,0 @@
package telegram
import (
"context"
"errors"
"io"
"net"
"strconv"
"testing"
"github.com/9seconds/mtg/v2/internal/testlib"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)
type TelegramTestSuite struct {
suite.Suite
dialerMock *testlib.MtglibNetworkMock
t *Telegram
}
func (suite *TelegramTestSuite) SetupTest() {
suite.dialerMock = &testlib.MtglibNetworkMock{}
suite.t, _ = New(suite.dialerMock, "prefer-ipv4", false)
}
func (suite *TelegramTestSuite) TearDownTest() {
suite.dialerMock.AssertExpectations(suite.T())
}
func (suite *TelegramTestSuite) TestUnknownDC() {
testData := []int{
-1,
0,
6,
100,
}
for _, v := range testData {
value := v
suite.T().Run(strconv.Itoa(value), func(t *testing.T) {
_, err := suite.t.Dial(context.Background(), value)
assert.Error(t, err)
assert.False(t, suite.t.IsKnownDC(value))
})
}
}
func (suite *TelegramTestSuite) TestDialToCorrectIPs() {
testData := map[int][]tgAddr{}
for i := 1; i <= 5; i++ {
testData[i] = []tgAddr{}
testData[i] = append(testData[i], productionV4Addresses[i-1]...)
testData[i] = append(testData[i], productionV6Addresses[i-1]...)
}
for i, v := range testData {
idx := i
addresses := v
suite.T().Run(strconv.Itoa(idx), func(t *testing.T) {
for _, addr := range addresses {
suite.dialerMock.
On("DialContext", mock.Anything, addr.network, addr.address).
Once().
Return((*net.TCPConn)(nil), io.EOF)
}
_, err := suite.t.Dial(context.Background(), idx)
assert.True(t, errors.Is(err, io.EOF))
assert.True(t, suite.t.IsKnownDC(idx))
})
}
}
func (suite *TelegramTestSuite) TestDialPreferIPRange() {
testData := map[string][]tgAddr{
"prefer-ipv4": {testV4Addresses[0][0], testV6Addresses[0][0]},
"prefer-ipv6": {testV6Addresses[0][0], testV4Addresses[0][0]},
"only-ipv4": {testV4Addresses[0][0]},
"only-ipv6": {testV6Addresses[0][0]},
}
for k, v := range testData {
name := k
addresses := v
suite.T().Run(name, func(t *testing.T) {
for _, addr := range addresses {
suite.dialerMock.
On("DialContext", mock.Anything, addr.network, addr.address).
Once().
Return((*net.TCPConn)(nil), io.EOF)
}
tg, _ := New(suite.dialerMock, name, true)
_, err := tg.Dial(context.Background(), 1)
assert.True(t, errors.Is(err, io.EOF))
})
}
}
func (suite *TelegramTestSuite) TestDialPreferIPPriority() {
testData := map[string]tgAddr{
"prefer-ipv4": productionV4Addresses[0][0],
"prefer-ipv6": productionV6Addresses[0][0],
}
for k, v := range testData {
name := k
addr := v
suite.T().Run(name, func(t *testing.T) {
conn := &net.TCPConn{}
suite.dialerMock.
On("DialContext", mock.Anything, addr.network, addr.address).
Once().
Return(conn, nil)
tg, _ := New(suite.dialerMock, name, false)
res, err := tg.Dial(context.Background(), 1)
assert.NoError(t, err)
assert.Equal(t, conn, res)
})
}
}
func (suite *TelegramTestSuite) TestUnknownPreferIP() {
_, err := New(suite.dialerMock, "xxx", false)
suite.Error(err)
}
func (suite *TelegramTestSuite) TestFallbackDC() {
dcs := make([]int, 10)
for i := 0; i < len(dcs); i++ {
dcs[i] = suite.t.GetFallbackDC()
}
for _, v := range dcs {
value := v
suite.T().Run(strconv.Itoa(value), func(t *testing.T) {
assert.True(t, suite.t.IsKnownDC(value))
})
}
}
func TestTelegram(t *testing.T) {
t.Parallel()
suite.Run(t, &TelegramTestSuite{})
}
+23 -15
View File
@@ -10,11 +10,11 @@ import (
"time" "time"
"github.com/9seconds/mtg/v2/essentials" "github.com/9seconds/mtg/v2/essentials"
"github.com/9seconds/mtg/v2/mtglib/internal/dc"
"github.com/9seconds/mtg/v2/mtglib/internal/faketls" "github.com/9seconds/mtg/v2/mtglib/internal/faketls"
"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record" "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
"github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2" "github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2"
"github.com/9seconds/mtg/v2/mtglib/internal/relay" "github.com/9seconds/mtg/v2/mtglib/internal/relay"
"github.com/9seconds/mtg/v2/mtglib/internal/telegram"
"github.com/panjf2000/ants/v2" "github.com/panjf2000/ants/v2"
) )
@@ -28,7 +28,7 @@ type Proxy struct {
tolerateTimeSkewness time.Duration tolerateTimeSkewness time.Duration
domainFrontingPort int domainFrontingPort int
workerPool *ants.PoolWithFunc workerPool *ants.PoolWithFunc
telegram *telegram.Telegram telegram *dc.Telegram
secret Secret secret Secret
network Network network Network
@@ -110,7 +110,7 @@ func (p *Proxy) Serve(listener net.Listener) error {
logger := p.logger.BindStr("ip", ipAddr.String()) logger := p.logger.BindStr("ip", ipAddr.String())
if !p.allowlist.Contains(ipAddr) { if !p.allowlist.Contains(ipAddr) {
conn.Close() conn.Close() //nolint: errcheck
logger.Info("ip was rejected by allowlist") logger.Info("ip was rejected by allowlist")
p.eventStream.Send(p.ctx, NewEventIPAllowlisted(ipAddr)) p.eventStream.Send(p.ctx, NewEventIPAllowlisted(ipAddr))
@@ -118,7 +118,7 @@ func (p *Proxy) Serve(listener net.Listener) error {
} }
if p.blocklist.Contains(ipAddr) { if p.blocklist.Contains(ipAddr) {
conn.Close() conn.Close() //nolint: errcheck
logger.Info("ip was blacklisted") logger.Info("ip was blacklisted")
p.eventStream.Send(p.ctx, NewEventIPBlocklisted(ipAddr)) p.eventStream.Send(p.ctx, NewEventIPBlocklisted(ipAddr))
@@ -219,23 +219,31 @@ func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error {
} }
func (p *Proxy) doTelegramCall(ctx *streamContext) error { func (p *Proxy) doTelegramCall(ctx *streamContext) error {
dc := ctx.dc dcid := ctx.dc
if p.allowFallbackOnUnknownDC && !p.telegram.IsKnownDC(dc) {
dc = p.telegram.GetFallbackDC()
ctx.logger = ctx.logger.BindInt("fallback_dc", dc)
addresses := p.telegram.GetAddresses(dcid)
if len(addresses) == 0 && p.allowFallbackOnUnknownDC {
ctx.logger = ctx.logger.BindInt("fallback_dc", dc.DefaultDC)
ctx.logger.Warning("unknown DC, fallbacks") ctx.logger.Warning("unknown DC, fallbacks")
addresses = p.telegram.GetAddresses(dc.DefaultDC)
} }
conn, err := p.telegram.Dial(ctx, dc) var conn essentials.Conn
var err error
for _, addr := range addresses {
conn, err = p.network.Dial(addr.Network, addr.Address)
if err == nil {
break
}
}
if err != nil { if err != nil {
return fmt.Errorf("cannot dial to Telegram: %w", err) return fmt.Errorf("no addresses to call: %w", err)
} }
encryptor, decryptor, err := obfuscated2.ServerHandshake(conn) encryptor, decryptor, err := obfuscated2.ServerHandshake(conn)
if err != nil { if err != nil {
conn.Close() conn.Close() //nolint: errcheck
return fmt.Errorf("cannot perform obfuscated2 handshake: %w", err) return fmt.Errorf("cannot perform obfuscated2 handshake: %w", err)
} }
@@ -292,9 +300,9 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) {
return nil, fmt.Errorf("invalid settings: %w", err) return nil, fmt.Errorf("invalid settings: %w", err)
} }
tg, err := telegram.New(opts.Network, opts.getPreferIP(), opts.UseTestDCs) tg, err := dc.New(opts.getPreferIP(), opts.DCOverrides)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot build telegram dialer: %w", err) return nil, fmt.Errorf("cannot build telegram dc fetcher: %w", err)
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@@ -315,7 +323,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) {
} }
pool, err := ants.NewPoolWithFunc(opts.getConcurrency(), pool, err := ants.NewPoolWithFunc(opts.getConcurrency(),
func(arg interface{}) { func(arg any) {
proxy.ServeConn(arg.(essentials.Conn)) //nolint: forcetypeassert proxy.ServeConn(arg.(essentials.Conn)) //nolint: forcetypeassert
}, },
ants.WithLogger(opts.getLogger("ants")), ants.WithLogger(opts.getLogger("ants")),
+8
View File
@@ -110,7 +110,15 @@ type ProxyOpts struct {
// Telegram-related projects. // Telegram-related projects.
// //
// This is an optional setting. // This is an optional setting.
//
// OBSOLETE and DEPRECATED. Ignored.
UseTestDCs bool UseTestDCs bool
// DCOverrides defines a set of IP addresses that should be used
// with a higher priority to those that are calculated somehow by mtg.
//
// This is an optional setting
DCOverrides map[int][]string
} }
func (p ProxyOpts) valid() error { func (p ProxyOpts) valid() error {
+2 -33
View File
@@ -1,9 +1,7 @@
package mtglib_test package mtglib_test
import ( import (
"context"
"crypto/tls" "crypto/tls"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@@ -19,9 +17,6 @@ import (
"github.com/9seconds/mtg/v2/logger" "github.com/9seconds/mtg/v2/logger"
"github.com/9seconds/mtg/v2/mtglib" "github.com/9seconds/mtg/v2/mtglib"
"github.com/9seconds/mtg/v2/network" "github.com/9seconds/mtg/v2/network"
"github.com/gotd/td/telegram"
"github.com/gotd/td/telegram/dcs"
"github.com/gotd/td/tg"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/yl2chen/cidranger" "github.com/yl2chen/cidranger"
) )
@@ -91,7 +86,7 @@ func (suite *ProxyTestSuite) SetupSuite() {
func (suite *ProxyTestSuite) TearDownSuite() { func (suite *ProxyTestSuite) TearDownSuite() {
if suite.listener != nil { if suite.listener != nil {
suite.listener.Close() suite.listener.Close() //nolint: errcheck
} }
if suite.p != nil { if suite.p != nil {
@@ -182,7 +177,7 @@ func (suite *ProxyTestSuite) TestHTTPSRequest() {
resp, err := client.Get(addr) //nolint: noctx resp, err := client.Get(addr) //nolint: noctx
suite.NoError(err) suite.NoError(err)
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
suite.Equal(http.StatusOK, resp.StatusCode) suite.Equal(http.StatusOK, resp.StatusCode)
@@ -199,32 +194,6 @@ func (suite *ProxyTestSuite) TestHTTPSRequest() {
suite.NotEmpty(jsonStruct.Headers.TraceID) suite.NotEmpty(jsonStruct.Headers.TraceID)
} }
func (suite *ProxyTestSuite) TestMakeRealRequest() {
secret, _ := hex.DecodeString(suite.opts.Secret.Hex())
resolver, err := dcs.MTProxyResolver(
suite.ProxyAddress(),
secret,
dcs.MTProxyOptions{},
)
suite.NoError(err)
tgClient := telegram.NewClient(telegram.TestAppID,
telegram.TestAppHash,
telegram.Options{
Resolver: resolver,
})
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
suite.NoError(tgClient.Run(ctx, func(ctx context.Context) error {
_, err := tg.NewClient(tgClient).HelpGetConfig(ctx)
suite.NoError(err)
return err //nolint: wrapcheck
}))
}
func TestProxy(t *testing.T) { func TestProxy(t *testing.T) {
t.Parallel() t.Parallel()
suite.Run(t, &ProxyTestSuite{}) suite.Run(t, &ProxyTestSuite{})
+1 -1
View File
@@ -74,7 +74,7 @@ func (s *Secret) Set(text string) error {
return fmt.Errorf("incorrect secret format: %w", err) return fmt.Errorf("incorrect secret format: %w", err)
} }
if len(decoded) < 2 { //nolint: gomnd // we need at least 1 byte here if len(decoded) < 2 { // we need at least 1 byte here
return fmt.Errorf("secret is truncated, length=%d", len(decoded)) return fmt.Errorf("secret is truncated, length=%d", len(decoded))
} }
+3 -3
View File
@@ -32,7 +32,7 @@ func (s *streamContext) Err() error {
return s.ctx.Err() //nolint: wrapcheck return s.ctx.Err() //nolint: wrapcheck
} }
func (s *streamContext) Value(key interface{}) interface{} { func (s *streamContext) Value(key any) any {
return s.ctx.Value(key) return s.ctx.Value(key)
} }
@@ -40,11 +40,11 @@ func (s *streamContext) Close() {
s.ctxCancel() s.ctxCancel()
if s.clientConn != nil { if s.clientConn != nil {
s.clientConn.Close() s.clientConn.Close() //nolint: errcheck
} }
if s.telegramConn != nil { if s.telegramConn != nil {
s.telegramConn.Close() s.telegramConn.Close() //nolint: errcheck
} }
} }
+1 -1
View File
@@ -24,7 +24,7 @@ func (suite *StreamContextTestSuite) SetupSuite() {
func (suite *StreamContextTestSuite) SetupTest() { func (suite *StreamContextTestSuite) SetupTest() {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
ctx = context.WithValue(ctx, "key", "value") //nolint: golint, staticcheck ctx = context.WithValue(ctx, "key", "value") //nolint: staticcheck
suite.ctxCancel = cancel suite.ctxCancel = cancel
suite.connMock = &testlib.EssentialsConnMock{} suite.connMock = &testlib.EssentialsConnMock{}
+2 -2
View File
@@ -56,7 +56,7 @@ func (c *circuitBreakerDialer) doClosed(ctx context.Context,
select { select {
case <-ctx.Done(): case <-ctx.Done():
if conn != nil { if conn != nil {
conn.Close() conn.Close() //nolint: errcheck
} }
return nil, ctx.Err() //nolint: wrapcheck return nil, ctx.Err() //nolint: wrapcheck
@@ -93,7 +93,7 @@ func (c *circuitBreakerDialer) doHalfOpened(ctx context.Context,
select { select {
case <-ctx.Done(): case <-ctx.Done():
if conn != nil { if conn != nil {
conn.Close() conn.Close() //nolint: errcheck
} }
return nil, ctx.Err() //nolint: wrapcheck return nil, ctx.Err() //nolint: wrapcheck
+8 -11
View File
@@ -52,17 +52,9 @@ func (suite *CircuitBreakerTestSuite) TestMultipleRunsOk() {
Return(suite.connMock, nil) Return(suite.connMock, nil)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(5)
go func() {
wg.Wait()
suite.ctxCancel()
}()
for i := 0; i < 5; i++ {
go func() {
defer wg.Done()
for range 5 {
wg.Go(func() {
conn, err := suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1") conn, err := suite.d.DialContext(suite.ctx, "tcp", "127.0.0.1")
suite.mutex.Lock() suite.mutex.Lock()
@@ -70,9 +62,14 @@ func (suite *CircuitBreakerTestSuite) TestMultipleRunsOk() {
suite.NoError(err) suite.NoError(err)
suite.Equal("127.0.0.1:3128", conn.RemoteAddr().String()) suite.Equal("127.0.0.1:3128", conn.RemoteAddr().String())
}() })
} }
go func() {
wg.Wait()
suite.ctxCancel()
}()
suite.Eventually(func() bool { suite.Eventually(func() bool {
_, ok := <-suite.ctx.Done() _, ok := <-suite.ctx.Done()
+1 -1
View File
@@ -31,7 +31,7 @@ func (d *defaultDialer) DialContext(ctx context.Context, network, address string
// we do not need to call to end user. End users call us. // we do not need to call to end user. End users call us.
if err := SetServerSocketOptions(conn, 0); err != nil { if err := SetServerSocketOptions(conn, 0); err != nil {
conn.Close() conn.Close() //nolint: errcheck
return nil, fmt.Errorf("cannot set socket options: %w", err) return nil, fmt.Errorf("cannot set socket options: %w", err)
} }
+2 -2
View File
@@ -51,7 +51,7 @@ func (suite *DefaultDialerTestSuite) TestConnectOk() {
suite.NoError(err) suite.NoError(err)
suite.NotNil(conn) suite.NotNil(conn)
conn.Close() conn.Close() //nolint: errcheck
} }
func (suite *DefaultDialerTestSuite) TestHTTPRequest() { func (suite *DefaultDialerTestSuite) TestHTTPRequest() {
@@ -59,7 +59,7 @@ func (suite *DefaultDialerTestSuite) TestHTTPRequest() {
resp, err := httpClient.Get(suite.MakeURL("/get")) //nolint: noctx resp, err := httpClient.Get(suite.MakeURL("/get")) //nolint: noctx
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
} }
suite.NoError(err) suite.NoError(err)
+1 -1
View File
@@ -63,7 +63,7 @@ const (
// DefaultDOHHostname defines a default IP address for DOH host. Since mtg is // DefaultDOHHostname defines a default IP address for DOH host. Since mtg is
// simple, please pass IP address here. We do not have bootstrap servers here // simple, please pass IP address here. We do not have bootstrap servers here
// embedded. // embedded.
DefaultDOHHostname = "9.9.9.9" DefaultDOHHostname = "1.1.1.1"
// DNSTimeout defines a timeout for DNS queries. // DNSTimeout defines a timeout for DNS queries.
DNSTimeout = 5 * time.Second DNSTimeout = 5 * time.Second
+1 -1
View File
@@ -78,7 +78,7 @@ func (suite *Socks5ServerTestSuite) SetupSuite() {
} }
func (suite *Socks5ServerTestSuite) TearDownSuite() { func (suite *Socks5ServerTestSuite) TearDownSuite() {
suite.socks5Listener.Close() suite.socks5Listener.Close() //nolint: errcheck
} }
func (suite *Socks5ServerTestSuite) MakeSocks5URL(user, password string) *url.URL { func (suite *Socks5ServerTestSuite) MakeSocks5URL(user, password string) *url.URL {
+2 -2
View File
@@ -3,7 +3,7 @@ package network
import ( import (
"context" "context"
"fmt" "fmt"
"math/rand" "math/rand/v2"
"net/url" "net/url"
"github.com/9seconds/mtg/v2/essentials" "github.com/9seconds/mtg/v2/essentials"
@@ -19,7 +19,7 @@ func (l loadBalancedSocks5Dialer) Dial(network, address string) (essentials.Conn
func (l loadBalancedSocks5Dialer) DialContext(ctx context.Context, network, address string) (essentials.Conn, error) { func (l loadBalancedSocks5Dialer) DialContext(ctx context.Context, network, address string) (essentials.Conn, error) {
length := len(l.dialers) length := len(l.dialers)
start := rand.Intn(length) start := rand.IntN(length)
moved := false moved := false
for i := start; i != start || !moved; i = (i + 1) % length { for i := start; i != start || !moved; i = (i + 1) % length {
+2 -2
View File
@@ -64,7 +64,7 @@ func (suite *LoadBalancedSocks5TestSuite) TestCannotDial() {
}) })
suite.NoError(err) suite.NoError(err)
for i := 0; i < network.ProxyDialerOpenThreshold*2; i++ { for range network.ProxyDialerOpenThreshold * 2 {
_, err = lbDialer.Dial("tcp", "127.1.1.1:80") _, err = lbDialer.Dial("tcp", "127.1.1.1:80")
suite.True(errors.Is(err, network.ErrCannotDialWithAllProxies)) suite.True(errors.Is(err, network.ErrCannotDialWithAllProxies))
} }
@@ -75,7 +75,7 @@ func (suite *LoadBalancedSocks5TestSuite) TestCannotDial() {
func (suite *LoadBalancedSocks5TestSuite) TestDialOk() { func (suite *LoadBalancedSocks5TestSuite) TestDialOk() {
resp, err := suite.httpClient.Get(suite.MakeURL("/get")) //nolint: noctx resp, err := suite.httpClient.Get(suite.MakeURL("/get")) //nolint: noctx
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
} }
suite.NoError(err) suite.NoError(err)
+5 -13
View File
@@ -3,7 +3,7 @@ package network
import ( import (
"context" "context"
"fmt" "fmt"
"math/rand" "math/rand/v2"
"net" "net"
"net/http" "net/http"
"sync" "sync"
@@ -81,32 +81,24 @@ func (n *network) dnsResolve(protocol, address string) ([]string, error) {
switch protocol { switch protocol {
case "tcp", "tcp4": case "tcp", "tcp4":
wg.Add(1) wg.Go(func() {
go func() {
defer wg.Done()
resolved := n.dns.LookupA(address) resolved := n.dns.LookupA(address)
mutex.Lock() mutex.Lock()
ips = append(ips, resolved...) ips = append(ips, resolved...)
mutex.Unlock() mutex.Unlock()
}() })
} }
switch protocol { switch protocol {
case "tcp", "tcp6": case "tcp", "tcp6":
wg.Add(1) wg.Go(func() {
go func() {
defer wg.Done()
resolved := n.dns.LookupAAAA(address) resolved := n.dns.LookupAAAA(address)
mutex.Lock() mutex.Lock()
ips = append(ips, resolved...) ips = append(ips, resolved...)
mutex.Unlock() mutex.Unlock()
}() })
} }
wg.Wait() wg.Wait()
+2 -2
View File
@@ -34,7 +34,7 @@ func (suite *NetworkTestSuite) TestLocalHTTPRequest() {
resp, err := client.Get(suite.httpServer.URL + "/headers") //nolint: noctx resp, err := client.Get(suite.httpServer.URL + "/headers") //nolint: noctx
suite.NoError(err) suite.NoError(err)
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
data, err := io.ReadAll(resp.Body) data, err := io.ReadAll(resp.Body)
suite.NoError(err) suite.NoError(err)
@@ -59,7 +59,7 @@ func (suite *NetworkTestSuite) TestRealHTTPRequest() {
resp, err := client.Get("https://httpbin.org/headers") //nolint: noctx resp, err := client.Get("https://httpbin.org/headers") //nolint: noctx
suite.NoError(err) suite.NoError(err)
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
data, err := io.ReadAll(resp.Body) data, err := io.ReadAll(resp.Body)
suite.NoError(err) suite.NoError(err)
+1 -1
View File
@@ -16,7 +16,7 @@ func newProxyDialer(baseDialer Dialer, proxyURL *url.URL) Dialer {
) )
if param := params.Get("open_threshold"); param != "" { if param := params.Get("open_threshold"); param != "" {
if intNum, err := strconv.ParseUint(param, 10, 32); err == nil { //nolint: gomnd if intNum, err := strconv.ParseUint(param, 10, 32); err == nil {
openThreshold = uint32(intNum) openThreshold = uint32(intNum)
} }
} }
+2 -2
View File
@@ -14,14 +14,14 @@ func setSocketReuseAddrPort(conn syscall.RawConn) error {
var err error var err error
conn.Control(func(fd uintptr) { //nolint: errcheck conn.Control(func(fd uintptr) { //nolint: errcheck
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) //nolint: nosnakecase err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
if err != nil { if err != nil {
err = fmt.Errorf("cannot set SO_REUSEADDR: %w", err) err = fmt.Errorf("cannot set SO_REUSEADDR: %w", err)
return return
} }
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1) //nolint: nosnakecase err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
if err != nil { if err != nil {
err = fmt.Errorf("cannot set SO_REUSEPORT: %w", err) err = fmt.Errorf("cannot set SO_REUSEPORT: %w", err)
} }
+2 -2
View File
@@ -36,13 +36,13 @@ func (s socks5Dialer) DialContext(ctx context.Context, network, address string)
} }
if err := s.handshake(conn); err != nil { if err := s.handshake(conn); err != nil {
conn.Close() conn.Close() //nolint: errcheck
return nil, fmt.Errorf("cannot perform a handshake: %w", err) return nil, fmt.Errorf("cannot perform a handshake: %w", err)
} }
if err := s.connect(conn, address); err != nil { if err := s.connect(conn, address); err != nil {
conn.Close() conn.Close() //nolint: errcheck
return nil, fmt.Errorf("cannot connect to a destination host %s: %w", address, err) return nil, fmt.Errorf("cannot connect to a destination host %s: %w", address, err)
} }
+2 -2
View File
@@ -35,7 +35,7 @@ func (suite *Socks5TestSuite) TestRequestFailed() {
resp, err := httpClient.Get(suite.MakeURL("/get")) //nolint: noctx resp, err := httpClient.Get(suite.MakeURL("/get")) //nolint: noctx
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
} }
suite.Error(err) suite.Error(err)
@@ -48,7 +48,7 @@ func (suite *Socks5TestSuite) TestRequestOk() {
resp, err := httpClient.Get(suite.MakeURL("/get")) //nolint: noctx resp, err := httpClient.Get(suite.MakeURL("/get")) //nolint: noctx
if err == nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
} }
suite.NoError(err) suite.NoError(err)
+1 -1
View File
@@ -3,7 +3,7 @@ package stats
import "sync" import "sync"
var streamInfoPool = sync.Pool{ var streamInfoPool = sync.Pool{
New: func() interface{} { New: func() any {
return &streamInfo{ return &streamInfo{
tags: make(map[string]string), tags: make(map[string]string),
} }
+2 -2
View File
@@ -30,7 +30,7 @@ func (suite *PrometheusTestSuite) Get() (string, error) {
return "", err //nolint: wrapcheck return "", err //nolint: wrapcheck
} }
defer resp.Body.Close() defer resp.Body.Close() //nolint: errcheck
data, err := io.ReadAll(resp.Body) data, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
@@ -51,7 +51,7 @@ func (suite *PrometheusTestSuite) SetupTest() {
func (suite *PrometheusTestSuite) TearDownTest() { func (suite *PrometheusTestSuite) TearDownTest() {
suite.prometheus.Shutdown() suite.prometheus.Shutdown()
suite.NoError(suite.factory.Close()) suite.NoError(suite.factory.Close())
suite.httpListener.Close() suite.httpListener.Close() //nolint: errcheck
} }
func (suite *PrometheusTestSuite) TestTelegramPath() { func (suite *PrometheusTestSuite) TestTelegramPath() {
+2 -2
View File
@@ -100,8 +100,8 @@ func (suite *StatsdTestSuite) SetupTest() {
func (suite *StatsdTestSuite) TearDownTest() { func (suite *StatsdTestSuite) TearDownTest() {
suite.statsd.Shutdown() suite.statsd.Shutdown()
suite.factory.Close() suite.factory.Close() //nolint: errcheck
suite.statsdServer.Close() suite.statsdServer.Close() //nolint: errcheck
} }
func (suite *StatsdTestSuite) TestTelegramPath() { func (suite *StatsdTestSuite) TestTelegramPath() {