Compare commits

..

46 Commits

Author SHA1 Message Date
fatedier
8fb99ef7a9 Merge pull request #3348 from fatedier/dev
bump version
2023-03-08 11:40:31 +08:00
fatedier
968ba4d3a1 update release notes (#3347) 2023-03-08 11:19:52 +08:00
fatedier
862b1642ba tcpmux: support authentication (#3345) 2023-03-07 19:53:32 +08:00
fatedier
54eb704650 e2e: upgrade to ginkgo v2 (#3335) 2023-02-27 14:44:16 +08:00
fatedier
8c6303c1e5 web/frpc: support more info (#3334) 2023-02-26 02:54:53 +08:00
fatedier
871511ba52 sponsor: update (#3330) 2023-02-23 13:22:05 +08:00
fatedier
cb6d7ba7f9 sponsor: add pic 2023-02-23 12:05:47 +08:00
fatedier
31f40aa913 web/frpc&frps: support dark mode (#3327) 2023-02-22 14:15:21 +08:00
fatedier
2f59e967a0 web/frps: more info (#3326) 2023-02-22 00:39:56 +08:00
fatedier
fe8374e99b web/frpc: upgrade vue and element-plus (#3322) 2023-02-20 23:52:55 +08:00
fatedier
24f0b3afa5 web/frps: upgrade vue and element-plus (#3310) 2023-02-16 02:45:48 +08:00
fatedier
39941117b6 support windows arm64 2023-02-10 13:25:04 +08:00
fatedier
6a1f9ad893 update README.md 2023-02-10 01:15:28 +08:00
fatedier
88e74ff24d Merge pull request #3300 from fatedier/dev
sync
2023-02-10 01:12:00 +08:00
fatedier
18ab58eb25 fix incompatible problem for bandwidth_limit_mode 2023-02-10 00:56:20 +08:00
fatedier
534dc99d55 Merge pull request #3299 from fatedier/dev
sync
2023-02-09 23:06:14 +08:00
fatedier
fa0593ae2c add release notes 2023-02-09 22:52:48 +08:00
fatedier
89fff7d11d e2e: add test case for bandwidth_limit_mode server (#3295) 2023-02-09 01:11:00 +08:00
fatedier
38d42dbe4b release: prepare for 0.47.0 (#3296) 2023-02-09 00:59:40 +08:00
Craig O'Donnell
aa31d7ad0b support bandwidth_limit set by server plugin (#3271)
* support bandwidth_limit set by server plugin

* limiter at proxy level

* bandwidth_limit_mode

* updates tests for bandwidth_limit_mode default

* bandwidth_limit_mode as string

* add checkForSrv for bandwidth_limit_mode

* bandwidth_limit flags for sub cmds

* gci write
2023-02-09 00:38:36 +08:00
fatedier
113e3b0b0d revert random change (#3292) 2023-02-06 15:55:33 +08:00
fatedier
100148d925 support go1.20 (#3287) 2023-02-05 20:52:36 +08:00
fatedier
6b3daffaf0 upgrade quic-go and change import path (#3286) 2023-02-02 20:20:17 +08:00
fatedier
5e17bc7bf1 remove sponsors 2023-02-02 12:03:20 +08:00
Gerhard Tan
b1b8d9a82b frpc: do a graceful close for quic protocol at exit (#3282) 2023-02-01 13:09:31 +08:00
fatedier
24c7d1d9e2 clean Release.md 2023-02-01 11:19:31 +08:00
Gerhard Tan
d205c26480 Bugfix: add ipv6 parsing for custom DNS server (#3266) 2023-01-29 23:54:40 +08:00
Richard Kovacs
0eecab06c1 Fix basic example server to join in readme (#3209) 2023-01-15 19:15:48 +08:00
bobo liu
ad3548d332 optimize: GetAuthKey (#3254) 2023-01-14 21:43:26 +08:00
fatedier
595aba5a9b Merge pull request #3248 from fatedier/dev
bump version
2023-01-10 10:26:56 +08:00
fatedier
679992db25 update version (#3247) 2023-01-10 10:24:44 +08:00
fatedier
5cfbb976f4 pkg/util/net: fix quic streams leak (#3246) 2023-01-10 10:19:37 +08:00
Craig O'Donnell
b03f0ad1e6 fix: incorrect op for newWorkConn (#3244)
(cherry picked from commit 53b6bbf0b14ab632dc89416d7fffa9b1d0887c0a)
2023-01-09 10:34:09 +08:00
0x7fff
804f2910fd refactor: ifelse (#3224) 2022-12-22 17:55:06 +08:00
fatedier
a4189ba474 Merge branch 'dev' 2022-12-18 19:27:22 +08:00
fatedier
e2d28d9929 update goreleaser.yaml 2022-12-18 19:18:09 +08:00
fatedier
9ec84f8143 Merge pull request #3218 from fatedier/dev
release v0.46.0
2022-12-18 18:46:52 +08:00
fatedier
7678938c08 support quic options (#3211) 2022-12-18 18:43:42 +08:00
0x7fff
b2e3946800 feat: release (#3205)
Co-authored-by: blizard863 <760076784@qq.com>
2022-12-13 22:37:06 +08:00
0x7fff
af0b7939a7 feat: odic refine (#3202)
Co-authored-by: Matt Feury <mattfeury@gmail.com>
2022-12-12 15:10:38 +08:00
fatedier
2f66dc3e99 support protocol quic between frpc and frps (#3198) 2022-12-12 11:04:10 +08:00
Matt Feury
649df8827c feat: Support OIDC scope parameter (#3192) 2022-12-09 11:46:34 +08:00
Ashish Kurmi
da51adc276 Set least privileged token permission for GitHub Actions (#3155)
Signed-off-by: Ashish Kurmi <akurmi@stepsecurity.io>
2022-10-31 15:46:46 +08:00
fatedier
e5af37bc8c upgrade github actions version (#3150) 2022-10-27 14:22:14 +08:00
fatedier
8ab474cc97 remove unsupported platform (#3148) 2022-10-27 10:22:47 +08:00
fatedier
e8c8d5903a remove unsupported platform 2022-10-27 10:19:30 +08:00
183 changed files with 8660 additions and 13988 deletions

View File

@@ -2,7 +2,7 @@ version: 2
jobs: jobs:
go-version-latest: go-version-latest:
docker: docker:
- image: cimg/go:1.19-node - image: cimg/go:1.20-node
resource_class: large resource_class: large
steps: steps:
- checkout - checkout
@@ -10,7 +10,7 @@ jobs:
- run: make alltest - run: make alltest
go-version-last: go-version-last:
docker: docker:
- image: cimg/go:1.18-node - image: cimg/go:1.19-node
resource_class: large resource_class: large
steps: steps:
- checkout - checkout

View File

@@ -9,6 +9,9 @@ on:
description: 'Image tag' description: 'Image tag'
required: true required: true
default: 'test' default: 'test'
permissions:
contents: read
jobs: jobs:
image: image:
name: Build Image from Dockerfile and binaries name: Build Image from Dockerfile and binaries
@@ -16,15 +19,15 @@ jobs:
steps: steps:
# environment # environment
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: '0' fetch-depth: '0'
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v2
# get image tag name # get image tag name
- name: Get Image Tag Name - name: Get Image Tag Name
@@ -35,13 +38,13 @@ jobs:
echo "TAG_NAME=${{ github.event.inputs.tag }}" >> $GITHUB_ENV echo "TAG_NAME=${{ github.event.inputs.tag }}" >> $GITHUB_ENV
fi fi
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }} password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to the GPR - name: Login to the GPR
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
@@ -58,22 +61,22 @@ jobs:
echo "TAG_FRPS_GPR=ghcr.io/fatedier/frps:${{ env.TAG_NAME }}" >> $GITHUB_ENV echo "TAG_FRPS_GPR=ghcr.io/fatedier/frps:${{ env.TAG_NAME }}" >> $GITHUB_ENV
- name: Build and push frpc - name: Build and push frpc
uses: docker/build-push-action@v2 uses: docker/build-push-action@v3
with: with:
context: . context: .
file: ./dockerfiles/Dockerfile-for-frpc file: ./dockerfiles/Dockerfile-for-frpc
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/riscv64,linux/s390x platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
push: true push: true
tags: | tags: |
${{ env.TAG_FRPC }} ${{ env.TAG_FRPC }}
${{ env.TAG_FRPC_GPR }} ${{ env.TAG_FRPC_GPR }}
- name: Build and push frps - name: Build and push frps
uses: docker/build-push-action@v2 uses: docker/build-push-action@v3
with: with:
context: . context: .
file: ./dockerfiles/Dockerfile-for-frps file: ./dockerfiles/Dockerfile-for-frps
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/riscv64,linux/s390x platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
push: true push: true
tags: | tags: |
${{ env.TAG_FRPS }} ${{ env.TAG_FRPS }}

View File

@@ -16,13 +16,13 @@ jobs:
steps: steps:
- uses: actions/setup-go@v3 - uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v3
with: with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: v1.49.0 version: v1.51
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0 # args: --issues-exit-code=0

View File

@@ -8,25 +8,21 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- run: |
# https://github.com/actions/setup-go/issues/107
cp -f `which go` /usr/bin/go
- name: Make All - name: Make All
run: | run: |
./package.sh ./package.sh
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2 uses: goreleaser/goreleaser-action@v3
with: with:
version: latest version: latest
args: release --rm-dist --release-notes=./Release.md args: release --rm-dist --release-notes=./Release.md

View File

@@ -8,11 +8,17 @@ on:
description: 'In debug mod' description: 'In debug mod'
required: false required: false
default: 'false' default: 'false'
permissions:
contents: read
jobs: jobs:
stale: stale:
permissions:
issues: write # for actions/stale to close stale issues
pull-requests: write # for actions/stale to close stale PRs
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v5 - uses: actions/stale@v6
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Issues go stale after 30d of inactivity. Stale issues rot after an additional 7d of inactivity and eventually close.' stale-issue-message: 'Issues go stale after 30d of inactivity. Stale issues rot after an additional 7d of inactivity and eventually close.'

1
.gitignore vendored
View File

@@ -31,6 +31,7 @@ test/bin/
vendor/ vendor/
dist/ dist/
.idea/ .idea/
.vscode/
# Cache # Cache
*.swp *.swp

View File

@@ -1,6 +1,5 @@
service: service:
# When updating this, also update the version stored in docker/build-tools/Dockerfile in the istio/tools repo. golangci-lint-version: 1.51.x # use the fixed version to not introduce new linters unexpectedly
golangci-lint-version: 1.49.x # use the fixed version to not introduce new linters unexpectedly
run: run:
concurrency: 4 concurrency: 4
@@ -127,6 +126,11 @@ issues:
- errcheck - errcheck
- maligned - maligned
# keep it until we only support go1.20
- linters:
- staticcheck
text: "SA1019: rand.Seed has been deprecated"
# Independently from option `exclude` we use default exclude patterns, # Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all # it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`. # excluded by default patterns execute `golangci-lint run --help`.

View File

@@ -16,6 +16,9 @@ file:
fmt: fmt:
go fmt ./... go fmt ./...
fmt-more:
gofumpt -l -w .
vet: vet:
go vet ./... go vet ./...

View File

@@ -2,7 +2,7 @@ export PATH := $(GOPATH)/bin:$(PATH)
export GO111MODULE=on export GO111MODULE=on
LDFLAGS := -s -w LDFLAGS := -s -w
os-archs=darwin:amd64 darwin:arm64 freebsd:386 freebsd:amd64 linux:386 linux:amd64 linux:arm linux:arm64 windows:386 windows:amd64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 os-archs=darwin:amd64 darwin:arm64 freebsd:386 freebsd:amd64 linux:386 linux:amd64 linux:arm linux:arm64 windows:386 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64
all: build all: build
@@ -23,3 +23,5 @@ app:
@mv ./release/frps_windows_386 ./release/frps_windows_386.exe @mv ./release/frps_windows_386 ./release/frps_windows_386.exe
@mv ./release/frpc_windows_amd64 ./release/frpc_windows_amd64.exe @mv ./release/frpc_windows_amd64 ./release/frpc_windows_amd64.exe
@mv ./release/frps_windows_amd64 ./release/frps_windows_amd64.exe @mv ./release/frps_windows_amd64 ./release/frps_windows_amd64.exe
@mv ./release/frpc_windows_arm64 ./release/frpc_windows_arm64.exe
@mv ./release/frps_windows_arm64 ./release/frps_windows_arm64.exe

129
README.md
View File

@@ -8,24 +8,23 @@
<h3 align="center">Gold Sponsors</h3> <h3 align="center">Gold Sponsors</h3>
<!--gold sponsors start--> <!--gold sponsors start-->
<p align="center"> <p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank"> <a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="300px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png"> <img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
</a>
<a>&nbsp</a>
<a href="https://asocks.com/c/vDu6Dk" target="_blank">
<img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_asocks.jpg">
</a> </a>
</p> </p>
<!--gold sponsors end--> <!--gold sponsors end-->
<h3 align="center">Silver Sponsors</h3>
* Sakura Frp - 欢迎点击 "加入我们"
## What is frp? ## What is frp?
frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it supports **TCP** and **UDP**, as well as **HTTP** and **HTTPS** protocols, where requests can be forwarded to internal services by domain name. frp is a fast reverse proxy that allows you to expose a local server located behind a NAT or firewall to the Internet. It currently supports **TCP** and **UDP**, as well as **HTTP** and **HTTPS** protocols, enabling requests to be forwarded to internal services via domain name.
frp also has a P2P connect mode. frp also offers a P2P connect mode.
## Table of Contents ## Table of Contents
@@ -34,12 +33,12 @@ frp also has a P2P connect mode.
* [Development Status](#development-status) * [Development Status](#development-status)
* [Architecture](#architecture) * [Architecture](#architecture)
* [Example Usage](#example-usage) * [Example Usage](#example-usage)
* [Access your computer in LAN by SSH](#access-your-computer-in-lan-by-ssh) * [Access your computer in a LAN network via SSH](#access-your-computer-in-a-lan-network-via-ssh)
* [Visit your web service in LAN by custom domains](#visit-your-web-service-in-lan-by-custom-domains) * [Accessing Internal Web Services with Custom Domains in LAN](#accessing-internal-web-services-with-custom-domains-in-lan)
* [Forward DNS query request](#forward-dns-query-request) * [Forward DNS query requests](#forward-dns-query-requests)
* [Forward Unix domain socket](#forward-unix-domain-socket) * [Forward Unix Domain Socket](#forward-unix-domain-socket)
* [Expose a simple HTTP file server](#expose-a-simple-http-file-server) * [Expose a simple HTTP file server](#expose-a-simple-http-file-server)
* [Enable HTTPS for local HTTP(S) service](#enable-https-for-local-https-service) * [Enable HTTPS for a local HTTP(S) service](#enable-https-for-a-local-https-service)
* [Expose your service privately](#expose-your-service-privately) * [Expose your service privately](#expose-your-service-privately)
* [P2P Mode](#p2p-mode) * [P2P Mode](#p2p-mode)
* [Features](#features) * [Features](#features)
@@ -63,6 +62,7 @@ frp also has a P2P connect mode.
* [For Each Proxy](#for-each-proxy) * [For Each Proxy](#for-each-proxy)
* [TCP Stream Multiplexing](#tcp-stream-multiplexing) * [TCP Stream Multiplexing](#tcp-stream-multiplexing)
* [Support KCP Protocol](#support-kcp-protocol) * [Support KCP Protocol](#support-kcp-protocol)
* [Support QUIC Protocol](#support-quic-protocol)
* [Connection Pooling](#connection-pooling) * [Connection Pooling](#connection-pooling)
* [Load balancing](#load-balancing) * [Load balancing](#load-balancing)
* [Service Health Check](#service-health-check) * [Service Health Check](#service-health-check)
@@ -89,11 +89,11 @@ frp also has a P2P connect mode.
## Development Status ## Development Status
frp is under development. Try the latest release version in the `master` branch, or use the `dev` branch for the version in development. frp is currently under development. You can try the latest release version in the `master` branch, or use the `dev` branch to access the version currently in development.
We are working on v2 version and trying to do some code refactor and improvements. It won't be compatible with v1. We are currently working on version 2 and attempting to perform some code refactoring and improvements. However, please note that it will not be compatible with version 1.
We will switch v0 to v1 at the right time and only accept bug fixes and improvements instead of big feature requirements. We will transition from version 0 to version 1 at the appropriate time and will only accept bug fixes and improvements, rather than big feature requests.
## Architecture ## Architecture
@@ -101,15 +101,15 @@ We will switch v0 to v1 at the right time and only accept bug fixes and improvem
## Example Usage ## Example Usage
Firstly, download the latest programs from [Release](https://github.com/fatedier/frp/releases) page according to your operating system and architecture. To begin, download the latest program for your operating system and architecture from the [Release](https://github.com/fatedier/frp/releases) page.
Put `frps` and `frps.ini` onto your server A with public IP. Next, place the `frps` binary and `frps.ini` configuration file on Server A, which has a public IP address.
Put `frpc` and `frpc.ini` onto your server B in LAN (that can't be connected from public Internet). Finally, place the `frpc` binary and `frpc.ini` configuration file on Server B, which is located on a LAN that cannot be directly accessed from the public internet.
### Access your computer in LAN by SSH ### Access your computer in a LAN network via SSH
1. Modify `frps.ini` on server A and set the `bind_port` to be connected to frp clients: 1. Modify `frps.ini` on server A by setting the `bind_port` for frp clients to connect to:
```ini ```ini
# frps.ini # frps.ini
@@ -121,7 +121,7 @@ Put `frpc` and `frpc.ini` onto your server B in LAN (that can't be connected fro
`./frps -c ./frps.ini` `./frps -c ./frps.ini`
3. On server B, modify `frpc.ini` to put in your `frps` server public IP as `server_addr` field: 3. Modify `frpc.ini` on server B and set the `server_addr` field to the public IP address of your frps server:
```ini ```ini
# frpc.ini # frpc.ini
@@ -136,23 +136,23 @@ Put `frpc` and `frpc.ini` onto your server B in LAN (that can't be connected fro
remote_port = 6000 remote_port = 6000
``` ```
Note that `local_port` (listened on client) and `remote_port` (exposed on server) are for traffic goes in/out the frp system, whereas `server_port` is used between frps. Note that the `local_port` (listened on the client) and `remote_port` (exposed on the server) are used for traffic going in and out of the frp system, while the `server_port` is used for communication between frps and frpc.
4. Start `frpc` on server B: 4. Start `frpc` on server B:
`./frpc -c ./frpc.ini` `./frpc -c ./frpc.ini`
5. From another machine, SSH to server B like this (assuming that username is `test`): 5. To access server B from another machine through server A via SSH (assuming the username is `test`), use the following command:
`ssh -oPort=6000 test@x.x.x.x` `ssh -oPort=6000 test@x.x.x.x`
### Visit your web service in LAN by custom domains ### Accessing Internal Web Services with Custom Domains in LAN
Sometimes we want to expose a local web service behind a NAT network to others for testing with your own domain name and unfortunately we can't resolve a domain name to a local IP. Sometimes we need to expose a local web service behind a NAT network to others for testing purposes with our own domain name.
However, we can expose an HTTP(S) service using frp. Unfortunately, we cannot resolve a domain name to a local IP. However, we can use frp to expose an HTTP(S) service.
1. Modify `frps.ini`, set the vhost HTTP port to 8080: 1. Modify `frps.ini` and set the HTTP port for vhost to 8080:
```ini ```ini
# frps.ini # frps.ini
@@ -165,7 +165,7 @@ However, we can expose an HTTP(S) service using frp.
`./frps -c ./frps.ini` `./frps -c ./frps.ini`
3. Modify `frpc.ini` and set `server_addr` to the IP address of the remote frps server. The `local_port` is the port of your web service: 3. Modify `frpc.ini` and set `server_addr` to the IP address of the remote frps server. Specify the `local_port` of your web service:
```ini ```ini
# frpc.ini # frpc.ini
@@ -183,11 +183,11 @@ However, we can expose an HTTP(S) service using frp.
`./frpc -c ./frpc.ini` `./frpc -c ./frpc.ini`
5. Resolve A record of `www.example.com` to the public IP of the remote frps server or CNAME record to your origin domain. 5. Map the A record of `www.example.com` to either the public IP of the remote frps server or a CNAME record pointing to your original domain.
6. Now visit your local web service using url `http://www.example.com:8080`. 6. Visit your local web service using url `http://www.example.com:8080`.
### Forward DNS query request ### Forward DNS query requests
1. Modify `frps.ini`: 1. Modify `frps.ini`:
@@ -201,7 +201,7 @@ However, we can expose an HTTP(S) service using frp.
`./frps -c ./frps.ini` `./frps -c ./frps.ini`
3. Modify `frpc.ini` and set `server_addr` to the IP address of the remote frps server, forward DNS query request to Google Public DNS server `8.8.8.8:53`: 3. Modify `frpc.ini` and set `server_addr` to the IP address of the remote frps server. Forward DNS query requests to the Google Public DNS server `8.8.8.8:53`:
```ini ```ini
# frpc.ini # frpc.ini
@@ -220,17 +220,17 @@ However, we can expose an HTTP(S) service using frp.
`./frpc -c ./frpc.ini` `./frpc -c ./frpc.ini`
5. Test DNS resolution using `dig` command: 5. Test DNS resolution using the `dig` command:
`dig @x.x.x.x -p 6000 www.google.com` `dig @x.x.x.x -p 6000 www.google.com`
### Forward Unix domain socket ### Forward Unix Domain Socket
Expose a Unix domain socket (e.g. the Docker daemon socket) as TCP. Expose a Unix domain socket (e.g. the Docker daemon socket) as TCP.
Configure `frps` same as above. Configure `frps` as above.
1. Start `frpc` with configuration: 1. Start `frpc` with the following configuration:
```ini ```ini
# frpc.ini # frpc.ini
@@ -245,17 +245,17 @@ Configure `frps` same as above.
plugin_unix_path = /var/run/docker.sock plugin_unix_path = /var/run/docker.sock
``` ```
2. Test: Get Docker version using `curl`: 2. Test the configuration by getting the docker version using `curl`:
`curl http://x.x.x.x:6000/version` `curl http://x.x.x.x:6000/version`
### Expose a simple HTTP file server ### Expose a simple HTTP file server
Browser your files stored in the LAN, from public Internet. Expose a simple HTTP file server to access files stored in the LAN from the public Internet.
Configure `frps` same as above. Configure `frps` as described above, then:
1. Start `frpc` with configuration: 1. Start `frpc` with the following configuration:
```ini ```ini
# frpc.ini # frpc.ini
@@ -273,13 +273,13 @@ Configure `frps` same as above.
plugin_http_passwd = abc plugin_http_passwd = abc
``` ```
2. Visit `http://x.x.x.x:6000/static/` from your browser and specify correct user and password to view files in `/tmp/files` on the `frpc` machine. 2. Visit `http://x.x.x.x:6000/static/` from your browser and specify correct username and password to view files in `/tmp/files` on the `frpc` machine.
### Enable HTTPS for local HTTP(S) service ### Enable HTTPS for a local HTTP(S) service
You may substitute `https2https` for the plugin, and point the `plugin_local_addr` to a HTTPS endpoint. You may substitute `https2https` for the plugin, and point the `plugin_local_addr` to a HTTPS endpoint.
1. Start `frpc` with configuration: 1. Start `frpc` with the following configuration:
```ini ```ini
# frpc.ini # frpc.ini
@@ -303,7 +303,7 @@ You may substitute `https2https` for the plugin, and point the `plugin_local_add
### Expose your service privately ### Expose your service privately
Some services will be at risk if exposed directly to the public network. With **STCP** (secret TCP) mode, a preshared key is needed to access the service from another client. To mitigate risks associated with exposing certain services directly to the public network, STCP (Secret TCP) mode requires a preshared key to be used for access to the service from other clients.
Configure `frps` same as above. Configure `frps` same as above.
@@ -345,9 +345,9 @@ Configure `frps` same as above.
### P2P Mode ### P2P Mode
**xtcp** is designed for transmitting large amounts of data directly between clients. A frps server is still needed, as P2P here only refers the actual data transmission. **xtcp** is designed to transmit large amounts of data directly between clients. A frps server is still needed, as P2P here only refers to the actual data transmission.
Note it can't penetrate all types of NAT devices. You might want to fallback to **stcp** if **xtcp** doesn't work. Note that it may not work with all types of NAT devices. You might want to fallback to stcp if xtcp doesn't work.
1. In `frps.ini` configure a UDP port for xtcp: 1. In `frps.ini` configure a UDP port for xtcp:
@@ -356,7 +356,7 @@ Note it can't penetrate all types of NAT devices. You might want to fallback to
bind_udp_port = 7001 bind_udp_port = 7001
``` ```
2. Start `frpc` on machine B, expose the SSH port. Note that `remote_port` field is removed: 2. Start `frpc` on machine B, and expose the SSH port. Note that the `remote_port` field is removed:
```ini ```ini
# frpc.ini # frpc.ini
@@ -371,7 +371,7 @@ Note it can't penetrate all types of NAT devices. You might want to fallback to
local_port = 22 local_port = 22
``` ```
3. Start another `frpc` (typically on another machine C) with the config to connect to SSH using P2P mode: 3. Start another `frpc` (typically on another machine C) with the configuration to connect to SSH using P2P mode:
```ini ```ini
# frpc.ini # frpc.ini
@@ -720,6 +720,8 @@ bandwidth_limit = 1MB
Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`. Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`.
Set `bandwidth_limit_mode` to `client` or `server` to limit bandwidth on the client or server side. Default is `client`.
### TCP Stream Multiplexing ### TCP Stream Multiplexing
frp supports tcp stream multiplexing since v0.10.0 like HTTP2 Multiplexing, in which case all logic connections to the same frpc are multiplexed into the same TCP connection. frp supports tcp stream multiplexing since v0.10.0 like HTTP2 Multiplexing, in which case all logic connections to the same frpc are multiplexed into the same TCP connection.
@@ -761,6 +763,35 @@ KCP mode uses UDP as the underlying transport. Using KCP in frp:
protocol = kcp protocol = kcp
``` ```
### Support QUIC Protocol
QUIC is a new multiplexed transport built on top of UDP.
Using QUIC in frp:
1. Enable QUIC in frps:
```ini
# frps.ini
[common]
bind_port = 7000
# Specify a UDP port for QUIC.
quic_bind_port = 7000
```
The `quic_bind_port` number can be the same number as `bind_port`, since `bind_port` field specifies a TCP port.
2. Configure `frpc.ini` to use QUIC to connect to frps:
```ini
# frpc.ini
[common]
server_addr = x.x.x.x
# Same as the 'quic_bind_port' in frps.ini
server_port = 7000
protocol = quic
```
### Connection Pooling ### Connection Pooling
By default, frps creates a new frpc connection to the backend service upon a user request. With connection pooling, frps keeps a certain number of pre-established connections, reducing the time needed to establish a connection. By default, frps creates a new frpc connection to the backend service upon a user request. With connection pooling, frps keeps a certain number of pre-established connections, reducing the time needed to establish a connection.

View File

@@ -9,19 +9,17 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP
<h3 align="center">Gold Sponsors</h3> <h3 align="center">Gold Sponsors</h3>
<!--gold sponsors start--> <!--gold sponsors start-->
<p align="center"> <p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank"> <a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="300px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png"> <img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
</a>
<a>&nbsp</a>
<a href="https://asocks.com/c/vDu6Dk" target="_blank">
<img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_asocks.jpg">
</a> </a>
</p> </p>
<!--gold sponsors end--> <!--gold sponsors end-->
<h3 align="center">Silver Sponsors</h3>
* Sakura Frp - 欢迎点击 "加入我们"
## 为什么使用 frp ## 为什么使用 frp
通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括: 通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:

View File

@@ -1,3 +1,8 @@
### Improve ### New
* Adjust http group load balancing to forward requests to each frpc proxy round robin. Previous behavior is always forwarding requests to single proxy in the case of single concurrency. * The `httpconnect` type in `tcpmux` now supports authentication through the parameters `http_user` and `http_pwd`.
### Improved
* The web framework has been upgraded to vue3 + element-plus, and the dashboard has added some information display and supports dark mode.
* The e2e testing has been switched to ginkgo v2.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,16 @@
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?5d5774096cf5c1b4d5af"></script><script type="text/javascript" src="vendor.js?dc42700731a508d39009"></script></body> </html> <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>frp client admin UI</title>
<script type="module" crossorigin src="./index-7dd223da.js"></script>
<link rel="stylesheet" href="./index-aa3c7267.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -1 +0,0 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"dc42700731a508d39009"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,16 @@
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?5d154ba4c6b342d8c0c3"></script><script type="text/javascript" src="vendor.js?ddbd1f69fb6e67be4b78"></script></body> </html> <!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8">
<title>frps dashboard</title>
<script type="module" crossorigin src="./index-b8250b3f.js"></script>
<link rel="stylesheet" href="./index-7b4711f8.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -1 +0,0 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,u,c){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(e[i]=u[i]);for(r&&r(t,u,c);s.length;)s.shift()();if(c)for(l=0;l<c.length;l++)f=n(n.s=c[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var u=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=u;var c=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"ddbd1f69fb6e67be4b78"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,c.appendChild(i),u},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);

File diff suppressed because one or more lines are too long

View File

@@ -28,6 +28,7 @@ import (
"github.com/fatedier/frp/client/proxy" "github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/util"
) )
type GeneralResponse struct { type GeneralResponse struct {
@@ -70,15 +71,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
log.Info("success reload conf") log.Info("success reload conf")
} }
type StatusResp struct { type StatusResp map[string][]ProxyStatusResp
TCP []ProxyStatusResp `json:"tcp"`
UDP []ProxyStatusResp `json:"udp"`
HTTP []ProxyStatusResp `json:"http"`
HTTPS []ProxyStatusResp `json:"https"`
STCP []ProxyStatusResp `json:"stcp"`
XTCP []ProxyStatusResp `json:"xtcp"`
SUDP []ProxyStatusResp `json:"sudp"`
}
type ProxyStatusResp struct { type ProxyStatusResp struct {
Name string `json:"name"` Name string `json:"name"`
@@ -90,12 +83,6 @@ type ProxyStatusResp struct {
RemoteAddr string `json:"remote_addr"` RemoteAddr string `json:"remote_addr"`
} }
type ByProxyStatusResp []ProxyStatusResp
func (a ByProxyStatusResp) Len() int { return len(a) }
func (a ByProxyStatusResp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByProxyStatusResp) Less(i, j int) bool { return strings.Compare(a[i].Name, a[j].Name) < 0 }
func NewProxyStatusResp(status *proxy.WorkingStatus, serverAddr string) ProxyStatusResp { func NewProxyStatusResp(status *proxy.WorkingStatus, serverAddr string) ProxyStatusResp {
psr := ProxyStatusResp{ psr := ProxyStatusResp{
Name: status.Name, Name: status.Name,
@@ -103,53 +90,17 @@ func NewProxyStatusResp(status *proxy.WorkingStatus, serverAddr string) ProxySta
Status: status.Phase, Status: status.Phase,
Err: status.Err, Err: status.Err,
} }
switch cfg := status.Cfg.(type) { baseCfg := status.Cfg.GetBaseInfo()
case *config.TCPProxyConf: if baseCfg.LocalPort != 0 {
if cfg.LocalPort != 0 { psr.LocalAddr = net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort))
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort)) }
} psr.Plugin = baseCfg.Plugin
psr.Plugin = cfg.Plugin
if status.Err != "" { if status.Err == "" {
psr.RemoteAddr = net.JoinHostPort(serverAddr, strconv.Itoa(cfg.RemotePort))
} else {
psr.RemoteAddr = serverAddr + status.RemoteAddr
}
case *config.UDPProxyConf:
if cfg.LocalPort != 0 {
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort))
}
if status.Err != "" {
psr.RemoteAddr = net.JoinHostPort(serverAddr, strconv.Itoa(cfg.RemotePort))
} else {
psr.RemoteAddr = serverAddr + status.RemoteAddr
}
case *config.HTTPProxyConf:
if cfg.LocalPort != 0 {
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort))
}
psr.Plugin = cfg.Plugin
psr.RemoteAddr = status.RemoteAddr psr.RemoteAddr = status.RemoteAddr
case *config.HTTPSProxyConf: if util.InSlice(status.Type, []string{"tcp", "udp"}) {
if cfg.LocalPort != 0 { psr.RemoteAddr = serverAddr + psr.RemoteAddr
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort))
} }
psr.Plugin = cfg.Plugin
psr.RemoteAddr = status.RemoteAddr
case *config.STCPProxyConf:
if cfg.LocalPort != 0 {
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort))
}
psr.Plugin = cfg.Plugin
case *config.XTCPProxyConf:
if cfg.LocalPort != 0 {
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort))
}
psr.Plugin = cfg.Plugin
case *config.SUDPProxyConf:
if cfg.LocalPort != 0 {
psr.LocalAddr = net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort))
}
psr.Plugin = cfg.Plugin
} }
return psr return psr
} }
@@ -158,15 +109,8 @@ func NewProxyStatusResp(status *proxy.WorkingStatus, serverAddr string) ProxySta
func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) { func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
var ( var (
buf []byte buf []byte
res StatusResp res StatusResp = make(map[string][]ProxyStatusResp)
) )
res.TCP = make([]ProxyStatusResp, 0)
res.UDP = make([]ProxyStatusResp, 0)
res.HTTP = make([]ProxyStatusResp, 0)
res.HTTPS = make([]ProxyStatusResp, 0)
res.STCP = make([]ProxyStatusResp, 0)
res.XTCP = make([]ProxyStatusResp, 0)
res.SUDP = make([]ProxyStatusResp, 0)
log.Info("Http request [/api/status]") log.Info("Http request [/api/status]")
defer func() { defer func() {
@@ -177,30 +121,17 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
ps := svr.ctl.pm.GetAllProxyStatus() ps := svr.ctl.pm.GetAllProxyStatus()
for _, status := range ps { for _, status := range ps {
switch status.Type { res[status.Type] = append(res[status.Type], NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "tcp": }
res.TCP = append(res.TCP, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "udp": for _, arrs := range res {
res.UDP = append(res.UDP, NewProxyStatusResp(status, svr.cfg.ServerAddr)) if len(arrs) <= 1 {
case "http": continue
res.HTTP = append(res.HTTP, NewProxyStatusResp(status, svr.cfg.ServerAddr)) }
case "https": sort.Slice(arrs, func(i, j int) bool {
res.HTTPS = append(res.HTTPS, NewProxyStatusResp(status, svr.cfg.ServerAddr)) return strings.Compare(arrs[i].Name, arrs[j].Name) < 0
case "stcp": })
res.STCP = append(res.STCP, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "xtcp":
res.XTCP = append(res.XTCP, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "sudp":
res.SUDP = append(res.SUDP, NewProxyStatusResp(status, svr.cfg.ServerAddr))
}
} }
sort.Sort(ByProxyStatusResp(res.TCP))
sort.Sort(ByProxyStatusResp(res.UDP))
sort.Sort(ByProxyStatusResp(res.HTTP))
sort.Sort(ByProxyStatusResp(res.HTTPS))
sort.Sort(ByProxyStatusResp(res.STCP))
sort.Sort(ByProxyStatusResp(res.XTCP))
sort.Sort(ByProxyStatusResp(res.SUDP))
} }
// GET api/config // GET api/config

View File

@@ -16,24 +16,18 @@ package client
import ( import (
"context" "context"
"crypto/tls"
"io" "io"
"net" "net"
"runtime/debug" "runtime/debug"
"strconv"
"time" "time"
"github.com/fatedier/golib/control/shutdown" "github.com/fatedier/golib/control/shutdown"
"github.com/fatedier/golib/crypto" "github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux"
"github.com/fatedier/frp/client/proxy" "github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/transport"
frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
) )
@@ -51,8 +45,7 @@ type Control struct {
// control connection // control connection
conn net.Conn conn net.Conn
// tcp stream multiplexing, if enabled cm *ConnectionManager
session *fmux.Session
// put a message in this channel to send it over control connection to server // put a message in this channel to send it over control connection to server
sendCh chan (msg.Message) sendCh chan (msg.Message)
@@ -87,7 +80,8 @@ type Control struct {
authSetter auth.Setter authSetter auth.Setter
} }
func NewControl(ctx context.Context, runID string, conn net.Conn, session *fmux.Session, func NewControl(
ctx context.Context, runID string, conn net.Conn, cm *ConnectionManager,
clientCfg config.ClientCommonConf, clientCfg config.ClientCommonConf,
pxyCfgs map[string]config.ProxyConf, pxyCfgs map[string]config.ProxyConf,
visitorCfgs map[string]config.VisitorConf, visitorCfgs map[string]config.VisitorConf,
@@ -98,7 +92,7 @@ func NewControl(ctx context.Context, runID string, conn net.Conn, session *fmux.
ctl := &Control{ ctl := &Control{
runID: runID, runID: runID,
conn: conn, conn: conn,
session: session, cm: cm,
pxyCfgs: pxyCfgs, pxyCfgs: pxyCfgs,
sendCh: make(chan msg.Message, 100), sendCh: make(chan msg.Message, 100),
readCh: make(chan msg.Message, 100), readCh: make(chan msg.Message, 100),
@@ -134,6 +128,7 @@ func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
xl := ctl.xl xl := ctl.xl
workConn, err := ctl.connectServer() workConn, err := ctl.connectServer()
if err != nil { if err != nil {
xl.Warn("start new connection to server error: %v", err)
return return
} }
@@ -152,7 +147,7 @@ func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
var startMsg msg.StartWorkConn var startMsg msg.StartWorkConn
if err = msg.ReadMsgInto(workConn, &startMsg); err != nil { if err = msg.ReadMsgInto(workConn, &startMsg); err != nil {
xl.Error("work connection closed before response StartWorkConn message: %v", err) xl.Trace("work connection closed before response StartWorkConn message: %v", err)
workConn.Close() workConn.Close()
return return
} }
@@ -189,9 +184,7 @@ func (ctl *Control) GracefulClose(d time.Duration) error {
time.Sleep(d) time.Sleep(d)
ctl.conn.Close() ctl.conn.Close()
if ctl.session != nil { ctl.cm.Close()
ctl.session.Close()
}
return nil return nil
} }
@@ -202,70 +195,7 @@ func (ctl *Control) ClosedDoneCh() <-chan struct{} {
// connectServer return a new connection to frps // connectServer return a new connection to frps
func (ctl *Control) connectServer() (conn net.Conn, err error) { func (ctl *Control) connectServer() (conn net.Conn, err error) {
xl := ctl.xl return ctl.cm.Connect()
if ctl.clientCfg.TCPMux {
stream, errRet := ctl.session.OpenStream()
if errRet != nil {
err = errRet
xl.Warn("start new connection to server error: %v", err)
return
}
conn = stream
} else {
var tlsConfig *tls.Config
sn := ctl.clientCfg.TLSServerName
if sn == "" {
sn = ctl.clientCfg.ServerAddr
}
if ctl.clientCfg.TLSEnable {
tlsConfig, err = transport.NewClientTLSConfig(
ctl.clientCfg.TLSCertFile,
ctl.clientCfg.TLSKeyFile,
ctl.clientCfg.TLSTrustedCaFile,
sn)
if err != nil {
xl.Warn("fail to build tls configuration when connecting to server, err: %v", err)
return
}
}
proxyType, addr, auth, err := libdial.ParseProxyURL(ctl.clientCfg.HTTPProxy)
if err != nil {
xl.Error("fail to parse proxy url")
return nil, err
}
dialOptions := []libdial.DialOption{}
protocol := ctl.clientCfg.Protocol
if protocol == "websocket" {
protocol = "tcp"
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket()}))
}
if ctl.clientCfg.ConnectServerLocalIP != "" {
dialOptions = append(dialOptions, libdial.WithLocalAddr(ctl.clientCfg.ConnectServerLocalIP))
}
dialOptions = append(dialOptions,
libdial.WithProtocol(protocol),
libdial.WithTimeout(time.Duration(ctl.clientCfg.DialServerTimeout)*time.Second),
libdial.WithKeepAlive(time.Duration(ctl.clientCfg.DialServerKeepAlive)*time.Second),
libdial.WithProxy(proxyType, addr),
libdial.WithProxyAuth(auth),
libdial.WithTLSConfig(tlsConfig),
libdial.WithAfterHook(libdial.AfterHook{
Hook: frpNet.DialHookCustomTLSHeadByte(tlsConfig != nil, ctl.clientCfg.DisableCustomTLSFirstByte),
}),
)
conn, err = libdial.Dial(
net.JoinHostPort(ctl.clientCfg.ServerAddr, strconv.Itoa(ctl.clientCfg.ServerPort)),
dialOptions...,
)
if err != nil {
xl.Warn("start new connection to server error: %v", err)
return nil, err
}
}
return
} }
// reader read all messages from frps and send to readCh // reader read all messages from frps and send to readCh
@@ -409,9 +339,7 @@ func (ctl *Control) worker() {
ctl.vm.Close() ctl.vm.Close()
close(ctl.closedDoneCh) close(ctl.closedDoneCh)
if ctl.session != nil { ctl.cm.Close()
ctl.session.Close()
}
} }
func (ctl *Control) ReloadConf(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) error { func (ctl *Control) ReloadConf(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) error {

View File

@@ -54,7 +54,7 @@ type Proxy interface {
func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) { func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
var limiter *rate.Limiter var limiter *rate.Limiter
limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes()
if limitBytes > 0 { if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeClient {
limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes)) limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
} }

View File

@@ -31,6 +31,7 @@ import (
"github.com/fatedier/golib/crypto" "github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial" libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux" fmux "github.com/hashicorp/yamux"
quic "github.com/quic-go/quic-go"
"github.com/fatedier/frp/assets" "github.com/fatedier/frp/assets"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
@@ -46,6 +47,7 @@ import (
func init() { func init() {
crypto.DefaultSalt = "frp" crypto.DefaultSalt = "frp"
// TODO: remove this when we drop support for go1.19
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
} }
@@ -113,8 +115,8 @@ func (svr *Service) Run() error {
// set custom DNSServer // set custom DNSServer
if svr.cfg.DNSServer != "" { if svr.cfg.DNSServer != "" {
dnsAddr := svr.cfg.DNSServer dnsAddr := svr.cfg.DNSServer
if !strings.Contains(dnsAddr, ":") { if _, _, err := net.SplitHostPort(dnsAddr); err != nil {
dnsAddr += ":53" dnsAddr = net.JoinHostPort(dnsAddr, "53")
} }
// Change default dns server for frpc // Change default dns server for frpc
net.DefaultResolver = &net.Resolver{ net.DefaultResolver = &net.Resolver{
@@ -127,7 +129,7 @@ func (svr *Service) Run() error {
// login to frps // login to frps
for { for {
conn, session, err := svr.login() conn, cm, err := svr.login()
if err != nil { if err != nil {
xl.Warn("login to server failed: %v", err) xl.Warn("login to server failed: %v", err)
@@ -139,7 +141,7 @@ func (svr *Service) Run() error {
util.RandomSleep(10*time.Second, 0.9, 1.1) util.RandomSleep(10*time.Second, 0.9, 1.1)
} else { } else {
// login success // login success
ctl := NewControl(svr.ctx, svr.runID, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort, svr.authSetter) ctl := NewControl(svr.ctx, svr.runID, conn, cm, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort, svr.authSetter)
ctl.Run() ctl.Run()
svr.ctlMu.Lock() svr.ctlMu.Lock()
svr.ctl = ctl svr.ctl = ctl
@@ -207,7 +209,7 @@ func (svr *Service) keepControllerWorking() {
} }
xl.Info("try to reconnect to server...") xl.Info("try to reconnect to server...")
conn, session, err := svr.login() conn, cm, err := svr.login()
if err != nil { if err != nil {
xl.Warn("reconnect to server error: %v, wait %v for another retry", err, delayTime) xl.Warn("reconnect to server error: %v, wait %v for another retry", err, delayTime)
util.RandomSleep(delayTime, 0.9, 1.1) util.RandomSleep(delayTime, 0.9, 1.1)
@@ -221,7 +223,7 @@ func (svr *Service) keepControllerWorking() {
// reconnect success, init delayTime // reconnect success, init delayTime
delayTime = time.Second delayTime = time.Second
ctl := NewControl(svr.ctx, svr.runID, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort, svr.authSetter) ctl := NewControl(svr.ctx, svr.runID, conn, cm, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort, svr.authSetter)
ctl.Run() ctl.Run()
svr.ctlMu.Lock() svr.ctlMu.Lock()
if svr.ctl != nil { if svr.ctl != nil {
@@ -237,83 +239,23 @@ func (svr *Service) keepControllerWorking() {
// login creates a connection to frps and registers it self as a client // login creates a connection to frps and registers it self as a client
// conn: control connection // conn: control connection
// session: if it's not nil, using tcp mux // session: if it's not nil, using tcp mux
func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) { func (svr *Service) login() (conn net.Conn, cm *ConnectionManager, err error) {
xl := xlog.FromContextSafe(svr.ctx) xl := xlog.FromContextSafe(svr.ctx)
var tlsConfig *tls.Config cm = NewConnectionManager(svr.ctx, &svr.cfg)
if svr.cfg.TLSEnable {
sn := svr.cfg.TLSServerName
if sn == "" {
sn = svr.cfg.ServerAddr
}
tlsConfig, err = transport.NewClientTLSConfig( if err = cm.OpenConnection(); err != nil {
svr.cfg.TLSCertFile, return nil, nil, err
svr.cfg.TLSKeyFile,
svr.cfg.TLSTrustedCaFile,
sn)
if err != nil {
xl.Warn("fail to build tls configuration when service login, err: %v", err)
return
}
}
proxyType, addr, auth, err := libdial.ParseProxyURL(svr.cfg.HTTPProxy)
if err != nil {
xl.Error("fail to parse proxy url")
return
}
dialOptions := []libdial.DialOption{}
protocol := svr.cfg.Protocol
if protocol == "websocket" {
protocol = "tcp"
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket()}))
}
if svr.cfg.ConnectServerLocalIP != "" {
dialOptions = append(dialOptions, libdial.WithLocalAddr(svr.cfg.ConnectServerLocalIP))
}
dialOptions = append(dialOptions,
libdial.WithProtocol(protocol),
libdial.WithTimeout(time.Duration(svr.cfg.DialServerTimeout)*time.Second),
libdial.WithKeepAlive(time.Duration(svr.cfg.DialServerKeepAlive)*time.Second),
libdial.WithProxy(proxyType, addr),
libdial.WithProxyAuth(auth),
libdial.WithTLSConfig(tlsConfig),
libdial.WithAfterHook(libdial.AfterHook{
Hook: frpNet.DialHookCustomTLSHeadByte(tlsConfig != nil, svr.cfg.DisableCustomTLSFirstByte),
}),
)
conn, err = libdial.Dial(
net.JoinHostPort(svr.cfg.ServerAddr, strconv.Itoa(svr.cfg.ServerPort)),
dialOptions...,
)
if err != nil {
return
} }
defer func() { defer func() {
if err != nil { if err != nil {
conn.Close() cm.Close()
if session != nil {
session.Close()
}
} }
}() }()
if svr.cfg.TCPMux { conn, err = cm.Connect()
fmuxCfg := fmux.DefaultConfig() if err != nil {
fmuxCfg.KeepAliveInterval = time.Duration(svr.cfg.TCPMuxKeepaliveInterval) * time.Second return
fmuxCfg.LogOutput = io.Discard
session, err = fmux.Client(conn, fmuxCfg)
if err != nil {
return
}
stream, errRet := session.OpenStream()
if errRet != nil {
session.Close()
err = errRet
return
}
conn = stream
} }
loginMsg := &msg.Login{ loginMsg := &msg.Login{
@@ -389,3 +331,159 @@ func (svr *Service) GracefulClose(d time.Duration) {
svr.cancel() svr.cancel()
} }
type ConnectionManager struct {
ctx context.Context
cfg *config.ClientCommonConf
muxSession *fmux.Session
quicConn quic.Connection
}
func NewConnectionManager(ctx context.Context, cfg *config.ClientCommonConf) *ConnectionManager {
return &ConnectionManager{
ctx: ctx,
cfg: cfg,
}
}
func (cm *ConnectionManager) OpenConnection() error {
xl := xlog.FromContextSafe(cm.ctx)
// special for quic
if strings.EqualFold(cm.cfg.Protocol, "quic") {
var tlsConfig *tls.Config
var err error
sn := cm.cfg.TLSServerName
if sn == "" {
sn = cm.cfg.ServerAddr
}
if cm.cfg.TLSEnable {
tlsConfig, err = transport.NewClientTLSConfig(
cm.cfg.TLSCertFile,
cm.cfg.TLSKeyFile,
cm.cfg.TLSTrustedCaFile,
sn)
} else {
tlsConfig, err = transport.NewClientTLSConfig("", "", "", sn)
}
if err != nil {
xl.Warn("fail to build tls configuration, err: %v", err)
return err
}
tlsConfig.NextProtos = []string{"frp"}
conn, err := quic.DialAddr(
net.JoinHostPort(cm.cfg.ServerAddr, strconv.Itoa(cm.cfg.ServerPort)),
tlsConfig, &quic.Config{
MaxIdleTimeout: time.Duration(cm.cfg.QUICMaxIdleTimeout) * time.Second,
MaxIncomingStreams: int64(cm.cfg.QUICMaxIncomingStreams),
KeepAlivePeriod: time.Duration(cm.cfg.QUICKeepalivePeriod) * time.Second,
})
if err != nil {
return err
}
cm.quicConn = conn
return nil
}
if !cm.cfg.TCPMux {
return nil
}
conn, err := cm.realConnect()
if err != nil {
return err
}
fmuxCfg := fmux.DefaultConfig()
fmuxCfg.KeepAliveInterval = time.Duration(cm.cfg.TCPMuxKeepaliveInterval) * time.Second
fmuxCfg.LogOutput = io.Discard
session, err := fmux.Client(conn, fmuxCfg)
if err != nil {
return err
}
cm.muxSession = session
return nil
}
func (cm *ConnectionManager) Connect() (net.Conn, error) {
if cm.quicConn != nil {
stream, err := cm.quicConn.OpenStreamSync(context.Background())
if err != nil {
return nil, err
}
return frpNet.QuicStreamToNetConn(stream, cm.quicConn), nil
} else if cm.muxSession != nil {
stream, err := cm.muxSession.OpenStream()
if err != nil {
return nil, err
}
return stream, nil
}
return cm.realConnect()
}
func (cm *ConnectionManager) realConnect() (net.Conn, error) {
xl := xlog.FromContextSafe(cm.ctx)
var tlsConfig *tls.Config
var err error
if cm.cfg.TLSEnable {
sn := cm.cfg.TLSServerName
if sn == "" {
sn = cm.cfg.ServerAddr
}
tlsConfig, err = transport.NewClientTLSConfig(
cm.cfg.TLSCertFile,
cm.cfg.TLSKeyFile,
cm.cfg.TLSTrustedCaFile,
sn)
if err != nil {
xl.Warn("fail to build tls configuration, err: %v", err)
return nil, err
}
}
proxyType, addr, auth, err := libdial.ParseProxyURL(cm.cfg.HTTPProxy)
if err != nil {
xl.Error("fail to parse proxy url")
return nil, err
}
dialOptions := []libdial.DialOption{}
protocol := cm.cfg.Protocol
if protocol == "websocket" {
protocol = "tcp"
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: frpNet.DialHookWebsocket()}))
}
if cm.cfg.ConnectServerLocalIP != "" {
dialOptions = append(dialOptions, libdial.WithLocalAddr(cm.cfg.ConnectServerLocalIP))
}
dialOptions = append(dialOptions,
libdial.WithProtocol(protocol),
libdial.WithTimeout(time.Duration(cm.cfg.DialServerTimeout)*time.Second),
libdial.WithKeepAlive(time.Duration(cm.cfg.DialServerKeepAlive)*time.Second),
libdial.WithProxy(proxyType, addr),
libdial.WithProxyAuth(auth),
libdial.WithTLSConfig(tlsConfig),
libdial.WithAfterHook(libdial.AfterHook{
Hook: frpNet.DialHookCustomTLSHeadByte(tlsConfig != nil, cm.cfg.DisableCustomTLSFirstByte),
}),
)
conn, err := libdial.Dial(
net.JoinHostPort(cm.cfg.ServerAddr, strconv.Itoa(cm.cfg.ServerPort)),
dialOptions...,
)
return conn, err
}
func (cm *ConnectionManager) Close() error {
if cm.quicConn != nil {
_ = cm.quicConn.CloseWithError(0, "")
}
if cm.muxSession != nil {
_ = cm.muxSession.Close()
}
return nil
}

View File

@@ -39,6 +39,8 @@ func init() {
httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite") httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite")
httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
httpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") httpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
httpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
httpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(httpCmd) rootCmd.AddCommand(httpCmd)
} }
@@ -70,6 +72,12 @@ var httpCmd = &cobra.Command{
cfg.HostHeaderRewrite = hostHeaderRewrite cfg.HostHeaderRewrite = hostHeaderRewrite
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@@ -35,6 +35,8 @@ func init() {
httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain") httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
httpsCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") httpsCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
httpsCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
httpsCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(httpsCmd) rootCmd.AddCommand(httpsCmd)
} }
@@ -62,6 +64,12 @@ var httpsCmd = &cobra.Command{
cfg.SubDomain = subDomain cfg.SubDomain = subDomain
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@@ -54,24 +54,26 @@ var (
logMaxDays int logMaxDays int
disableLogColor bool disableLogColor bool
proxyName string proxyName string
localIP string localIP string
localPort int localPort int
remotePort int remotePort int
useEncryption bool useEncryption bool
useCompression bool useCompression bool
customDomains string bandwidthLimit string
subDomain string bandwidthLimitMode string
httpUser string customDomains string
httpPwd string subDomain string
locations string httpUser string
hostHeaderRewrite string httpPwd string
role string locations string
sk string hostHeaderRewrite string
multiplexer string role string
serverName string sk string
bindAddr string multiplexer string
bindPort int serverName string
bindAddr string
bindPort int
tlsEnable bool tlsEnable bool
) )
@@ -216,15 +218,16 @@ func startService(
return return
} }
kcpDoneCh := make(chan struct{}) closedDoneCh := make(chan struct{})
// Capture the exit signal if we use kcp. shouldGracefulClose := cfg.Protocol == "kcp" || cfg.Protocol == "quic"
if cfg.Protocol == "kcp" { // Capture the exit signal if we use kcp or quic.
go handleSignal(svr, kcpDoneCh) if shouldGracefulClose {
go handleSignal(svr, closedDoneCh)
} }
err = svr.Run() err = svr.Run()
if err == nil && cfg.Protocol == "kcp" { if err == nil && shouldGracefulClose {
<-kcpDoneCh <-closedDoneCh
} }
return return
} }

View File

@@ -81,67 +81,27 @@ func status(clientCfg config.ClientCommonConf) error {
if err != nil { if err != nil {
return err return err
} }
res := &client.StatusResp{} res := make(client.StatusResp)
err = json.Unmarshal(body, &res) err = json.Unmarshal(body, &res)
if err != nil { if err != nil {
return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body))) return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body)))
} }
fmt.Println("Proxy Status...") fmt.Println("Proxy Status...")
if len(res.TCP) > 0 { types := []string{"tcp", "udp", "tcpmux", "http", "https", "stcp", "sudp", "xtcp"}
fmt.Println("TCP") for _, pxyType := range types {
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error") arrs := res[pxyType]
for _, ps := range res.TCP { if len(arrs) == 0 {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err) continue
} }
tbl.Print()
fmt.Println("")
}
if len(res.UDP) > 0 {
fmt.Println("UDP")
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range res.UDP {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
if len(res.HTTP) > 0 {
fmt.Println("HTTP")
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range res.HTTP {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
if len(res.HTTPS) > 0 {
fmt.Println("HTTPS")
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range res.HTTPS {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
if len(res.STCP) > 0 {
fmt.Println("STCP")
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range res.STCP {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
if len(res.XTCP) > 0 {
fmt.Println("XTCP")
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range res.XTCP {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
fmt.Println(strings.ToUpper(pxyType))
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
for _, ps := range arrs {
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
}
tbl.Print()
fmt.Println("")
}
return nil return nil
} }

View File

@@ -37,6 +37,8 @@ func init() {
stcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") stcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
stcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") stcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
stcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
stcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(stcpCmd) rootCmd.AddCommand(stcpCmd)
} }
@@ -59,7 +61,8 @@ var stcpCmd = &cobra.Command{
prefix = user + "." prefix = user + "."
} }
if role == "server" { switch role {
case "server":
cfg := &config.STCPProxyConf{} cfg := &config.STCPProxyConf{}
cfg.ProxyName = prefix + proxyName cfg.ProxyName = prefix + proxyName
cfg.ProxyType = consts.STCPProxy cfg.ProxyType = consts.STCPProxy
@@ -69,13 +72,19 @@ var stcpCmd = &cobra.Command{
cfg.Sk = sk cfg.Sk = sk
cfg.LocalIP = localIP cfg.LocalIP = localIP
cfg.LocalPort = localPort cfg.LocalPort = localPort
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
proxyConfs[cfg.ProxyName] = cfg proxyConfs[cfg.ProxyName] = cfg
} else if role == "visitor" { case "visitor":
cfg := &config.STCPVisitorConf{} cfg := &config.STCPVisitorConf{}
cfg.ProxyName = prefix + proxyName cfg.ProxyName = prefix + proxyName
cfg.ProxyType = consts.STCPProxy cfg.ProxyType = consts.STCPProxy
@@ -92,7 +101,7 @@ var stcpCmd = &cobra.Command{
os.Exit(1) os.Exit(1)
} }
visitorConfs[cfg.ProxyName] = cfg visitorConfs[cfg.ProxyName] = cfg
} else { default:
fmt.Println("invalid role") fmt.Println("invalid role")
os.Exit(1) os.Exit(1)
} }

View File

@@ -37,6 +37,8 @@ func init() {
sudpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") sudpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
sudpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") sudpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
sudpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") sudpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
sudpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
sudpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(sudpCmd) rootCmd.AddCommand(sudpCmd)
} }
@@ -59,7 +61,8 @@ var sudpCmd = &cobra.Command{
prefix = user + "." prefix = user + "."
} }
if role == "server" { switch role {
case "server":
cfg := &config.SUDPProxyConf{} cfg := &config.SUDPProxyConf{}
cfg.ProxyName = prefix + proxyName cfg.ProxyName = prefix + proxyName
cfg.ProxyType = consts.SUDPProxy cfg.ProxyType = consts.SUDPProxy
@@ -69,13 +72,19 @@ var sudpCmd = &cobra.Command{
cfg.Sk = sk cfg.Sk = sk
cfg.LocalIP = localIP cfg.LocalIP = localIP
cfg.LocalPort = localPort cfg.LocalPort = localPort
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
proxyConfs[cfg.ProxyName] = cfg proxyConfs[cfg.ProxyName] = cfg
} else if role == "visitor" { case "visitor":
cfg := &config.SUDPVisitorConf{} cfg := &config.SUDPVisitorConf{}
cfg.ProxyName = prefix + proxyName cfg.ProxyName = prefix + proxyName
cfg.ProxyType = consts.SUDPProxy cfg.ProxyType = consts.SUDPProxy
@@ -92,7 +101,7 @@ var sudpCmd = &cobra.Command{
os.Exit(1) os.Exit(1)
} }
visitorConfs[cfg.ProxyName] = cfg visitorConfs[cfg.ProxyName] = cfg
} else { default:
fmt.Println("invalid role") fmt.Println("invalid role")
os.Exit(1) os.Exit(1)
} }

View File

@@ -33,6 +33,8 @@ func init() {
tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port") tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
tcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") tcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
tcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
tcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(tcpCmd) rootCmd.AddCommand(tcpCmd)
} }
@@ -59,6 +61,12 @@ var tcpCmd = &cobra.Command{
cfg.RemotePort = remotePort cfg.RemotePort = remotePort
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@@ -36,6 +36,8 @@ func init() {
tcpMuxCmd.PersistentFlags().StringVarP(&multiplexer, "mux", "", "", "multiplexer") tcpMuxCmd.PersistentFlags().StringVarP(&multiplexer, "mux", "", "", "multiplexer")
tcpMuxCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") tcpMuxCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
tcpMuxCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") tcpMuxCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
tcpMuxCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
tcpMuxCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(tcpMuxCmd) rootCmd.AddCommand(tcpMuxCmd)
} }
@@ -64,6 +66,12 @@ var tcpMuxCmd = &cobra.Command{
cfg.Multiplexer = multiplexer cfg.Multiplexer = multiplexer
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@@ -33,6 +33,8 @@ func init() {
udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port") udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
udpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") udpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
udpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
udpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(udpCmd) rootCmd.AddCommand(udpCmd)
} }
@@ -59,6 +61,12 @@ var udpCmd = &cobra.Command{
cfg.RemotePort = remotePort cfg.RemotePort = remotePort
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@@ -37,6 +37,8 @@ func init() {
xtcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") xtcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
xtcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") xtcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
xtcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit")
xtcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode")
rootCmd.AddCommand(xtcpCmd) rootCmd.AddCommand(xtcpCmd)
} }
@@ -59,7 +61,8 @@ var xtcpCmd = &cobra.Command{
prefix = user + "." prefix = user + "."
} }
if role == "server" { switch role {
case "server":
cfg := &config.XTCPProxyConf{} cfg := &config.XTCPProxyConf{}
cfg.ProxyName = prefix + proxyName cfg.ProxyName = prefix + proxyName
cfg.ProxyType = consts.XTCPProxy cfg.ProxyType = consts.XTCPProxy
@@ -69,13 +72,19 @@ var xtcpCmd = &cobra.Command{
cfg.Sk = sk cfg.Sk = sk
cfg.LocalIP = localIP cfg.LocalIP = localIP
cfg.LocalPort = localPort cfg.LocalPort = localPort
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
proxyConfs[cfg.ProxyName] = cfg proxyConfs[cfg.ProxyName] = cfg
} else if role == "visitor" { case "visitor":
cfg := &config.XTCPVisitorConf{} cfg := &config.XTCPVisitorConf{}
cfg.ProxyName = prefix + proxyName cfg.ProxyName = prefix + proxyName
cfg.ProxyType = consts.XTCPProxy cfg.ProxyType = consts.XTCPProxy
@@ -92,7 +101,7 @@ var xtcpCmd = &cobra.Command{
os.Exit(1) os.Exit(1)
} }
visitorConfs[cfg.ProxyName] = cfg visitorConfs[cfg.ProxyName] = cfg
} else { default:
fmt.Println("invalid role") fmt.Println("invalid role")
os.Exit(1) os.Exit(1)
} }

View File

@@ -26,6 +26,7 @@ import (
func main() { func main() {
crypto.DefaultSalt = "frp" crypto.DefaultSalt = "frp"
// TODO: remove this when we drop support for go1.19
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
Execute() Execute()

View File

@@ -40,6 +40,8 @@ authenticate_new_work_conns = false
# auth token # auth token
token = 12345678 token = 12345678
authentication_method =
# oidc_client_id specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc". # oidc_client_id specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# By default, this value is "". # By default, this value is "".
oidc_client_id = oidc_client_id =
@@ -51,6 +53,9 @@ oidc_client_secret =
# oidc_audience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "". # oidc_audience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
oidc_audience = oidc_audience =
# oidc_scope specifies the permisssions of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
oidc_scope =
# oidc_token_endpoint_url specifies the URL which implements OIDC Token Endpoint. # oidc_token_endpoint_url specifies the URL which implements OIDC Token Endpoint.
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "". # It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
oidc_token_endpoint_url = oidc_token_endpoint_url =
@@ -87,13 +92,18 @@ user = your_name
login_fail_exit = true login_fail_exit = true
# communication protocol used to connect to server # communication protocol used to connect to server
# now it supports tcp, kcp and websocket, default is tcp # supports tcp, kcp, quic and websocket now, default is tcp
protocol = tcp protocol = tcp
# set client binding ip when connect server, default is empty. # set client binding ip when connect server, default is empty.
# only when protocol = tcp or websocket, the value will be used. # only when protocol = tcp or websocket, the value will be used.
connect_server_local_ip = 0.0.0.0 connect_server_local_ip = 0.0.0.0
# quic protocol options
# quic_keepalive_period = 10
# quic_max_idle_timeout = 30
# quic_max_incoming_streams = 100000
# if tls_enable is true, frpc will connect frps by tls # if tls_enable is true, frpc will connect frps by tls
tls_enable = true tls_enable = true
@@ -144,6 +154,8 @@ local_ip = 127.0.0.1
local_port = 22 local_port = 22
# limit bandwidth for this proxy, unit is KB and MB # limit bandwidth for this proxy, unit is KB and MB
bandwidth_limit = 1MB bandwidth_limit = 1MB
# where to limit bandwidth, can be 'client' or 'server', default is 'client'
bandwidth_limit_mode = client
# true or false, if true, messages between frps and frpc will be encrypted, default is false # true or false, if true, messages between frps and frpc will be encrypted, default is false
use_encryption = false use_encryption = false
# if true, message will be compressed # if true, message will be compressed

View File

@@ -9,10 +9,18 @@ bind_port = 7000
# udp port to help make udp hole to penetrate nat # udp port to help make udp hole to penetrate nat
bind_udp_port = 7001 bind_udp_port = 7001
# udp port used for kcp protocol, it can be same with 'bind_port' # udp port used for kcp protocol, it can be same with 'bind_port'.
# if not set, kcp is disabled in frps # if not set, kcp is disabled in frps.
kcp_bind_port = 7000 kcp_bind_port = 7000
# udp port used for quic protocol.
# if not set, quic is disabled in frps.
# quic_bind_port = 7002
# quic protocol options
# quic_keepalive_period = 10
# quic_max_idle_timeout = 30
# quic_max_incoming_streams = 100000
# specify which address proxy will listen for, default value is same with bind_addr # specify which address proxy will listen for, default value is same with bind_addr
# proxy_bind_addr = 127.0.0.1 # proxy_bind_addr = 127.0.0.1

BIN
doc/pic/sponsor_asocks.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -110,6 +110,8 @@ Create new proxy
"proxy_type": <string>, "proxy_type": <string>,
"use_encryption": <bool>, "use_encryption": <bool>,
"use_compression": <bool>, "use_compression": <bool>,
"bandwidth_limit": <string>,
"bandwidth_limit_mode": <string>,
"group": <string>, "group": <string>,
"group_key": <string>, "group_key": <string>,

View File

@@ -1,4 +1,4 @@
FROM golang:1.19 AS building FROM golang:1.20 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building

View File

@@ -1,4 +1,4 @@
FROM golang:1.19 AS building FROM golang:1.20 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building

47
go.mod
View File

@@ -1,10 +1,10 @@
module github.com/fatedier/frp module github.com/fatedier/frp
go 1.18 go 1.20
require ( require (
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
github.com/coreos/go-oidc v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.4.0
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb
github.com/fatedier/golib v0.1.1-0.20220321042308-c306138b83ac github.com/fatedier/golib v0.1.1-0.20220321042308-c306138b83ac
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible
@@ -13,19 +13,20 @@ require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/hashicorp/yamux v0.1.1 github.com/hashicorp/yamux v0.1.1
github.com/onsi/ginkgo v1.16.4 github.com/onsi/ginkgo/v2 v2.8.3
github.com/onsi/gomega v1.20.2 github.com/onsi/gomega v1.27.0
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.6.2
github.com/prometheus/client_golang v1.13.0 github.com/prometheus/client_golang v1.13.0
github.com/quic-go/quic-go v0.32.0
github.com/rodaine/table v1.0.1 github.com/rodaine/table v1.0.1
github.com/spf13/cobra v1.1.3 github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.8.0
golang.org/x/net v0.0.0-20220722155237-a158d28d115b golang.org/x/net v0.7.0
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b golang.org/x/oauth2 v0.3.0
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 golang.org/x/time v0.0.0-20220210224613-90d013bbcef8
gopkg.in/ini.v1 v1.67.0 gopkg.in/ini.v1 v1.67.0
k8s.io/apimachinery v0.25.0 k8s.io/apimachinery v0.26.1
k8s.io/client-go v0.25.0 k8s.io/client-go v0.26.1
) )
require ( require (
@@ -33,35 +34,41 @@ require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // 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/fsnotify/fsnotify v1.4.9 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.1 // indirect github.com/golang/snappy v0.0.3 // indirect
github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.6 // indirect github.com/klauspost/cpuid/v2 v2.0.6 // indirect
github.com/klauspost/reedsolomon v1.9.15 // indirect github.com/klauspost/reedsolomon v1.9.15 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/crypto v0.4.0 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/square/go-jose.v2 v2.4.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
) )

347
go.sum
View File

@@ -13,15 +13,37 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 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.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 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.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.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 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.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/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 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/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 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.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.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -31,6 +53,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 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.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
@@ -42,6 +65,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 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-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@@ -63,10 +87,18 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 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/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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
@@ -80,6 +112,12 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 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.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/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw= github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk= github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
@@ -89,8 +127,6 @@ github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s= github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -103,7 +139,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-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-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
@@ -113,6 +150,7 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw= github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -128,6 +166,9 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/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.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/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.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -143,10 +184,11 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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/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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -156,13 +198,20 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/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.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.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/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.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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 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-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-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -170,11 +219,27 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/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-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 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/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
@@ -184,6 +249,7 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -206,8 +272,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -263,19 +329,11 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo/v2 v2.8.3 h1:RpbK1G8nWPNaCVFBWsOGnEQQGgASi6b8fxcWBvDYjxQ=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo/v2 v2.8.3/go.mod h1:6OaUA8BCi0aZfmzYT/q9AacwTzDpNbxILUT+TlBq6MY=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/gomega v1.27.0 h1:QLidEla4bXUuZVFa4KX6JHCsuGgbi85LC/pCHrt/O08=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.27.0/go.mod h1:i189pavgK95OSIipFBa74gC2V4qrQuvjuyGEr3GmbXA=
github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.20.2 h1:8uQq0zMgLEfa0vRrrBgaJF2gyW9Da9BmfGV+OyUzfkY=
github.com/onsi/gomega v1.20.2/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
@@ -288,8 +346,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@@ -320,9 +376,18 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
github.com/rodaine/table v1.0.1 h1:U/VwCnUxlVYxw8+NJiLIuCxA/xa6jL38MY3FYysVWWQ= github.com/rodaine/table v1.0.1 h1:U/VwCnUxlVYxw8+NJiLIuCxA/xa6jL38MY3FYysVWWQ=
github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4= github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
@@ -339,7 +404,6 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
@@ -350,13 +414,16 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
@@ -371,12 +438,16 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -389,8 +460,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -401,6 +472,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/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-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/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 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/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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -413,6 +486,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 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-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/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-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/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.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -421,9 +496,13 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -449,27 +528,55 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/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-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-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/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-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-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-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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-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-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-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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -480,10 +587,11 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -496,10 +604,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/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-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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/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-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-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -518,18 +623,45 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/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-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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/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-20210616094352-59db8d763f22/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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/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-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -537,9 +669,12 @@ 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.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.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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
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/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -588,11 +723,26 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 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-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 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.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.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -609,6 +759,29 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.28.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.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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.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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -640,12 +813,61 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/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-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-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/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-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-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-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-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-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/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 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.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -658,6 +880,26 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 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.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/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 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-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 v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -670,6 +912,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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-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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@@ -679,18 +923,16 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/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.3/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.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.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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -706,13 +948,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ=
k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E= k8s.io/client-go v0.26.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU=
k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8= k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 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/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -5,7 +5,7 @@ ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd)
which ginkgo &> /dev/null which ginkgo &> /dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "ginkgo not found, try to install..." echo "ginkgo not found, try to install..."
go install github.com/onsi/ginkgo/ginkgo@v1.16.5 go install github.com/onsi/ginkgo/v2/ginkgo@v2.8.3
fi fi
debug=false debug=false
@@ -17,4 +17,4 @@ if [ x${LOG_LEVEL} != x"" ]; then
logLevel=${LOG_LEVEL} logLevel=${LOG_LEVEL}
fi fi
ginkgo -nodes=8 -slowSpecThreshold=20 ${ROOT}/test/e2e -- -frpc-path=${ROOT}/bin/frpc -frps-path=${ROOT}/bin/frps -log-level=${logLevel} -debug=${debug} ginkgo -nodes=8 --poll-progress-after=20s ${ROOT}/test/e2e -- -frpc-path=${ROOT}/bin/frpc -frps-path=${ROOT}/bin/frps -log-level=${logLevel} -debug=${debug}

View File

@@ -18,7 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/coreos/go-oidc" "github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2/clientcredentials" "golang.org/x/oauth2/clientcredentials"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
@@ -36,6 +36,9 @@ type OidcClientConfig struct {
// OidcAudience specifies the audience of the token in OIDC authentication // OidcAudience specifies the audience of the token in OIDC authentication
// if AuthenticationMethod == "oidc". By default, this value is "". // if AuthenticationMethod == "oidc". By default, this value is "".
OidcAudience string `ini:"oidc_audience" json:"oidc_audience"` OidcAudience string `ini:"oidc_audience" json:"oidc_audience"`
// OidcScope specifies the scope of the token in OIDC authentication
// if AuthenticationMethod == "oidc". By default, this value is "".
OidcScope string `ini:"oidc_scope" json:"oidc_scope"`
// OidcTokenEndpointURL specifies the URL which implements OIDC Token Endpoint. // OidcTokenEndpointURL specifies the URL which implements OIDC Token Endpoint.
// It will be used to get an OIDC token if AuthenticationMethod == "oidc". // It will be used to get an OIDC token if AuthenticationMethod == "oidc".
// By default, this value is "". // By default, this value is "".
@@ -52,6 +55,7 @@ func getDefaultOidcClientConf() OidcClientConfig {
OidcClientID: "", OidcClientID: "",
OidcClientSecret: "", OidcClientSecret: "",
OidcAudience: "", OidcAudience: "",
OidcScope: "",
OidcTokenEndpointURL: "", OidcTokenEndpointURL: "",
OidcAdditionalEndpointParams: make(map[string]string), OidcAdditionalEndpointParams: make(map[string]string),
} }
@@ -99,10 +103,14 @@ func NewOidcAuthSetter(baseCfg BaseConfig, cfg OidcClientConfig) *OidcAuthProvid
eps[k] = []string{v} eps[k] = []string{v}
} }
if cfg.OidcAudience != "" {
eps["audience"] = []string{cfg.OidcAudience}
}
tokenGenerator := &clientcredentials.Config{ tokenGenerator := &clientcredentials.Config{
ClientID: cfg.OidcClientID, ClientID: cfg.OidcClientID,
ClientSecret: cfg.OidcClientSecret, ClientSecret: cfg.OidcClientSecret,
Scopes: []string{cfg.OidcAudience}, Scopes: []string{cfg.OidcScope},
TokenURL: cfg.OidcTokenEndpointURL, TokenURL: cfg.OidcTokenEndpointURL,
EndpointParams: eps, EndpointParams: eps,
} }

View File

@@ -115,9 +115,13 @@ type ClientCommonConf struct {
Start []string `ini:"start" json:"start"` Start []string `ini:"start" json:"start"`
// Start map[string]struct{} `json:"start"` // Start map[string]struct{} `json:"start"`
// Protocol specifies the protocol to use when interacting with the server. // Protocol specifies the protocol to use when interacting with the server.
// Valid values are "tcp", "kcp" and "websocket". By default, this value // Valid values are "tcp", "kcp", "quic" and "websocket". By default, this value
// is "tcp". // is "tcp".
Protocol string `ini:"protocol" json:"protocol"` Protocol string `ini:"protocol" json:"protocol"`
// QUIC protocol options
QUICKeepalivePeriod int `ini:"quic_keepalive_period" json:"quic_keepalive_period" validate:"gte=0"`
QUICMaxIdleTimeout int `ini:"quic_max_idle_timeout" json:"quic_max_idle_timeout" validate:"gte=0"`
QUICMaxIncomingStreams int `ini:"quic_max_incoming_streams" json:"quic_max_incoming_streams" validate:"gte=0"`
// TLSEnable specifies whether or not TLS should be used when communicating // TLSEnable specifies whether or not TLS should be used when communicating
// with the server. If "tls_cert_file" and "tls_key_file" are valid, // with the server. If "tls_cert_file" and "tls_key_file" are valid,
// client will load the supplied tls configuration. // client will load the supplied tls configuration.
@@ -172,30 +176,21 @@ func GetDefaultClientConf() ClientCommonConf {
LogWay: "console", LogWay: "console",
LogLevel: "info", LogLevel: "info",
LogMaxDays: 3, LogMaxDays: 3,
DisableLogColor: false,
AdminAddr: "127.0.0.1", AdminAddr: "127.0.0.1",
AdminPort: 0,
AdminUser: "",
AdminPwd: "",
AssetsDir: "",
PoolCount: 1, PoolCount: 1,
TCPMux: true, TCPMux: true,
TCPMuxKeepaliveInterval: 60, TCPMuxKeepaliveInterval: 60,
User: "",
DNSServer: "",
LoginFailExit: true, LoginFailExit: true,
Start: make([]string, 0), Start: make([]string, 0),
Protocol: "tcp", Protocol: "tcp",
TLSEnable: false, QUICKeepalivePeriod: 10,
TLSCertFile: "", QUICMaxIdleTimeout: 30,
TLSKeyFile: "", QUICMaxIncomingStreams: 100000,
TLSTrustedCaFile: "",
HeartbeatInterval: 30, HeartbeatInterval: 30,
HeartbeatTimeout: 90, HeartbeatTimeout: 90,
Metas: make(map[string]string), Metas: make(map[string]string),
UDPPacketSize: 1500, UDPPacketSize: 1500,
IncludeConfigFiles: make([]string, 0), IncludeConfigFiles: make([]string, 0),
PprofEnable: false,
} }
} }
@@ -228,7 +223,7 @@ func (cfg *ClientCommonConf) Validate() error {
} }
} }
if cfg.Protocol != "tcp" && cfg.Protocol != "kcp" && cfg.Protocol != "websocket" { if cfg.Protocol != "tcp" && cfg.Protocol != "kcp" && cfg.Protocol != "websocket" && cfg.Protocol != "quic" {
return fmt.Errorf("invalid protocol") return fmt.Errorf("invalid protocol")
} }

View File

@@ -74,6 +74,7 @@ var testClientBytesWithFull = []byte(`
local_ip = 127.0.0.9 local_ip = 127.0.0.9
local_port = 29 local_port = 29
bandwidth_limit = 19MB bandwidth_limit = 19MB
bandwidth_limit_mode = server
use_encryption use_encryption
use_compression use_compression
remote_port = 6009 remote_port = 6009
@@ -278,6 +279,9 @@ func Test_LoadClientCommonConf(t *testing.T) {
User: "your_name", User: "your_name",
LoginFailExit: true, LoginFailExit: true,
Protocol: "tcp", Protocol: "tcp",
QUICKeepalivePeriod: 10,
QUICMaxIdleTimeout: 30,
QUICMaxIncomingStreams: 100000,
TLSEnable: true, TLSEnable: true,
TLSCertFile: "client.crt", TLSCertFile: "client.crt",
TLSKeyFile: "client.key", TLSKeyFile: "client.key",
@@ -306,13 +310,14 @@ func Test_LoadClientBasicConf(t *testing.T) {
proxyExpected := map[string]ProxyConf{ proxyExpected := map[string]ProxyConf{
testUser + ".ssh": &TCPProxyConf{ testUser + ".ssh": &TCPProxyConf{
BaseProxyConf: BaseProxyConf{ BaseProxyConf: BaseProxyConf{
ProxyName: testUser + ".ssh", ProxyName: testUser + ".ssh",
ProxyType: consts.TCPProxy, ProxyType: consts.TCPProxy,
UseCompression: true, UseCompression: true,
UseEncryption: true, UseEncryption: true,
Group: "test_group", Group: "test_group",
GroupKey: "123456", GroupKey: "123456",
BandwidthLimit: MustBandwidthQuantity("19MB"), BandwidthLimit: MustBandwidthQuantity("19MB"),
BandwidthLimitMode: BandwidthLimitModeServer,
Metas: map[string]string{ Metas: map[string]string{
"var1": "123", "var1": "123",
"var2": "234", "var2": "234",
@@ -339,6 +344,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 29, LocalPort: 29,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 9, RemotePort: 9,
}, },
@@ -350,6 +356,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@@ -361,6 +368,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },
@@ -372,6 +380,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6019, LocalPort: 6019,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6019, RemotePort: 6019,
}, },
@@ -385,6 +394,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 59, LocalPort: 59,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6009, RemotePort: 6009,
}, },
@@ -398,6 +408,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6000, LocalPort: 6000,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6000, RemotePort: 6000,
}, },
@@ -411,6 +422,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@@ -424,6 +436,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },
@@ -444,6 +457,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
HealthCheckIntervalS: 19, HealthCheckIntervalS: 19,
HealthCheckURL: "http://127.0.0.9:89/status", HealthCheckURL: "http://127.0.0.9:89/status",
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@@ -468,6 +482,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalPort: 8009, LocalPort: 8009,
}, },
ProxyProtocolVersion: "v2", ProxyProtocolVersion: "v2",
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@@ -482,6 +497,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@@ -494,6 +510,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@@ -506,6 +523,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 10701, LocalPort: 10701,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"tunnel1"}, CustomDomains: []string{"tunnel1"},
@@ -524,6 +542,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_unix_path": "/var/run/docker.sock", "plugin_unix_path": "/var/run/docker.sock",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6003, RemotePort: 6003,
}, },
@@ -539,6 +558,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_http_passwd": "abc", "plugin_http_passwd": "abc",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6004, RemotePort: 6004,
}, },
@@ -554,6 +574,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_passwd": "abc", "plugin_passwd": "abc",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6005, RemotePort: 6005,
}, },
@@ -571,6 +592,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_http_passwd": "abc", "plugin_http_passwd": "abc",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6006, RemotePort: 6006,
}, },
@@ -589,6 +611,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_header_X-From-Where": "frp", "plugin_header_X-From-Where": "frp",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"test.yourdomain.com"}, CustomDomains: []string{"test.yourdomain.com"},
@@ -607,6 +630,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_header_X-From-Where": "frp", "plugin_header_X-From-Where": "frp",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"test.yourdomain.com"}, CustomDomains: []string{"test.yourdomain.com"},

View File

@@ -141,6 +141,10 @@ type BaseProxyConf struct {
// BandwidthLimit limit the bandwidth // BandwidthLimit limit the bandwidth
// 0 means no limit // 0 means no limit
BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"` BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"`
// BandwidthLimitMode specifies whether to limit the bandwidth on the
// client or server side. Valid values include "client" and "server".
// By default, this value is "client".
BandwidthLimitMode string `ini:"bandwidth_limit_mode" json:"bandwidth_limit_mode"`
// meta info for each proxy // meta info for each proxy
Metas map[string]string `ini:"-" json:"metas"` Metas map[string]string `ini:"-" json:"metas"`
@@ -183,6 +187,8 @@ type TCPProxyConf struct {
type TCPMuxProxyConf struct { type TCPMuxProxyConf struct {
BaseProxyConf `ini:",extends"` BaseProxyConf `ini:",extends"`
DomainConf `ini:",extends"` DomainConf `ini:",extends"`
HTTPUser string `ini:"http_user" json:"http_user,omitempty"`
HTTPPwd string `ini:"http_pwd" json:"http_pwd,omitempty"`
RouteByHTTPUser string `ini:"route_by_http_user" json:"route_by_http_user"` RouteByHTTPUser string `ini:"route_by_http_user" json:"route_by_http_user"`
Multiplexer string `ini:"multiplexer"` Multiplexer string `ini:"multiplexer"`
@@ -319,6 +325,7 @@ func defaultBaseProxyConf(proxyType string) BaseProxyConf {
LocalSvrConf: LocalSvrConf{ LocalSvrConf: LocalSvrConf{
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
} }
} }
@@ -335,6 +342,7 @@ func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool {
cfg.GroupKey != cmp.GroupKey || cfg.GroupKey != cmp.GroupKey ||
cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion || cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion ||
!cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) || !cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) ||
cfg.BandwidthLimitMode != cmp.BandwidthLimitMode ||
!reflect.DeepEqual(cfg.Metas, cmp.Metas) { !reflect.DeepEqual(cfg.Metas, cmp.Metas) {
return false return false
} }
@@ -389,6 +397,11 @@ func (cfg *BaseProxyConf) marshalToMsg(pMsg *msg.NewProxy) {
pMsg.ProxyType = cfg.ProxyType pMsg.ProxyType = cfg.ProxyType
pMsg.UseEncryption = cfg.UseEncryption pMsg.UseEncryption = cfg.UseEncryption
pMsg.UseCompression = cfg.UseCompression pMsg.UseCompression = cfg.UseCompression
pMsg.BandwidthLimit = cfg.BandwidthLimit.String()
// leave it empty for default value to reduce traffic
if cfg.BandwidthLimitMode != "client" {
pMsg.BandwidthLimitMode = cfg.BandwidthLimitMode
}
pMsg.Group = cfg.Group pMsg.Group = cfg.Group
pMsg.GroupKey = cfg.GroupKey pMsg.GroupKey = cfg.GroupKey
pMsg.Metas = cfg.Metas pMsg.Metas = cfg.Metas
@@ -399,6 +412,12 @@ func (cfg *BaseProxyConf) unmarshalFromMsg(pMsg *msg.NewProxy) {
cfg.ProxyType = pMsg.ProxyType cfg.ProxyType = pMsg.ProxyType
cfg.UseEncryption = pMsg.UseEncryption cfg.UseEncryption = pMsg.UseEncryption
cfg.UseCompression = pMsg.UseCompression cfg.UseCompression = pMsg.UseCompression
if pMsg.BandwidthLimit != "" {
cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit)
}
if pMsg.BandwidthLimitMode != "" {
cfg.BandwidthLimitMode = pMsg.BandwidthLimitMode
}
cfg.Group = pMsg.Group cfg.Group = pMsg.Group
cfg.GroupKey = pMsg.GroupKey cfg.GroupKey = pMsg.GroupKey
cfg.Metas = pMsg.Metas cfg.Metas = pMsg.Metas
@@ -411,6 +430,10 @@ func (cfg *BaseProxyConf) checkForCli() (err error) {
} }
} }
if cfg.BandwidthLimitMode != "client" && cfg.BandwidthLimitMode != "server" {
return fmt.Errorf("bandwidth_limit_mode should be client or server")
}
if err = cfg.LocalSvrConf.checkForCli(); err != nil { if err = cfg.LocalSvrConf.checkForCli(); err != nil {
return return
} }
@@ -420,6 +443,13 @@ func (cfg *BaseProxyConf) checkForCli() (err error) {
return nil return nil
} }
func (cfg *BaseProxyConf) checkForSvr() (err error) {
if cfg.BandwidthLimitMode != "client" && cfg.BandwidthLimitMode != "server" {
return fmt.Errorf("bandwidth_limit_mode should be client or server")
}
return nil
}
// DomainConf // DomainConf
func (cfg *DomainConf) check() (err error) { func (cfg *DomainConf) check() (err error) {
if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" { if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" {
@@ -557,6 +587,9 @@ func (cfg *TCPProxyConf) CheckForCli() (err error) {
} }
func (cfg *TCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *TCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@@ -576,7 +609,10 @@ func (cfg *TCPMuxProxyConf) Compare(cmp ProxyConf) bool {
return false return false
} }
if cfg.Multiplexer != cmpConf.Multiplexer || cfg.RouteByHTTPUser != cmpConf.RouteByHTTPUser { if cfg.Multiplexer != cmpConf.Multiplexer ||
cfg.HTTPUser != cmpConf.HTTPUser ||
cfg.HTTPPwd != cmpConf.HTTPPwd ||
cfg.RouteByHTTPUser != cmpConf.RouteByHTTPUser {
return false return false
} }
@@ -601,6 +637,8 @@ func (cfg *TCPMuxProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
cfg.CustomDomains = pMsg.CustomDomains cfg.CustomDomains = pMsg.CustomDomains
cfg.SubDomain = pMsg.SubDomain cfg.SubDomain = pMsg.SubDomain
cfg.Multiplexer = pMsg.Multiplexer cfg.Multiplexer = pMsg.Multiplexer
cfg.HTTPUser = pMsg.HTTPUser
cfg.HTTPPwd = pMsg.HTTPPwd
cfg.RouteByHTTPUser = pMsg.RouteByHTTPUser cfg.RouteByHTTPUser = pMsg.RouteByHTTPUser
} }
@@ -611,6 +649,8 @@ func (cfg *TCPMuxProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
pMsg.CustomDomains = cfg.CustomDomains pMsg.CustomDomains = cfg.CustomDomains
pMsg.SubDomain = cfg.SubDomain pMsg.SubDomain = cfg.SubDomain
pMsg.Multiplexer = cfg.Multiplexer pMsg.Multiplexer = cfg.Multiplexer
pMsg.HTTPUser = cfg.HTTPUser
pMsg.HTTPPwd = cfg.HTTPPwd
pMsg.RouteByHTTPUser = cfg.RouteByHTTPUser pMsg.RouteByHTTPUser = cfg.RouteByHTTPUser
} }
@@ -632,6 +672,10 @@ func (cfg *TCPMuxProxyConf) CheckForCli() (err error) {
} }
func (cfg *TCPMuxProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { func (cfg *TCPMuxProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer { if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer {
return fmt.Errorf("proxy [%s] incorrect multiplexer [%s]", cfg.ProxyName, cfg.Multiplexer) return fmt.Errorf("proxy [%s] incorrect multiplexer [%s]", cfg.ProxyName, cfg.Multiplexer)
} }
@@ -703,6 +747,9 @@ func (cfg *UDPProxyConf) CheckForCli() (err error) {
} }
func (cfg *UDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *UDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@@ -788,6 +835,10 @@ func (cfg *HTTPProxyConf) CheckForCli() (err error) {
} }
func (cfg *HTTPProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { func (cfg *HTTPProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
if serverCfg.VhostHTTPPort == 0 { if serverCfg.VhostHTTPPort == 0 {
return fmt.Errorf("type [http] not support when vhost_http_port is not set") return fmt.Errorf("type [http] not support when vhost_http_port is not set")
} }
@@ -860,6 +911,10 @@ func (cfg *HTTPSProxyConf) CheckForCli() (err error) {
} }
func (cfg *HTTPSProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { func (cfg *HTTPSProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
if serverCfg.VhostHTTPSPort == 0 { if serverCfg.VhostHTTPSPort == 0 {
return fmt.Errorf("type [https] not support when vhost_https_port is not set") return fmt.Errorf("type [https] not support when vhost_https_port is not set")
} }
@@ -932,6 +987,9 @@ func (cfg *SUDPProxyConf) CheckForCli() (err error) {
} }
func (cfg *SUDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *SUDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@@ -998,6 +1056,9 @@ func (cfg *STCPProxyConf) CheckForCli() (err error) {
} }
func (cfg *STCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *STCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@@ -1064,5 +1125,8 @@ func (cfg *XTCPProxyConf) CheckForCli() (err error) {
} }
func (cfg *XTCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *XTCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }

View File

@@ -58,6 +58,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
local_ip = 127.0.0.9 local_ip = 127.0.0.9
local_port = 29 local_port = 29
bandwidth_limit = 19MB bandwidth_limit = 19MB
bandwidth_limit_mode = server
use_encryption use_encryption
use_compression use_compression
remote_port = 6009 remote_port = 6009
@@ -71,13 +72,14 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
meta_var2 = 234`), meta_var2 = 234`),
expected: &TCPProxyConf{ expected: &TCPProxyConf{
BaseProxyConf: BaseProxyConf{ BaseProxyConf: BaseProxyConf{
ProxyName: testProxyPrefix + "ssh", ProxyName: testProxyPrefix + "ssh",
ProxyType: consts.TCPProxy, ProxyType: consts.TCPProxy,
UseCompression: true, UseCompression: true,
UseEncryption: true, UseEncryption: true,
Group: "test_group", Group: "test_group",
GroupKey: "123456", GroupKey: "123456",
BandwidthLimit: MustBandwidthQuantity("19MB"), BandwidthLimit: MustBandwidthQuantity("19MB"),
BandwidthLimitMode: BandwidthLimitModeServer,
Metas: map[string]string{ Metas: map[string]string{
"var1": "123", "var1": "123",
"var2": "234", "var2": "234",
@@ -114,6 +116,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 29, LocalPort: 29,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 9, RemotePort: 9,
}, },
@@ -139,6 +142,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 59, LocalPort: 59,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6009, RemotePort: 6009,
}, },
@@ -182,6 +186,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
HealthCheckIntervalS: 19, HealthCheckIntervalS: 19,
HealthCheckURL: "http://127.0.0.9:89/status", HealthCheckURL: "http://127.0.0.9:89/status",
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@@ -220,6 +225,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalPort: 8009, LocalPort: 8009,
}, },
ProxyProtocolVersion: "v2", ProxyProtocolVersion: "v2",
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@@ -246,6 +252,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@@ -270,6 +277,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@@ -293,6 +301,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 10701, LocalPort: 10701,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"tunnel1"}, CustomDomains: []string{"tunnel1"},
@@ -347,6 +356,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@@ -358,6 +368,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },
@@ -369,6 +380,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6019, LocalPort: 6019,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6019, RemotePort: 6019,
}, },
@@ -396,6 +408,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6000, LocalPort: 6000,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6000, RemotePort: 6000,
}, },
@@ -409,6 +422,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@@ -422,6 +436,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },

View File

@@ -46,6 +46,14 @@ type ServerCommonConf struct {
// value is 0, the server will not listen for KCP connections. By default, // value is 0, the server will not listen for KCP connections. By default,
// this value is 0. // this value is 0.
KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port" validate:"gte=0,lte=65535"` KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port" validate:"gte=0,lte=65535"`
// QUICBindPort specifies the QUIC port that the server listens on.
// Set this value to 0 will disable this feature.
// By default, the value is 0.
QUICBindPort int `ini:"quic_bind_port" json:"quic_bind_port" validate:"gte=0,lte=65535"`
// QUIC protocol options
QUICKeepalivePeriod int `ini:"quic_keepalive_period" json:"quic_keepalive_period" validate:"gte=0"`
QUICMaxIdleTimeout int `ini:"quic_max_idle_timeout" json:"quic_max_idle_timeout" validate:"gte=0"`
QUICMaxIncomingStreams int `ini:"quic_max_incoming_streams" json:"quic_max_incoming_streams" validate:"gte=0"`
// ProxyBindAddr specifies the address that the proxy binds to. This value // ProxyBindAddr specifies the address that the proxy binds to. This value
// may be the same as BindAddr. // may be the same as BindAddr.
ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"` ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"`
@@ -146,6 +154,8 @@ type ServerCommonConf struct {
// If the length of this value is 0, all ports are allowed. By default, // If the length of this value is 0, all ports are allowed. By default,
// this value is an empty set. // this value is an empty set.
AllowPorts map[int]struct{} `ini:"-" json:"-"` AllowPorts map[int]struct{} `ini:"-" json:"-"`
// Original string.
AllowPortsStr string `ini:"-" json:"-"`
// MaxPoolCount specifies the maximum pool size for each proxy. By default, // MaxPoolCount specifies the maximum pool size for each proxy. By default,
// this value is 5. // this value is 5.
MaxPoolCount int64 `ini:"max_pool_count" json:"max_pool_count"` MaxPoolCount int64 `ini:"max_pool_count" json:"max_pool_count"`
@@ -195,43 +205,26 @@ func GetDefaultServerConf() ServerCommonConf {
ServerConfig: auth.GetDefaultServerConf(), ServerConfig: auth.GetDefaultServerConf(),
BindAddr: "0.0.0.0", BindAddr: "0.0.0.0",
BindPort: 7000, BindPort: 7000,
BindUDPPort: 0, QUICKeepalivePeriod: 10,
KCPBindPort: 0, QUICMaxIdleTimeout: 30,
ProxyBindAddr: "", QUICMaxIncomingStreams: 100000,
VhostHTTPPort: 0,
VhostHTTPSPort: 0,
TCPMuxHTTPConnectPort: 0,
TCPMuxPassthrough: false,
VhostHTTPTimeout: 60, VhostHTTPTimeout: 60,
DashboardAddr: "0.0.0.0", DashboardAddr: "0.0.0.0",
DashboardPort: 0,
DashboardUser: "",
DashboardPwd: "",
EnablePrometheus: false,
AssetsDir: "",
LogFile: "console", LogFile: "console",
LogWay: "console", LogWay: "console",
LogLevel: "info", LogLevel: "info",
LogMaxDays: 3, LogMaxDays: 3,
DisableLogColor: false,
DetailedErrorsToClient: true, DetailedErrorsToClient: true,
SubDomainHost: "",
TCPMux: true, TCPMux: true,
TCPMuxKeepaliveInterval: 60, TCPMuxKeepaliveInterval: 60,
TCPKeepAlive: 7200, TCPKeepAlive: 7200,
AllowPorts: make(map[int]struct{}), AllowPorts: make(map[int]struct{}),
MaxPoolCount: 5, MaxPoolCount: 5,
MaxPortsPerClient: 0, MaxPortsPerClient: 0,
TLSOnly: false,
TLSCertFile: "",
TLSKeyFile: "",
TLSTrustedCaFile: "",
HeartbeatTimeout: 90, HeartbeatTimeout: 90,
UserConnTimeout: 10, UserConnTimeout: 10,
Custom404Page: "",
HTTPPlugins: make(map[string]plugin.HTTPPluginOptions), HTTPPlugins: make(map[string]plugin.HTTPPluginOptions),
UDPPacketSize: 1500, UDPPacketSize: 1500,
PprofEnable: false,
} }
} }
@@ -268,6 +261,7 @@ func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) {
for _, port := range allowPorts { for _, port := range allowPorts {
common.AllowPorts[int(port)] = struct{}{} common.AllowPorts[int(port)] = struct{}{}
} }
common.AllowPortsStr = allowPortStr
} }
// plugin.xxx // plugin.xxx

View File

@@ -106,6 +106,9 @@ func Test_LoadServerCommonConf(t *testing.T) {
BindPort: 7009, BindPort: 7009,
BindUDPPort: 7008, BindUDPPort: 7008,
KCPBindPort: 7007, KCPBindPort: 7007,
QUICKeepalivePeriod: 10,
QUICMaxIdleTimeout: 30,
QUICMaxIncomingStreams: 100000,
ProxyBindAddr: "127.0.0.9", ProxyBindAddr: "127.0.0.9",
VhostHTTPPort: 89, VhostHTTPPort: 89,
VhostHTTPSPort: 449, VhostHTTPSPort: 449,
@@ -131,6 +134,7 @@ func Test_LoadServerCommonConf(t *testing.T) {
12: {}, 12: {},
99: {}, 99: {},
}, },
AllowPortsStr: "10-12,99",
MaxPoolCount: 59, MaxPoolCount: 59,
MaxPortsPerClient: 9, MaxPortsPerClient: 9,
TLSOnly: true, TLSOnly: true,
@@ -179,6 +183,9 @@ func Test_LoadServerCommonConf(t *testing.T) {
BindAddr: "0.0.0.9", BindAddr: "0.0.0.9",
BindPort: 7009, BindPort: 7009,
BindUDPPort: 7008, BindUDPPort: 7008,
QUICKeepalivePeriod: 10,
QUICMaxIdleTimeout: 30,
QUICMaxIncomingStreams: 100000,
ProxyBindAddr: "0.0.0.9", ProxyBindAddr: "0.0.0.9",
VhostHTTPTimeout: 60, VhostHTTPTimeout: 60,
DashboardAddr: "0.0.0.0", DashboardAddr: "0.0.0.0",

View File

@@ -24,6 +24,9 @@ import (
const ( const (
MB = 1024 * 1024 MB = 1024 * 1024
KB = 1024 KB = 1024
BandwidthLimitModeClient = "client"
BandwidthLimitModeServer = "server"
) )
type BandwidthQuantity struct { type BandwidthQuantity struct {

View File

@@ -14,7 +14,9 @@
package msg package msg
import "net" import (
"net"
)
const ( const (
TypeLogin = 'o' TypeLogin = 'o'
@@ -83,13 +85,15 @@ type LoginResp struct {
// When frpc login success, send this message to frps for running a new proxy. // When frpc login success, send this message to frps for running a new proxy.
type NewProxy struct { type NewProxy struct {
ProxyName string `json:"proxy_name,omitempty"` ProxyName string `json:"proxy_name,omitempty"`
ProxyType string `json:"proxy_type,omitempty"` ProxyType string `json:"proxy_type,omitempty"`
UseEncryption bool `json:"use_encryption,omitempty"` UseEncryption bool `json:"use_encryption,omitempty"`
UseCompression bool `json:"use_compression,omitempty"` UseCompression bool `json:"use_compression,omitempty"`
Group string `json:"group,omitempty"` BandwidthLimit string `json:"bandwidth_limit,omitempty"`
GroupKey string `json:"group_key,omitempty"` BandwidthLimitMode string `json:"bandwidth_limit_mode,omitempty"`
Metas map[string]string `json:"metas,omitempty"` Group string `json:"group,omitempty"`
GroupKey string `json:"group_key,omitempty"`
Metas map[string]string `json:"metas,omitempty"`
// tcp and udp only // tcp and udp only
RemotePort int `json:"remote_port,omitempty"` RemotePort int `json:"remote_port,omitempty"`

View File

@@ -211,7 +211,7 @@ func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent,
ctx = NewReqidContext(ctx, reqid) ctx = NewReqidContext(ctx, reqid)
for _, p := range m.newWorkConnPlugins { for _, p := range m.newWorkConnPlugins {
res, retContent, err = p.Handle(ctx, OpPing, *content) res, retContent, err = p.Handle(ctx, OpNewWorkConn, *content)
if err != nil { if err != nil {
xl.Warn("send NewWorkConn request to plugin [%s] error: %v", p.Name(), err) xl.Warn("send NewWorkConn request to plugin [%s] error: %v", p.Name(), err)
return nil, errors.New("send NewWorkConn request to plugin error") return nil, errors.New("send NewWorkConn request to plugin error")

View File

@@ -22,6 +22,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
quic "github.com/quic-go/quic-go"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
) )
@@ -183,3 +185,34 @@ func (statsConn *StatsConn) Close() (err error) {
} }
return return
} }
type wrapQuicStream struct {
quic.Stream
c quic.Connection
}
func QuicStreamToNetConn(s quic.Stream, c quic.Connection) net.Conn {
return &wrapQuicStream{
Stream: s,
c: c,
}
}
func (conn *wrapQuicStream) LocalAddr() net.Addr {
if conn.c != nil {
return conn.c.LocalAddr()
}
return (*net.TCPAddr)(nil)
}
func (conn *wrapQuicStream) RemoteAddr() net.Addr {
if conn.c != nil {
return conn.c.RemoteAddr()
}
return (*net.TCPAddr)(nil)
}
func (conn *wrapQuicStream) Close() error {
conn.Stream.CancelRead(0)
return conn.Stream.Close()
}

View File

@@ -31,18 +31,21 @@ import (
type HTTPConnectTCPMuxer struct { type HTTPConnectTCPMuxer struct {
*vhost.Muxer *vhost.Muxer
passthrough bool // If passthrough is set to true, the CONNECT request will be forwarded to the backend service.
authRequired bool // Not supported until we really need this. // Otherwise, it will return an OK response to the client and forward the remaining content to the backend service.
passthrough bool
} }
func NewHTTPConnectTCPMuxer(listener net.Listener, passthrough bool, timeout time.Duration) (*HTTPConnectTCPMuxer, error) { func NewHTTPConnectTCPMuxer(listener net.Listener, passthrough bool, timeout time.Duration) (*HTTPConnectTCPMuxer, error) {
ret := &HTTPConnectTCPMuxer{passthrough: passthrough, authRequired: false} ret := &HTTPConnectTCPMuxer{passthrough: passthrough}
mux, err := vhost.NewMuxer(listener, ret.getHostFromHTTPConnect, nil, ret.sendConnectResponse, nil, timeout) mux, err := vhost.NewMuxer(listener, ret.getHostFromHTTPConnect, timeout)
mux.SetCheckAuthFunc(ret.auth).
SetSuccessHookFunc(ret.sendConnectResponse)
ret.Muxer = mux ret.Muxer = mux
return ret, err return ret, err
} }
func (muxer *HTTPConnectTCPMuxer) readHTTPConnectRequest(rd io.Reader) (host string, httpUser string, err error) { func (muxer *HTTPConnectTCPMuxer) readHTTPConnectRequest(rd io.Reader) (host, httpUser, httpPwd string, err error) {
bufioReader := bufio.NewReader(rd) bufioReader := bufio.NewReader(rd)
req, err := http.ReadRequest(bufioReader) req, err := http.ReadRequest(bufioReader)
@@ -58,7 +61,7 @@ func (muxer *HTTPConnectTCPMuxer) readHTTPConnectRequest(rd io.Reader) (host str
host, _ = util.CanonicalHost(req.Host) host, _ = util.CanonicalHost(req.Host)
proxyAuth := req.Header.Get("Proxy-Authorization") proxyAuth := req.Header.Get("Proxy-Authorization")
if proxyAuth != "" { if proxyAuth != "" {
httpUser, _, _ = util.ParseBasicAuth(proxyAuth) httpUser, httpPwd, _ = util.ParseBasicAuth(proxyAuth)
} }
return return
} }
@@ -74,11 +77,26 @@ func (muxer *HTTPConnectTCPMuxer) sendConnectResponse(c net.Conn, reqInfo map[st
return res.Write(c) return res.Write(c)
} }
func (muxer *HTTPConnectTCPMuxer) auth(c net.Conn, username, password string, reqInfo map[string]string) (bool, error) {
reqUsername := reqInfo["HTTPUser"]
reqPassword := reqInfo["HTTPPwd"]
if username == reqUsername && password == reqPassword {
return true, nil
}
resp := util.ProxyUnauthorizedResponse()
if resp.Body != nil {
defer resp.Body.Close()
}
_ = resp.Write(c)
return false, nil
}
func (muxer *HTTPConnectTCPMuxer) getHostFromHTTPConnect(c net.Conn) (net.Conn, map[string]string, error) { func (muxer *HTTPConnectTCPMuxer) getHostFromHTTPConnect(c net.Conn) (net.Conn, map[string]string, error) {
reqInfoMap := make(map[string]string, 0) reqInfoMap := make(map[string]string, 0)
sc, rd := gnet.NewSharedConn(c) sc, rd := gnet.NewSharedConn(c)
host, httpUser, err := muxer.readHTTPConnectRequest(rd) host, httpUser, httpPwd, err := muxer.readHTTPConnectRequest(rd)
if err != nil { if err != nil {
return nil, reqInfoMap, err return nil, reqInfoMap, err
} }
@@ -86,18 +104,11 @@ func (muxer *HTTPConnectTCPMuxer) getHostFromHTTPConnect(c net.Conn) (net.Conn,
reqInfoMap["Host"] = host reqInfoMap["Host"] = host
reqInfoMap["Scheme"] = "tcp" reqInfoMap["Scheme"] = "tcp"
reqInfoMap["HTTPUser"] = httpUser reqInfoMap["HTTPUser"] = httpUser
reqInfoMap["HTTPPwd"] = httpPwd
outConn := c outConn := c
if muxer.passthrough { if muxer.passthrough {
outConn = sc outConn = sc
if muxer.authRequired && httpUser == "" {
resp := util.ProxyUnauthorizedResponse()
if resp.Body != nil {
defer resp.Body.Close()
}
_ = resp.Write(c)
outConn = c
}
} }
return outConn, reqInfoMap, nil return outConn, reqInfoMap, nil
} }

25
pkg/util/util/slice.go Normal file
View File

@@ -0,0 +1,25 @@
package util
func InSlice[T comparable](v T, s []T) bool {
for _, vv := range s {
if v == vv {
return true
}
}
return false
}
func InSliceAny[T any](v T, s []T, equalFn func(a, b T) bool) bool {
for _, vv := range s {
if equalFn(v, vv) {
return true
}
}
return false
}
func InSliceAnyFunc[T any](equalFn func(a, b T) bool) func(v T, s []T) bool {
return func(v T, s []T) bool {
return InSliceAny(v, s, equalFn)
}
}

View File

@@ -0,0 +1,49 @@
package util
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestInSlice(t *testing.T) {
require := require.New(t)
require.True(InSlice(1, []int{1, 2, 3}))
require.False(InSlice(0, []int{1, 2, 3}))
require.True(InSlice("foo", []string{"foo", "bar"}))
require.False(InSlice("not exist", []string{"foo", "bar"}))
}
type testStructA struct {
Name string
Age int
}
func TestInSliceAny(t *testing.T) {
require := require.New(t)
a := testStructA{Name: "foo", Age: 20}
b := testStructA{Name: "foo", Age: 30}
c := testStructA{Name: "bar", Age: 20}
equalFn := func(o, p testStructA) bool {
return o.Name == p.Name
}
require.True(InSliceAny(a, []testStructA{b, c}, equalFn))
require.False(InSliceAny(c, []testStructA{a, b}, equalFn))
}
func TestInSliceAnyFunc(t *testing.T) {
require := require.New(t)
a := testStructA{Name: "foo", Age: 20}
b := testStructA{Name: "foo", Age: 30}
c := testStructA{Name: "bar", Age: 20}
equalFn := func(o, p testStructA) bool {
return o.Name == p.Name
}
testStructAInSlice := InSliceAnyFunc(equalFn)
require.True(testStructAInSlice(a, []testStructA{b, c}))
require.False(testStructAInSlice(c, []testStructA{a, b}))
}

View File

@@ -44,9 +44,9 @@ func RandIDWithLen(idLen int) (id string, err error) {
} }
func GetAuthKey(token string, timestamp int64) (key string) { func GetAuthKey(token string, timestamp int64) (key string) {
token += fmt.Sprintf("%d", timestamp)
md5Ctx := md5.New() md5Ctx := md5.New()
md5Ctx.Write([]byte(token)) md5Ctx.Write([]byte(token))
md5Ctx.Write([]byte(strconv.FormatInt(timestamp, 10)))
data := md5Ctx.Sum(nil) data := md5Ctx.Sum(nil)
return hex.EncodeToString(data) return hex.EncodeToString(data)
} }

View File

@@ -19,7 +19,7 @@ import (
"strings" "strings"
) )
var version = "0.45.0" var version = "0.48.0"
func Full() string { func Full() string {
return version return version

View File

@@ -28,7 +28,10 @@ type HTTPSMuxer struct {
} }
func NewHTTPSMuxer(listener net.Listener, timeout time.Duration) (*HTTPSMuxer, error) { func NewHTTPSMuxer(listener net.Listener, timeout time.Duration) (*HTTPSMuxer, error) {
mux, err := NewMuxer(listener, GetHTTPSHostname, nil, nil, nil, timeout) mux, err := NewMuxer(listener, GetHTTPSHostname, timeout)
if err != nil {
return nil, err
}
return &HTTPSMuxer{mux}, err return &HTTPSMuxer{mux}, err
} }

View File

@@ -85,17 +85,3 @@ func notFoundResponse() *http.Response {
} }
return res return res
} }
func noAuthResponse() *http.Response {
header := make(map[string][]string)
header["WWW-Authenticate"] = []string{`Basic realm="Restricted"`}
res := &http.Response{
Status: "401 Not authorized",
StatusCode: 401,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: header,
}
return res
}

View File

@@ -43,43 +43,55 @@ type RequestRouteInfo struct {
type ( type (
muxFunc func(net.Conn) (net.Conn, map[string]string, error) muxFunc func(net.Conn) (net.Conn, map[string]string, error)
httpAuthFunc func(net.Conn, string, string, string) (bool, error) authFunc func(conn net.Conn, username, password string, reqInfoMap map[string]string) (bool, error)
hostRewriteFunc func(net.Conn, string) (net.Conn, error) hostRewriteFunc func(net.Conn, string) (net.Conn, error)
successFunc func(net.Conn, map[string]string) error successHookFunc func(net.Conn, map[string]string) error
) )
// Muxer is only used for https and tcpmux proxy. // Muxer is a functional component used for https and tcpmux proxies.
// It accepts connections and extracts vhost information from the beginning of the connection data.
// It then routes the connection to its appropriate listener.
type Muxer struct { type Muxer struct {
listener net.Listener listener net.Listener
timeout time.Duration timeout time.Duration
vhostFunc muxFunc vhostFunc muxFunc
authFunc httpAuthFunc checkAuth authFunc
successFunc successFunc successHook successHookFunc
rewriteFunc hostRewriteFunc rewriteHost hostRewriteFunc
registryRouter *Routers registryRouter *Routers
} }
func NewMuxer( func NewMuxer(
listener net.Listener, listener net.Listener,
vhostFunc muxFunc, vhostFunc muxFunc,
authFunc httpAuthFunc,
successFunc successFunc,
rewriteFunc hostRewriteFunc,
timeout time.Duration, timeout time.Duration,
) (mux *Muxer, err error) { ) (mux *Muxer, err error) {
mux = &Muxer{ mux = &Muxer{
listener: listener, listener: listener,
timeout: timeout, timeout: timeout,
vhostFunc: vhostFunc, vhostFunc: vhostFunc,
authFunc: authFunc,
successFunc: successFunc,
rewriteFunc: rewriteFunc,
registryRouter: NewRouters(), registryRouter: NewRouters(),
} }
go mux.run() go mux.run()
return mux, nil return mux, nil
} }
func (v *Muxer) SetCheckAuthFunc(f authFunc) *Muxer {
v.checkAuth = f
return v
}
func (v *Muxer) SetSuccessHookFunc(f successHookFunc) *Muxer {
v.successHook = f
return v
}
func (v *Muxer) SetRewriteHostFunc(f hostRewriteFunc) *Muxer {
v.rewriteHost = f
return v
}
type ChooseEndpointFunc func() (string, error) type ChooseEndpointFunc func() (string, error)
type CreateConnFunc func(remoteAddr string) (net.Conn, error) type CreateConnFunc func(remoteAddr string) (net.Conn, error)
@@ -101,7 +113,7 @@ type RouteConfig struct {
CreateConnByEndpointFn CreateConnByEndpointFunc CreateConnByEndpointFn CreateConnByEndpointFunc
} }
// listen for a new domain name, if rewriteHost is not empty and rewriteFunc is not nil // listen for a new domain name, if rewriteHost is not empty and rewriteHost func is not nil,
// then rewrite the host header to rewriteHost // then rewrite the host header to rewriteHost
func (v *Muxer) Listen(ctx context.Context, cfg *RouteConfig) (l *Listener, err error) { func (v *Muxer) Listen(ctx context.Context, cfg *RouteConfig) (l *Listener, err error) {
l = &Listener{ l = &Listener{
@@ -109,8 +121,8 @@ func (v *Muxer) Listen(ctx context.Context, cfg *RouteConfig) (l *Listener, err
location: cfg.Location, location: cfg.Location,
routeByHTTPUser: cfg.RouteByHTTPUser, routeByHTTPUser: cfg.RouteByHTTPUser,
rewriteHost: cfg.RewriteHost, rewriteHost: cfg.RewriteHost,
userName: cfg.Username, username: cfg.Username,
passWord: cfg.Password, password: cfg.Password,
mux: v, mux: v,
accept: make(chan net.Conn), accept: make(chan net.Conn),
ctx: ctx, ctx: ctx,
@@ -205,25 +217,20 @@ func (v *Muxer) handle(c net.Conn) {
} }
xl := xlog.FromContextSafe(l.ctx) xl := xlog.FromContextSafe(l.ctx)
if v.successFunc != nil { if v.successHook != nil {
if err := v.successFunc(c, reqInfoMap); err != nil { if err := v.successHook(c, reqInfoMap); err != nil {
xl.Info("success func failure on vhost connection: %v", err) xl.Info("success func failure on vhost connection: %v", err)
_ = c.Close() _ = c.Close()
return return
} }
} }
// if authFunc is exist and username/password is set // if checkAuth func is exist and username/password is set
// then verify user access // then verify user access
if l.mux.authFunc != nil && l.userName != "" && l.passWord != "" { if l.mux.checkAuth != nil && l.username != "" {
bAccess, err := l.mux.authFunc(c, l.userName, l.passWord, reqInfoMap["Authorization"]) ok, err := l.mux.checkAuth(c, l.username, l.password, reqInfoMap)
if !bAccess || err != nil { if !ok || err != nil {
xl.Debug("check http Authorization failed") xl.Debug("auth failed for user: %s", l.username)
res := noAuthResponse()
if res.Body != nil {
defer res.Body.Close()
}
_ = res.Write(c)
_ = c.Close() _ = c.Close()
return return
} }
@@ -249,8 +256,8 @@ type Listener struct {
location string location string
routeByHTTPUser string routeByHTTPUser string
rewriteHost string rewriteHost string
userName string username string
passWord string password string
mux *Muxer // for closing Muxer mux *Muxer // for closing Muxer
accept chan net.Conn accept chan net.Conn
ctx context.Context ctx context.Context
@@ -263,11 +270,11 @@ func (l *Listener) Accept() (net.Conn, error) {
return nil, fmt.Errorf("Listener closed") return nil, fmt.Errorf("Listener closed")
} }
// if rewriteFunc is exist // if rewriteHost func is exist
// rewrite http requests with a modified host header // rewrite http requests with a modified host header
// if l.rewriteHost is empty, nothing to do // if l.rewriteHost is empty, nothing to do
if l.mux.rewriteFunc != nil { if l.mux.rewriteHost != nil {
sConn, err := l.mux.rewriteFunc(conn, l.rewriteHost) sConn, err := l.mux.rewriteHost(conn, l.rewriteHost)
if err != nil { if err != nil {
xl.Warn("host header rewrite failed: %v", err) xl.Warn("host header rewrite failed: %v", err)
return nil, fmt.Errorf("host header rewrite failed") return nil, fmt.Errorf("host header rewrite failed")

View File

@@ -514,7 +514,7 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
// NewProxy will return a interface Proxy. // NewProxy will return a interface Proxy.
// In fact it create different proxies by different proxy type, we just call run() here. // In fact it create different proxies by different proxy type, we just call run() here.
pxy, err := proxy.NewProxy(ctl.ctx, userInfo, ctl.rc, ctl.poolCount, ctl.GetWorkConn, pxyConf, ctl.serverCfg) pxy, err := proxy.NewProxy(ctl.ctx, userInfo, ctl.rc, ctl.poolCount, ctl.GetWorkConn, pxyConf, ctl.serverCfg, ctl.loginMsg)
if err != nil { if err != nil {
return remoteAddr, err return remoteAddr, err
} }

View File

@@ -33,16 +33,20 @@ type GeneralResponse struct {
} }
type serverInfoResp struct { type serverInfoResp struct {
Version string `json:"version"` Version string `json:"version"`
BindPort int `json:"bind_port"` BindPort int `json:"bind_port"`
BindUDPPort int `json:"bind_udp_port"` BindUDPPort int `json:"bind_udp_port"`
VhostHTTPPort int `json:"vhost_http_port"` VhostHTTPPort int `json:"vhost_http_port"`
VhostHTTPSPort int `json:"vhost_https_port"` VhostHTTPSPort int `json:"vhost_https_port"`
KCPBindPort int `json:"kcp_bind_port"` TCPMuxHTTPConnectPort int `json:"tcpmux_httpconnect_port"`
SubdomainHost string `json:"subdomain_host"` KCPBindPort int `json:"kcp_bind_port"`
MaxPoolCount int64 `json:"max_pool_count"` QUICBindPort int `json:"quic_bind_port"`
MaxPortsPerClient int64 `json:"max_ports_per_client"` SubdomainHost string `json:"subdomain_host"`
HeartBeatTimeout int64 `json:"heart_beat_timeout"` MaxPoolCount int64 `json:"max_pool_count"`
MaxPortsPerClient int64 `json:"max_ports_per_client"`
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
AllowPortsStr string `json:"allow_ports_str,omitempty"`
TLSOnly bool `json:"tls_only,omitempty"`
TotalTrafficIn int64 `json:"total_traffic_in"` TotalTrafficIn int64 `json:"total_traffic_in"`
TotalTrafficOut int64 `json:"total_traffic_out"` TotalTrafficOut int64 `json:"total_traffic_out"`
@@ -70,16 +74,20 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
log.Info("Http request: [%s]", r.URL.Path) log.Info("Http request: [%s]", r.URL.Path)
serverStats := mem.StatsCollector.GetServer() serverStats := mem.StatsCollector.GetServer()
svrResp := serverInfoResp{ svrResp := serverInfoResp{
Version: version.Full(), Version: version.Full(),
BindPort: svr.cfg.BindPort, BindPort: svr.cfg.BindPort,
BindUDPPort: svr.cfg.BindUDPPort, BindUDPPort: svr.cfg.BindUDPPort,
VhostHTTPPort: svr.cfg.VhostHTTPPort, VhostHTTPPort: svr.cfg.VhostHTTPPort,
VhostHTTPSPort: svr.cfg.VhostHTTPSPort, VhostHTTPSPort: svr.cfg.VhostHTTPSPort,
KCPBindPort: svr.cfg.KCPBindPort, TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
SubdomainHost: svr.cfg.SubDomainHost, KCPBindPort: svr.cfg.KCPBindPort,
MaxPoolCount: svr.cfg.MaxPoolCount, QUICBindPort: svr.cfg.QUICBindPort,
MaxPortsPerClient: svr.cfg.MaxPortsPerClient, SubdomainHost: svr.cfg.SubDomainHost,
HeartBeatTimeout: svr.cfg.HeartbeatTimeout, MaxPoolCount: svr.cfg.MaxPoolCount,
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
HeartBeatTimeout: svr.cfg.HeartbeatTimeout,
AllowPortsStr: svr.cfg.AllowPortsStr,
TLSOnly: svr.cfg.TLSOnly,
TotalTrafficIn: serverStats.TotalTrafficIn, TotalTrafficIn: serverStats.TotalTrafficIn,
TotalTrafficOut: serverStats.TotalTrafficOut, TotalTrafficOut: serverStats.TotalTrafficOut,
@@ -157,6 +165,7 @@ func getConfByType(proxyType string) interface{} {
type ProxyStatsInfo struct { type ProxyStatsInfo struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf interface{} `json:"conf"`
ClientVersion string `json:"client_version,omitempty"`
TodayTrafficIn int64 `json:"today_traffic_in"` TodayTrafficIn int64 `json:"today_traffic_in"`
TodayTrafficOut int64 `json:"today_traffic_out"` TodayTrafficOut int64 `json:"today_traffic_out"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"cur_conns"`
@@ -208,6 +217,9 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt
continue continue
} }
proxyInfo.Status = consts.Online proxyInfo.Status = consts.Online
if pxy.GetLoginMsg() != nil {
proxyInfo.ClientVersion = pxy.GetLoginMsg().Version
}
} else { } else {
proxyInfo.Status = consts.Offline proxyInfo.Status = consts.Offline
} }

View File

@@ -81,6 +81,8 @@ type TCPMuxGroup struct {
groupKey string groupKey string
domain string domain string
routeByHTTPUser string routeByHTTPUser string
username string
password string
acceptCh chan net.Conn acceptCh chan net.Conn
tcpMuxLn net.Listener tcpMuxLn net.Listener
@@ -120,6 +122,8 @@ func (tmg *TCPMuxGroup) HTTPConnectListen(
tmg.groupKey = groupKey tmg.groupKey = groupKey
tmg.domain = routeConfig.Domain tmg.domain = routeConfig.Domain
tmg.routeByHTTPUser = routeConfig.RouteByHTTPUser tmg.routeByHTTPUser = routeConfig.RouteByHTTPUser
tmg.username = routeConfig.Username
tmg.password = routeConfig.Password
tmg.tcpMuxLn = tcpMuxLn tmg.tcpMuxLn = tcpMuxLn
tmg.lns = append(tmg.lns, ln) tmg.lns = append(tmg.lns, ln)
if tmg.acceptCh == nil { if tmg.acceptCh == nil {
@@ -128,7 +132,10 @@ func (tmg *TCPMuxGroup) HTTPConnectListen(
go tmg.worker() go tmg.worker()
} else { } else {
// route config in the same group must be equal // route config in the same group must be equal
if tmg.group != group || tmg.domain != routeConfig.Domain || tmg.routeByHTTPUser != routeConfig.RouteByHTTPUser { if tmg.group != group || tmg.domain != routeConfig.Domain ||
tmg.routeByHTTPUser != routeConfig.RouteByHTTPUser ||
tmg.username != routeConfig.Username ||
tmg.password != routeConfig.Password {
return nil, ErrGroupParamsInvalid return nil, ErrGroupParamsInvalid
} }
if tmg.groupKey != groupKey { if tmg.groupKey != groupKey {

View File

@@ -20,8 +20,10 @@ import (
"strings" "strings"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
@@ -135,6 +137,10 @@ func (pxy *HTTPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *HTTPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) { func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) {
xl := pxy.xl xl := pxy.xl
rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr) rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr)
@@ -160,6 +166,13 @@ func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err err
if pxy.cfg.UseCompression { if pxy.cfg.UseCompression {
rwc = frpIo.WithCompression(rwc) rwc = frpIo.WithCompression(rwc)
} }
if pxy.GetLimiter() != nil {
rwc = frpIo.WrapReadWriteCloser(limit.NewReader(rwc, pxy.GetLimiter()), limit.NewWriter(rwc, pxy.GetLimiter()), func() error {
return rwc.Close()
})
}
workConn = frpNet.WrapReadWriteCloserToConn(rwc, tmpConn) workConn = frpNet.WrapReadWriteCloserToConn(rwc, tmpConn)
workConn = frpNet.WrapStatsConn(workConn, pxy.updateStatsAfterClosedConn) workConn = frpNet.WrapStatsConn(workConn, pxy.updateStatsAfterClosedConn)
metrics.Server.OpenConnection(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType) metrics.Server.OpenConnection(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType)

View File

@@ -17,6 +17,8 @@ package proxy
import ( import (
"strings" "strings"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
@@ -74,6 +76,10 @@ func (pxy *HTTPSProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *HTTPSProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *HTTPSProxy) Close() { func (pxy *HTTPSProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
} }

View File

@@ -24,10 +24,12 @@ import (
"time" "time"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
plugin "github.com/fatedier/frp/pkg/plugin/server" plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/frp/server/controller" "github.com/fatedier/frp/server/controller"
@@ -45,6 +47,8 @@ type Proxy interface {
GetUsedPortsNum() int GetUsedPortsNum() int
GetResourceController() *controller.ResourceController GetResourceController() *controller.ResourceController
GetUserInfo() plugin.UserInfo GetUserInfo() plugin.UserInfo
GetLimiter() *rate.Limiter
GetLoginMsg() *msg.Login
Close() Close()
} }
@@ -56,7 +60,9 @@ type BaseProxy struct {
poolCount int poolCount int
getWorkConnFn GetWorkConnFn getWorkConnFn GetWorkConnFn
serverCfg config.ServerCommonConf serverCfg config.ServerCommonConf
limiter *rate.Limiter
userInfo plugin.UserInfo userInfo plugin.UserInfo
loginMsg *msg.Login
mu sync.RWMutex mu sync.RWMutex
xl *xlog.Logger xl *xlog.Logger
@@ -83,6 +89,10 @@ func (pxy *BaseProxy) GetUserInfo() plugin.UserInfo {
return pxy.userInfo return pxy.userInfo
} }
func (pxy *BaseProxy) GetLoginMsg() *msg.Login {
return pxy.loginMsg
}
func (pxy *BaseProxy) Close() { func (pxy *BaseProxy) Close() {
xl := xlog.FromContextSafe(pxy.ctx) xl := xlog.FromContextSafe(pxy.ctx)
xl.Info("proxy closing") xl.Info("proxy closing")
@@ -184,9 +194,16 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn,
} }
func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int, func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int,
getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, loginMsg *msg.Login,
) (pxy Proxy, err error) { ) (pxy Proxy, err error) {
xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName) xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName)
var limiter *rate.Limiter
limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes()
if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeServer {
limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
}
basePxy := BaseProxy{ basePxy := BaseProxy{
name: pxyConf.GetBaseInfo().ProxyName, name: pxyConf.GetBaseInfo().ProxyName,
rc: rc, rc: rc,
@@ -194,9 +211,11 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso
poolCount: poolCount, poolCount: poolCount,
getWorkConnFn: getWorkConnFn, getWorkConnFn: getWorkConnFn,
serverCfg: serverCfg, serverCfg: serverCfg,
limiter: limiter,
xl: xl, xl: xl,
ctx: xlog.NewContext(ctx, xl), ctx: xlog.NewContext(ctx, xl),
userInfo: userInfo, userInfo: userInfo,
loginMsg: loginMsg,
} }
switch cfg := pxyConf.(type) { switch cfg := pxyConf.(type) {
case *config.TCPProxyConf: case *config.TCPProxyConf:
@@ -287,6 +306,13 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv
if cfg.UseCompression { if cfg.UseCompression {
local = frpIo.WithCompression(local) local = frpIo.WithCompression(local)
} }
if pxy.GetLimiter() != nil {
local = frpIo.WrapReadWriteCloser(limit.NewReader(local, pxy.GetLimiter()), limit.NewWriter(local, pxy.GetLimiter()), func() error {
return local.Close()
})
}
xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(), xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String()) workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())

View File

@@ -15,6 +15,8 @@
package proxy package proxy
import ( import (
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
@@ -41,6 +43,10 @@ func (pxy *STCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *STCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *STCPProxy) Close() { func (pxy *STCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.VisitorManager.CloseListener(pxy.GetName()) pxy.rc.VisitorManager.CloseListener(pxy.GetName())

View File

@@ -15,6 +15,8 @@
package proxy package proxy
import ( import (
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
@@ -42,6 +44,10 @@ func (pxy *SUDPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *SUDPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *SUDPProxy) Close() { func (pxy *SUDPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.VisitorManager.CloseListener(pxy.GetName()) pxy.rc.VisitorManager.CloseListener(pxy.GetName())

View File

@@ -19,6 +19,8 @@ import (
"net" "net"
"strconv" "strconv"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
@@ -74,6 +76,10 @@ func (pxy *TCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *TCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *TCPProxy) Close() { func (pxy *TCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
if pxy.cfg.Group == "" { if pxy.cfg.Group == "" {

View File

@@ -19,6 +19,8 @@ import (
"net" "net"
"strings" "strings"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
@@ -30,12 +32,16 @@ type TCPMuxProxy struct {
cfg *config.TCPMuxProxyConf cfg *config.TCPMuxProxyConf
} }
func (pxy *TCPMuxProxy) httpConnectListen(domain, routeByHTTPUser string, addrs []string) ([]string, error) { func (pxy *TCPMuxProxy) httpConnectListen(
domain, routeByHTTPUser, httpUser, httpPwd string, addrs []string) ([]string, error,
) {
var l net.Listener var l net.Listener
var err error var err error
routeConfig := &vhost.RouteConfig{ routeConfig := &vhost.RouteConfig{
Domain: domain, Domain: domain,
RouteByHTTPUser: routeByHTTPUser, RouteByHTTPUser: routeByHTTPUser,
Username: httpUser,
Password: httpPwd,
} }
if pxy.cfg.Group != "" { if pxy.cfg.Group != "" {
l, err = pxy.rc.TCPMuxGroupCtl.Listen(pxy.ctx, pxy.cfg.Multiplexer, pxy.cfg.Group, pxy.cfg.GroupKey, *routeConfig) l, err = pxy.rc.TCPMuxGroupCtl.Listen(pxy.ctx, pxy.cfg.Multiplexer, pxy.cfg.Group, pxy.cfg.GroupKey, *routeConfig)
@@ -58,14 +64,15 @@ func (pxy *TCPMuxProxy) httpConnectRun() (remoteAddr string, err error) {
continue continue
} }
addrs, err = pxy.httpConnectListen(domain, pxy.cfg.RouteByHTTPUser, addrs) addrs, err = pxy.httpConnectListen(domain, pxy.cfg.RouteByHTTPUser, pxy.cfg.HTTPUser, pxy.cfg.HTTPPwd, addrs)
if err != nil { if err != nil {
return "", err return "", err
} }
} }
if pxy.cfg.SubDomain != "" { if pxy.cfg.SubDomain != "" {
addrs, err = pxy.httpConnectListen(pxy.cfg.SubDomain+"."+pxy.serverCfg.SubDomainHost, pxy.cfg.RouteByHTTPUser, addrs) addrs, err = pxy.httpConnectListen(pxy.cfg.SubDomain+"."+pxy.serverCfg.SubDomainHost,
pxy.cfg.RouteByHTTPUser, pxy.cfg.HTTPUser, pxy.cfg.HTTPPwd, addrs)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -94,6 +101,10 @@ func (pxy *TCPMuxProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *TCPMuxProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *TCPMuxProxy) Close() { func (pxy *TCPMuxProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
} }

View File

@@ -24,10 +24,12 @@ import (
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/proto/udp" "github.com/fatedier/frp/pkg/proto/udp"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
) )
@@ -198,6 +200,12 @@ func (pxy *UDPProxy) Run() (remoteAddr string, err error) {
rwc = frpIo.WithCompression(rwc) rwc = frpIo.WithCompression(rwc)
} }
if pxy.GetLimiter() != nil {
rwc = frpIo.WrapReadWriteCloser(limit.NewReader(rwc, pxy.GetLimiter()), limit.NewWriter(rwc, pxy.GetLimiter()), func() error {
return rwc.Close()
})
}
pxy.workConn = frpNet.WrapReadWriteCloserToConn(rwc, workConn) pxy.workConn = frpNet.WrapReadWriteCloserToConn(rwc, workConn)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go workConnReaderFn(pxy.workConn) go workConnReaderFn(pxy.workConn)
@@ -225,6 +233,10 @@ func (pxy *UDPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *UDPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *UDPProxy) Close() { func (pxy *UDPProxy) Close() {
pxy.mu.Lock() pxy.mu.Lock()
defer pxy.mu.Unlock() defer pxy.mu.Unlock()

View File

@@ -18,6 +18,7 @@ import (
"fmt" "fmt"
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
@@ -88,6 +89,10 @@ func (pxy *XTCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *XTCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *XTCPProxy) Close() { func (pxy *XTCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.NatHoleController.CloseClient(pxy.GetName()) pxy.rc.NatHoleController.CloseClient(pxy.GetName())

View File

@@ -28,6 +28,7 @@ import (
"github.com/fatedier/golib/net/mux" "github.com/fatedier/golib/net/mux"
fmux "github.com/hashicorp/yamux" fmux "github.com/hashicorp/yamux"
quic "github.com/quic-go/quic-go"
"github.com/fatedier/frp/assets" "github.com/fatedier/frp/assets"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
@@ -68,6 +69,9 @@ type Service struct {
// Accept connections using kcp // Accept connections using kcp
kcpListener net.Listener kcpListener net.Listener
// Accept connections using quic
quicListener quic.Listener
// Accept connections using websocket // Accept connections using websocket
websocketListener net.Listener websocketListener net.Listener
@@ -200,12 +204,28 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.KCPBindPort)) address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.KCPBindPort))
svr.kcpListener, err = frpNet.ListenKcp(address) svr.kcpListener, err = frpNet.ListenKcp(address)
if err != nil { if err != nil {
err = fmt.Errorf("listen on kcp address udp %s error: %v", address, err) err = fmt.Errorf("listen on kcp udp address %s error: %v", address, err)
return return
} }
log.Info("frps kcp listen on udp %s", address) log.Info("frps kcp listen on udp %s", address)
} }
if cfg.QUICBindPort > 0 {
address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.QUICBindPort))
quicTLSCfg := tlsConfig.Clone()
quicTLSCfg.NextProtos = []string{"frp"}
svr.quicListener, err = quic.ListenAddr(address, quicTLSCfg, &quic.Config{
MaxIdleTimeout: time.Duration(cfg.QUICMaxIdleTimeout) * time.Second,
MaxIncomingStreams: int64(cfg.QUICMaxIncomingStreams),
KeepAlivePeriod: time.Duration(cfg.QUICKeepalivePeriod) * time.Second,
})
if err != nil {
err = fmt.Errorf("listen on quic udp address %s error: %v", address, err)
return
}
log.Info("frps quic listen on quic %s", address)
}
// Listen for accepting connections from client using websocket protocol. // Listen for accepting connections from client using websocket protocol.
websocketPrefix := []byte("GET " + frpNet.FrpWebsocketPath) websocketPrefix := []byte("GET " + frpNet.FrpWebsocketPath)
websocketLn := svr.muxer.Listen(0, uint32(len(websocketPrefix)), func(data []byte) bool { websocketLn := svr.muxer.Listen(0, uint32(len(websocketPrefix)), func(data []byte) bool {
@@ -310,9 +330,12 @@ func (svr *Service) Run() {
if svr.rc.NatHoleController != nil { if svr.rc.NatHoleController != nil {
go svr.rc.NatHoleController.Run() go svr.rc.NatHoleController.Run()
} }
if svr.cfg.KCPBindPort > 0 { if svr.kcpListener != nil {
go svr.HandleListener(svr.kcpListener) go svr.HandleListener(svr.kcpListener)
} }
if svr.quicListener != nil {
go svr.HandleQUICListener(svr.quicListener)
}
go svr.HandleListener(svr.websocketListener) go svr.HandleListener(svr.websocketListener)
go svr.HandleListener(svr.tlsListener) go svr.HandleListener(svr.tlsListener)
@@ -437,6 +460,29 @@ func (svr *Service) HandleListener(l net.Listener) {
} }
} }
func (svr *Service) HandleQUICListener(l quic.Listener) {
// Listen for incoming connections from client.
for {
c, err := l.Accept(context.Background())
if err != nil {
log.Warn("QUICListener for incoming connections from client closed")
return
}
// Start a new goroutine to handle connection.
go func(ctx context.Context, frpConn quic.Connection) {
for {
stream, err := frpConn.AcceptStream(context.Background())
if err != nil {
log.Debug("Accept new quic mux stream error: %v", err)
_ = frpConn.CloseWithError(0, "")
return
}
go svr.handleConnection(ctx, frpNet.QuicStreamToNetConn(stream, frpConn))
}
}(context.Background(), c)
}
}
func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login) (err error) { func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login) (err error) {
// If client's RunID is empty, it's a new client, we just create a new controller. // If client's RunID is empty, it's a new client, we just create a new controller.
// Otherwise, we check if there is one controller has the same run id. If so, we release previous controller and start new one. // Otherwise, we check if there is one controller has the same run id. If so, we release previous controller and start new one.

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/pkg/transport" "github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"

View File

@@ -6,7 +6,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
@@ -18,6 +18,15 @@ type generalTestConfigures struct {
expectError bool expectError bool
} }
func renderBindPortConfig(protocol string) string {
if protocol == "kcp" {
return fmt.Sprintf(`kcp_bind_port = {{ .%s }}`, consts.PortServerName)
} else if protocol == "quic" {
return fmt.Sprintf(`quic_bind_port = {{ .%s }}`, consts.PortServerName)
}
return ""
}
func runClientServerTest(f *framework.Framework, configures *generalTestConfigures) { func runClientServerTest(f *framework.Framework, configures *generalTestConfigures) {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@@ -63,13 +72,12 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
ginkgo.Describe("Protocol", func() { ginkgo.Describe("Protocol", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
configures := &generalTestConfigures{ configures := &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
kcp_bind_port = {{ .%s }} %s
protocol = %s" `, renderBindPortConfig(protocol)),
`, consts.PortServerName, protocol),
client: "protocol = " + protocol, client: "protocol = " + protocol,
} }
defineClientServerTest(protocol, f, configures) defineClientServerTest(protocol, f, configures)
@@ -90,14 +98,13 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
ginkgo.Describe("TLS", func() { ginkgo.Describe("TLS", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
defineClientServerTest("TLS over "+strings.ToUpper(tmp), f, &generalTestConfigures{ defineClientServerTest("TLS over "+strings.ToUpper(tmp), f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
kcp_bind_port = {{ .%s }} %s
protocol = %s `, renderBindPortConfig(protocol)),
`, consts.PortServerName, protocol),
client: fmt.Sprintf(`tls_enable = true client: fmt.Sprintf(`tls_enable = true
protocol = %s protocol = %s
`, protocol), `, protocol),
@@ -115,7 +122,7 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
ginkgo.Describe("TLS with custom certificate", func() { ginkgo.Describe("TLS with custom certificate", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
var ( var (
caCrtPath string caCrtPath string
@@ -124,14 +131,14 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
) )
ginkgo.JustBeforeEach(func() { ginkgo.JustBeforeEach(func() {
generator := &cert.SelfSignedCertGenerator{} generator := &cert.SelfSignedCertGenerator{}
artifacts, err := generator.Generate("0.0.0.0") artifacts, err := generator.Generate("127.0.0.1")
framework.ExpectNoError(err) framework.ExpectNoError(err)
caCrtPath = f.WriteTempFile("ca.crt", string(artifacts.CACert)) caCrtPath = f.WriteTempFile("ca.crt", string(artifacts.CACert))
serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert)) serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key)) serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
generator.SetCA(artifacts.CACert, artifacts.CAKey) generator.SetCA(artifacts.CACert, artifacts.CAKey)
_, err = generator.Generate("0.0.0.0") _, err = generator.Generate("127.0.0.1")
framework.ExpectNoError(err) framework.ExpectNoError(err)
clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert)) clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert))
clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key)) clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
@@ -143,10 +150,9 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
ginkgo.It("one-way authentication: "+tmp, func() { ginkgo.It("one-way authentication: "+tmp, func() {
runClientServerTest(f, &generalTestConfigures{ runClientServerTest(f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
protocol = %s %s
kcp_bind_port = {{ .%s }}
tls_trusted_ca_file = %s tls_trusted_ca_file = %s
`, tmp, consts.PortServerName, caCrtPath), `, renderBindPortConfig(tmp), caCrtPath),
client: fmt.Sprintf(` client: fmt.Sprintf(`
protocol = %s protocol = %s
tls_enable = true tls_enable = true
@@ -159,12 +165,11 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
ginkgo.It("mutual authentication: "+tmp, func() { ginkgo.It("mutual authentication: "+tmp, func() {
runClientServerTest(f, &generalTestConfigures{ runClientServerTest(f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
protocol = %s %s
kcp_bind_port = {{ .%s }}
tls_cert_file = %s tls_cert_file = %s
tls_key_file = %s tls_key_file = %s
tls_trusted_ca_file = %s tls_trusted_ca_file = %s
`, tmp, consts.PortServerName, serverCrtPath, serverKeyPath, caCrtPath), `, renderBindPortConfig(tmp), serverCrtPath, serverKeyPath, caCrtPath),
client: fmt.Sprintf(` client: fmt.Sprintf(`
protocol = %s protocol = %s
tls_enable = true tls_enable = true
@@ -235,14 +240,13 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
ginkgo.Describe("TLS with disable_custom_tls_first_byte", func() { ginkgo.Describe("TLS with disable_custom_tls_first_byte", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
defineClientServerTest("TLS over "+strings.ToUpper(tmp), f, &generalTestConfigures{ defineClientServerTest("TLS over "+strings.ToUpper(tmp), f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
kcp_bind_port = {{ .%s }} %s
protocol = %s `, renderBindPortConfig(protocol)),
`, consts.PortServerName, protocol),
client: fmt.Sprintf(` client: fmt.Sprintf(`
tls_enable = true tls_enable = true
protocol = %s protocol = %s
@@ -253,15 +257,14 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
ginkgo.Describe("IPv6 bind address", func() { ginkgo.Describe("IPv6 bind address", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
defineClientServerTest("IPv6 bind address: "+strings.ToUpper(tmp), f, &generalTestConfigures{ defineClientServerTest("IPv6 bind address: "+strings.ToUpper(tmp), f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
bind_addr = :: bind_addr = ::
kcp_bind_port = {{ .%s }} %s
protocol = %s `, renderBindPortConfig(protocol)),
`, consts.PortServerName, protocol),
client: fmt.Sprintf(` client: fmt.Sprintf(`
tls_enable = true tls_enable = true
protocol = %s protocol = %s

View File

@@ -5,7 +5,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"

View File

@@ -3,7 +3,7 @@ package basic
import ( import (
"fmt" "fmt"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"

View File

@@ -7,7 +7,7 @@ import (
"strconv" "strconv"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"

View File

@@ -5,7 +5,7 @@ import (
"net" "net"
"strconv" "strconv"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"

218
test/e2e/basic/tcpmux.go Normal file
View File

@@ -0,0 +1,218 @@
package basic
import (
"bufio"
"fmt"
"net"
"net/http"
"github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/mock/server/streamserver"
"github.com/fatedier/frp/test/e2e/pkg/request"
"github.com/fatedier/frp/test/e2e/pkg/rpc"
)
var _ = ginkgo.Describe("[Feature: TCPMUX httpconnect]", func() {
f := framework.NewDefaultFramework()
getDefaultServerConf := func(httpconnectPort int) string {
conf := consts.DefaultServerConfig + `
tcpmux_httpconnect_port = %d
`
return fmt.Sprintf(conf, httpconnectPort)
}
newServer := func(port int, respContent string) *streamserver.Server {
return streamserver.New(
streamserver.TCP,
streamserver.WithBindPort(port),
streamserver.WithRespContent([]byte(respContent)),
)
}
proxyURLWithAuth := func(username, password string, port int) string {
if username == "" {
return fmt.Sprintf("http://127.0.0.1:%d", port)
}
return fmt.Sprintf("http://%s:%s@127.0.0.1:%d", username, password, port)
}
ginkgo.It("Route by HTTP user", func() {
vhostPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostPort)
fooPort := f.AllocPort()
f.RunServer("", newServer(fooPort, "foo"))
barPort := f.AllocPort()
f.RunServer("", newServer(barPort, "bar"))
otherPort := f.AllocPort()
f.RunServer("", newServer(otherPort, "other"))
clientConf := consts.DefaultClientConfig
clientConf += fmt.Sprintf(`
[foo]
type = tcpmux
multiplexer = httpconnect
local_port = %d
custom_domains = normal.example.com
route_by_http_user = user1
[bar]
type = tcpmux
multiplexer = httpconnect
local_port = %d
custom_domains = normal.example.com
route_by_http_user = user2
[catchAll]
type = tcpmux
multiplexer = httpconnect
local_port = %d
custom_domains = normal.example.com
`, fooPort, barPort, otherPort)
f.RunProcesses([]string{serverConf}, []string{clientConf})
// user1
framework.NewRequestExpect(f).Explain("user1").
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("user1", "", vhostPort))
}).
ExpectResp([]byte("foo")).
Ensure()
// user2
framework.NewRequestExpect(f).Explain("user2").
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("user2", "", vhostPort))
}).
ExpectResp([]byte("bar")).
Ensure()
// other user
framework.NewRequestExpect(f).Explain("other user").
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("user3", "", vhostPort))
}).
ExpectResp([]byte("other")).
Ensure()
})
ginkgo.It("Proxy auth", func() {
vhostPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostPort)
fooPort := f.AllocPort()
f.RunServer("", newServer(fooPort, "foo"))
clientConf := consts.DefaultClientConfig
clientConf += fmt.Sprintf(`
[test]
type = tcpmux
multiplexer = httpconnect
local_port = %d
custom_domains = normal.example.com
http_user = test
http_pwd = test
`, fooPort)
f.RunProcesses([]string{serverConf}, []string{clientConf})
// not set auth header
framework.NewRequestExpect(f).Explain("no auth").
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("", "", vhostPort))
}).
ExpectError(true).
Ensure()
// set incorrect auth header
framework.NewRequestExpect(f).Explain("incorrect auth").
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("test", "invalid", vhostPort))
}).
ExpectError(true).
Ensure()
// set correct auth header
framework.NewRequestExpect(f).Explain("correct auth").
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("test", "test", vhostPort))
}).
ExpectResp([]byte("foo")).
Ensure()
})
ginkgo.It("TCPMux Passthrough", func() {
vhostPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostPort)
serverConf += `
tcpmux_passthrough = true
`
var (
respErr error
connectRequestHost string
)
newServer := func(port int) *streamserver.Server {
return streamserver.New(
streamserver.TCP,
streamserver.WithBindPort(port),
streamserver.WithCustomHandler(func(conn net.Conn) {
defer conn.Close()
// read HTTP CONNECT request
bufioReader := bufio.NewReader(conn)
req, err := http.ReadRequest(bufioReader)
if err != nil {
respErr = err
return
}
connectRequestHost = req.Host
// return ok response
res := util.OkResponse()
if res.Body != nil {
defer res.Body.Close()
}
_ = res.Write(conn)
buf, err := rpc.ReadBytes(conn)
if err != nil {
respErr = err
return
}
_, _ = rpc.WriteBytes(conn, buf)
}),
)
}
localPort := f.AllocPort()
f.RunServer("", newServer(localPort))
clientConf := consts.DefaultClientConfig
clientConf += fmt.Sprintf(`
[test]
type = tcpmux
multiplexer = httpconnect
local_port = %d
custom_domains = normal.example.com
`, localPort)
f.RunProcesses([]string{serverConf}, []string{clientConf})
framework.NewRequestExpect(f).
RequestModify(func(r *request.Request) {
r.Addr("normal.example.com").Proxy(proxyURLWithAuth("", "", vhostPort)).Body([]byte("frp"))
}).
ExpectResp([]byte("frp")).
Ensure()
framework.ExpectNoError(respErr)
framework.ExpectEqualValues(connectRequestHost, "normal.example.com")
})
})

View File

@@ -3,8 +3,7 @@ package e2e
import ( import (
"testing" "testing"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/onsi/ginkgo/config"
"github.com/onsi/gomega" "github.com/onsi/gomega"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
@@ -33,9 +32,15 @@ var _ = ginkgo.SynchronizedAfterSuite(func() {
func RunE2ETests(t *testing.T) { func RunE2ETests(t *testing.T) {
gomega.RegisterFailHandler(framework.Fail) gomega.RegisterFailHandler(framework.Fail)
suiteConfig, reporterConfig := ginkgo.GinkgoConfiguration()
// Turn on EmitSpecProgress to get spec progress (especially on interrupt)
suiteConfig.EmitSpecProgress = true
// Randomize specs as well as suites
suiteConfig.RandomizeAllSpecs = true
log.Info("Starting e2e run %q on Ginkgo node %d of total %d", log.Info("Starting e2e run %q on Ginkgo node %d of total %d",
framework.RunID, config.GinkgoConfig.ParallelNode, config.GinkgoConfig.ParallelTotal) framework.RunID, suiteConfig.ParallelProcess, suiteConfig.ParallelTotal)
ginkgo.RunSpecs(t, "frp e2e suite") ginkgo.RunSpecs(t, "frp e2e suite", suiteConfig, reporterConfig)
} }
// setupSuite is the boilerplate that can be used to setup ginkgo test suites, on the SynchronizedBeforeSuite step. // setupSuite is the boilerplate that can be used to setup ginkgo test suites, on the SynchronizedBeforeSuite step.

View File

@@ -6,7 +6,7 @@ import (
"os" "os"
"testing" "testing"
_ "github.com/onsi/ginkgo" _ "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
// test source // test source

View File

@@ -3,7 +3,7 @@ package e2e
import ( import (
"fmt" "fmt"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"

View File

@@ -5,18 +5,20 @@ import (
"strings" "strings"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
plugintest "github.com/fatedier/frp/test/e2e/plugin"
) )
var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() { var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
ginkgo.It("Proxy Bandwidth Limit", func() { ginkgo.It("Proxy Bandwidth Limit by Client", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@@ -40,8 +42,64 @@ var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) { framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) {
r.Body([]byte(content)).Timeout(30 * time.Second) r.Body([]byte(content)).Timeout(30 * time.Second)
}).ExpectResp([]byte(content)).Ensure() }).ExpectResp([]byte(content)).Ensure()
duration := time.Since(start)
framework.ExpectTrue(duration.Seconds() > 7, "100Kb with 10KB limit, want > 7 seconds, but got %d seconds", duration.Seconds()) duration := time.Since(start)
framework.Logf("request duration: %s", duration.String())
framework.ExpectTrue(duration.Seconds() > 8, "100Kb with 10KB limit, want > 8 seconds, but got %s", duration.String())
})
ginkgo.It("Proxy Bandwidth Limit by Server", func() {
// new test plugin server
newFunc := func() *plugin.Request {
var r plugin.Request
r.Content = &plugin.NewProxyContent{}
return &r
}
pluginPort := f.AllocPort()
handler := func(req *plugin.Request) *plugin.Response {
var ret plugin.Response
content := req.Content.(*plugin.NewProxyContent)
content.BandwidthLimit = "10KB"
content.BandwidthLimitMode = "server"
ret.Content = content
return &ret
}
pluginServer := plugintest.NewHTTPPluginServer(pluginPort, newFunc, handler, nil)
f.RunServer("", pluginServer)
serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
[plugin.test]
addr = 127.0.0.1:%d
path = /handler
ops = NewProxy
`, pluginPort)
clientConf := consts.DefaultClientConfig
localPort := f.AllocPort()
localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(localPort))
f.RunServer("", localServer)
remotePort := f.AllocPort()
clientConf += fmt.Sprintf(`
[tcp]
type = tcp
local_port = %d
remote_port = %d
`, localPort, remotePort)
f.RunProcesses([]string{serverConf}, []string{clientConf})
content := strings.Repeat("a", 50*1024) // 5KB
start := time.Now()
framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) {
r.Body([]byte(content)).Timeout(30 * time.Second)
}).ExpectResp([]byte(content)).Ensure()
duration := time.Since(start)
framework.Logf("request duration: %s", duration.String())
framework.ExpectTrue(duration.Seconds() > 8, "100Kb with 10KB limit, want > 8 seconds, but got %s", duration.String())
}) })
}) })

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
) )

View File

@@ -6,7 +6,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
) )

View File

@@ -5,7 +5,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"

View File

@@ -6,7 +6,7 @@ import (
"net" "net"
"net/http" "net/http"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo/v2"
pp "github.com/pires/go-proxyproto" pp "github.com/pires/go-proxyproto"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"

View File

@@ -25,6 +25,7 @@ var (
DefaultClientConfig = ` DefaultClientConfig = `
[common] [common]
server_addr = 127.0.0.1
server_port = {{ .%s }} server_port = {{ .%s }}
log_level = trace log_level = trace
` `

Some files were not shown because too many files have changed in this diff Show More