Compare commits

...

109 Commits

Author SHA1 Message Date
fatedier
e649692217 Merge pull request #4253 from fatedier/dev
bump version
2024-05-31 14:34:47 +08:00
fatedier
77990c31ef fix ini configuration default values (#4250) 2024-05-30 10:36:30 +08:00
fatedier
e680acf42d android: only use google dns server when the default dns server cannot be obtained (#4236) 2024-05-23 16:09:58 +08:00
fatedier
522e2c94c1 config: return error if plugin type is empty (#4235) 2024-05-23 14:52:12 +08:00
fatedier
301515d2e8 update the default value of transport.tcpMuxKeepaliveInterval (#4231) 2024-05-21 12:00:35 +08:00
fatedier
f0442d0cd5 plugin: fix http2 not enabled for https2http and https2https plugin (#4230) 2024-05-21 11:26:52 +08:00
fatedier
9ced717d69 update build-and-push-image.yml (#4206) 2024-05-07 19:14:09 +08:00
fatedier
4e8e9e1dec Merge pull request #4205 from fatedier/dev
bump version
2024-05-07 18:08:48 +08:00
fatedier
92cb0b30c2 update version (#4204) 2024-05-07 18:05:36 +08:00
fatedier
e81b36c5ba support responseHeaders.set for proxy type http (#4192) 2024-04-29 15:53:45 +08:00
Weltolk
d0d396becb Update README.md (#4190) 2024-04-29 11:50:56 +08:00
fatedier
ee3892798d change default value of heartbeat interval and timeout when tcpmux enabled (#4186) 2024-04-28 20:48:44 +08:00
fatedier
405969085f client: add StatusExporter in service (#4182) 2024-04-25 20:20:39 +08:00
fatedier
c1893ee1b4 adjust arm compilation configuration (#4181) 2024-04-25 13:08:41 +08:00
ddscentral
eaae212d2d Makefile.cross-compiles: Fix softfloat flag not being honored for mipsle. (#4176) 2024-04-22 19:50:58 +08:00
fatedier
885278c045 README add releated projects (#4167) 2024-04-17 20:41:14 +08:00
fatedier
2626d6ed92 support linux/arm v6 (#4154) 2024-04-12 21:21:28 +08:00
fatedier
f3a71bc08f show tcpmux proxies on the frps dashboard (#4152) 2024-04-11 22:40:42 +08:00
fatedier
dd7e2e8473 return 504 instead of 404 for proxy type http request timeout (#4151) 2024-04-11 20:19:08 +08:00
gopherfarm
07946e9752 fix: revert gorilla/websocket from 1.5.1 to 1.5.0 (#4149) 2024-04-11 11:01:02 +08:00
fatedier
e52727e01c update golib (#4142) 2024-04-10 12:05:22 +08:00
fatedier
ba937e9fbf update README (#4139) 2024-04-09 15:03:32 +08:00
fatedier
8f23733f47 Merge pull request #4137 from fatedier/dev
bump version
2024-04-09 11:45:41 +08:00
fatedier
d2d03a8fd9 bump deps version (#4136) 2024-04-09 11:39:21 +08:00
fatedier
590ccda677 fix x-forwarded-for header (#4111) 2024-03-28 16:47:27 +08:00
fatedier
86f90f4d27 package.sh add android (#4094) 2024-03-21 19:38:18 +08:00
fatedier
5a6d9f60c2 Merge pull request #4092 from fatedier/dev
bump v0.56.0
2024-03-21 17:37:39 +08:00
fatedier
f16ef00975 set CompatibilityMode for android (#4091) 2024-03-21 17:34:09 +08:00
fatedier
b36f3834eb use math/rand/v2 (#4020) 2024-03-20 15:48:31 +08:00
fatedier
c08be0fd92 update release notes (#4086) 2024-03-20 15:16:01 +08:00
Kaive Young
bc5fb91c05 add header for http healthcheck (#4085) 2024-03-20 14:58:03 +08:00
fatedier
002831ea82 add doc for port range mapping (#4081) 2024-03-19 13:22:29 +08:00
fatedier
acf33db4e4 update release notes (#4074) 2024-03-15 17:50:58 +08:00
fatedier
3585f5c0c0 support range ports mapping by go template (#4073) 2024-03-15 17:23:16 +08:00
fatedier
8383d528d9 disable quic-go's ECN support by default (#4069) 2024-03-15 14:22:03 +08:00
fatedier
fa977c839f fix daily log rotate (#4066) 2024-03-14 19:49:58 +08:00
fatedier
86c2ad78c8 disable quic-go's receive buffer warning (#4063) 2024-03-13 21:53:09 +08:00
fatedier
a5b7abfc8b Merge pull request #4060 from fatedier/dev
bump version
2024-03-12 18:11:37 +08:00
fatedier
d5589213c5 add set -e in package.sh (#4059) 2024-03-12 18:07:55 +08:00
fatedier
e0c979e98e fix release scripts (#4057) 2024-03-12 17:37:14 +08:00
fatedier
1e650ea9a7 Merge pull request #4056 from fatedier/dev
bump version
2024-03-12 16:55:25 +08:00
fatedier
e6ec5a509b update release notes (#4055) 2024-03-12 15:14:13 +08:00
fatedier
43ba7bd338 use new log package (#4054) 2024-03-12 13:58:53 +08:00
fatedier
49443cb2c6 update sponsor (#4045)
* update sponsors
2024-03-07 14:45:55 +08:00
fatedier
32f09c4b60 regen web assets (#4040) 2024-03-03 23:02:38 +08:00
Haotian Zou
f63b4d5c29 fix: change absolute path to relative path (#4038) 2024-03-03 22:57:17 +08:00
fatedier
b3946489dd add new badges (#4028) 2024-02-27 17:43:37 +08:00
fatedier
7ae3719b82 cleanup code (#4019) 2024-02-22 21:04:21 +08:00
fatedier
80cfd0938e use go1.22 (#4018) 2024-02-22 20:24:33 +08:00
fatedier
52f66b05e6 update golangci-lint version to 1.56 (#4013) 2024-02-21 17:20:40 +08:00
fatedier
b2b580be22 update kcp-go package (#4009) 2024-02-20 16:11:37 +08:00
fatedier
3e0c78233a use std slices package (#4008) 2024-02-20 12:01:41 +08:00
fatedier
d689f0fc53 Merge pull request #3968 from fatedier/dev
bump version
2024-02-01 14:29:17 +08:00
fatedier
d505ecb473 Merge pull request #3880 from fatedier/dev
fix login retry interval (#3879)
2023-12-21 21:42:47 +08:00
fatedier
2b83436a97 Merge pull request #3878 from fatedier/dev
bump version
2023-12-21 21:25:01 +08:00
fatedier
051299ec25 Merge pull request #3845 from fatedier/dev
bump version to v0.53.0
2023-12-14 20:58:11 +08:00
fatedier
44985f574d Merge pull request #3722 from fatedier/dev
bump version
2023-10-24 10:47:16 +08:00
fatedier
c9ca9353cf Merge pull request #3714 from fatedier/dev
bump version
2023-10-23 10:51:50 +08:00
fatedier
31fa3f021a Merge pull request #3668 from fatedier/dev
bump version to v0.52.1
2023-10-11 17:16:07 +08:00
fatedier
2d3af8a108 Merge pull request #3651 from fatedier/dev
bump version to v0.52.0
2023-10-10 17:24:07 +08:00
fatedier
466d69eae0 Merge pull request #3574 from fatedier/dev
release v0.51.3
2023-08-14 11:59:09 +08:00
fatedier
7c8cbeb250 Merge pull request #3550 from fatedier/dev
release v0.51.2
2023-07-25 21:35:08 +08:00
fatedier
4fd6301577 Merge pull request #3537 from fatedier/dev
release v0.51.1
2023-07-20 22:38:48 +08:00
fatedier
53626b370c Merge pull request #3517 from fatedier/dev
bump version to v0.51.0
2023-07-05 20:39:25 +08:00
fatedier
4fd800bc48 Merge pull request #3499 from fatedier/dev
release v0.50.0
2023-06-26 17:03:56 +08:00
fatedier
0d6d968fe8 Merge pull request #3454 from fatedier/dev
release v0.49.0
2023-05-29 01:12:26 +08:00
fatedier
8fb99ef7a9 Merge pull request #3348 from fatedier/dev
bump version
2023-03-08 11:40:31 +08:00
fatedier
88e74ff24d Merge pull request #3300 from fatedier/dev
sync
2023-02-10 01:12:00 +08:00
fatedier
534dc99d55 Merge pull request #3299 from fatedier/dev
sync
2023-02-09 23:06:14 +08:00
fatedier
595aba5a9b Merge pull request #3248 from fatedier/dev
bump version
2023-01-10 10:26:56 +08:00
fatedier
a4189ba474 Merge branch 'dev' 2022-12-18 19:27:22 +08:00
fatedier
9ec84f8143 Merge pull request #3218 from fatedier/dev
release v0.46.0
2022-12-18 18:46:52 +08:00
fatedier
8ab474cc97 remove unsupported platform (#3148) 2022-10-27 10:22:47 +08:00
fatedier
a301046f3d Merge pull request #3147 from fatedier/dev
bump version
2022-10-26 23:18:40 +08:00
fatedier
8888610d83 Merge pull request #3010 from fatedier/dev
release v0.44.0
2022-07-11 00:10:43 +08:00
fatedier
fe5fb0326b Merge pull request #2955 from fatedier/dev
bump version to v0.43.0
2022-05-27 16:27:19 +08:00
fatedier
eb1e19a821 Merge pull request #2906 from fatedier/dev
bump version
2022-04-22 11:32:27 +08:00
fatedier
10f2620131 Merge pull request #2869 from fatedier/dev
bump version to v0.41.0
2022-03-23 21:19:59 +08:00
fatedier
ce677820c6 Merge pull request #2834 from fatedier/dev
bump version
2022-03-11 19:51:32 +08:00
fatedier
88fcc079e8 Merge pull request #2792 from fatedier/dev
bump version
2022-02-09 16:11:20 +08:00
fatedier
2dab5d0bca Merge pull request #2782 from fatedier/dev
bump version
2022-01-26 20:17:54 +08:00
fatedier
143750901e Merge pull request #2638 from fatedier/dev
bump version to v0.38.0
2021-10-25 20:31:13 +08:00
fatedier
997d406ec2 Merge pull request #2508 from fatedier/dev
bump version
2021-08-03 23:13:31 +08:00
fatedier
cfd1a3128a Merge pull request #2426 from fatedier/dev
update workflow file
2021-06-03 00:59:21 +08:00
fatedier
57577ea044 Merge pull request #2425 from fatedier/dev
bump version
2021-06-03 00:14:32 +08:00
fatedier
c5c79e4148 Merge pull request #2324 from fatedier/dev
bump version v0.36.2
2021-03-22 14:56:48 +08:00
fatedier
55da58eca4 Merge pull request #2310 from fatedier/dev
bump version
2021-03-18 11:14:56 +08:00
fatedier
76a1efccd9 update 2021-03-17 11:43:23 +08:00
fatedier
980f084ad1 Merge pull request #2302 from fatedier/dev
bump version
2021-03-15 21:54:52 +08:00
fatedier
3bf1eb8565 Merge pull request #2216 from fatedier/dev
bump version
2021-01-25 16:15:52 +08:00
fatedier
b2ae433e18 Merge pull request #2206 from fatedier/dev
bump version
2021-01-19 20:56:06 +08:00
fatedier
aa0a41ee4e Merge pull request #2088 from fatedier/dev
bump version to v0.34.3
2020-11-20 17:04:55 +08:00
fatedier
1ea1530b36 Merge pull request #2058 from fatedier/dev
bump version to v0.34.2
2020-11-06 14:50:50 +08:00
fatedier
e0c45a1aca Merge pull request #2018 from fatedier/dev
bump version to v0.34.1
2020-09-30 15:13:08 +08:00
fatedier
813c45f5c2 Merge pull request #1993 from fatedier/dev
bump version to v0.34.0
2020-09-20 00:30:51 +08:00
fatedier
aa74dc4646 Merge pull request #1990 from fatedier/dev
bump version to v0.34.0
2020-09-20 00:10:32 +08:00
fatedier
2406ecdfea Merge pull request #1780 from fatedier/dev
bump version
2020-04-27 16:50:34 +08:00
fatedier
8668fef136 Merge pull request #1728 from fatedier/dev
bump version to v0.32.1
2020-04-03 01:14:58 +08:00
fatedier
ea62bc5a34 remove vendor (#1697) 2020-03-11 14:39:43 +08:00
fatedier
23bb76397a Merge pull request #1696 from fatedier/dev
bump version to v0.32.0
2020-03-11 14:30:47 +08:00
fatedier
487c8d7c29 Merge pull request #1637 from fatedier/dev
bump version to v0.31.2
2020-02-04 21:54:28 +08:00
fatedier
f480160e2d Merge pull request #1596 from fatedier/dev
v0.31.1, fix bugs
2020-01-06 15:55:44 +08:00
fatedier
30c246c488 Merge pull request #1588 from fatedier/dev
bump version to v0.31.0
2020-01-03 11:45:22 +08:00
fatedier
75f3bce04d Merge pull request #1542 from fatedier/dev
bump version to v0.30.0
2019-11-28 14:21:27 +08:00
fatedier
adc3adc13b Merge pull request #1494 from fatedier/dev
bump version to v0.29.1
2019-11-02 21:14:50 +08:00
fatedier
e62d9a5242 Merge pull request #1415 from fatedier/dev
bump version to v0.29.0
2019-08-29 21:22:30 +08:00
fatedier
134a46c00b Merge pull request #1369 from fatedier/dev
bump version to v0.28.2
2019-08-09 12:59:13 +08:00
fatedier
ae08811636 Merge pull request #1364 from fatedier/dev
bump version to v0.28.1 and remove support for go1.11
2019-08-08 17:32:57 +08:00
fatedier
6451583e60 Merge pull request #1349 from fatedier/dev
bump version to v0.28.0
2019-08-01 14:04:55 +08:00
132 changed files with 1642 additions and 1234 deletions

View File

@@ -2,24 +2,15 @@ version: 2
jobs: jobs:
go-version-latest: go-version-latest:
docker: docker:
- image: cimg/go:1.22-node - image: cimg/go:1.22-node
resource_class: large resource_class: large
steps: steps:
- checkout - checkout
- run: make - run: make
- run: make alltest - run: make alltest
go-version-last:
docker:
- image: cimg/go:1.21-node
resource_class: large
steps:
- checkout
- run: make
- run: make alltest
workflows: workflows:
version: 2 version: 2
build_and_test: build_and_test:
jobs: jobs:
- go-version-latest - go-version-latest
- go-version-last

View File

@@ -2,7 +2,7 @@ name: Build Image and Publish to Dockerhub & GPR
on: on:
release: release:
types: [ created ] types: [ published ]
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
@@ -61,7 +61,7 @@ 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@v4 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: ./dockerfiles/Dockerfile-for-frpc file: ./dockerfiles/Dockerfile-for-frpc

View File

@@ -18,11 +18,12 @@ jobs:
- uses: actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: '1.22' go-version: '1.22'
cache: false
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v4 uses: golangci/golangci-lint-action@v4
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.55 version: v1.57
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0 # args: --issues-exit-code=0

View File

@@ -1,6 +1,6 @@
service: service:
golangci-lint-version: 1.55.x # use the fixed version to not introduce new linters unexpectedly golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
run: run:
concurrency: 4 concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m # timeout for analysis, e.g. 30s, 5m, default is 1m
@@ -8,23 +8,6 @@ run:
build-tags: build-tags:
- integ - integ
- integfuzz - integfuzz
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- genfiles$
- vendor$
- bin$
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
skip-files:
- ".*\\.pb\\.go"
- ".*\\.gen\\.go"
linters: linters:
disable-all: true disable-all: true
@@ -103,12 +86,8 @@ linters-settings:
severity: "low" severity: "low"
confidence: "low" confidence: "low"
excludes: excludes:
- G102
- G112
- G306
- G401 - G401
- G402 - G402
- G404
- G501 - G501
issues: issues:
@@ -136,6 +115,14 @@ issues:
- unparam - unparam
text: "is always false" text: "is always false"
exclude-dirs:
- genfiles$
- vendor$
- bin$
exclude-files:
- ".*\\.pb\\.go"
- ".*\\.gen\\.go"
# 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

@@ -1,23 +1,35 @@
export PATH := $(GOPATH)/bin:$(PATH) export PATH := $(PATH):`go env GOPATH`/bin
export GO111MODULE=on export GO111MODULE=on
LDFLAGS := -s -w LDFLAGS := -s -w
os-archs=darwin:amd64 darwin:arm64 freebsd:amd64 linux:amd64 linux:arm linux:arm64 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 os-archs=darwin:amd64 darwin:arm64 freebsd:amd64 linux:amd64 linux:arm:7 linux:arm:5 linux:arm64 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 android:arm64
all: build all: build
build: app build: app
app: app:
@$(foreach n, $(os-archs),\ @$(foreach n, $(os-archs), \
os=$(shell echo "$(n)" | cut -d : -f 1);\ os=$(shell echo "$(n)" | cut -d : -f 1); \
arch=$(shell echo "$(n)" | cut -d : -f 2);\ arch=$(shell echo "$(n)" | cut -d : -f 2); \
gomips=$(shell echo "$(n)" | cut -d : -f 3);\ extra=$(shell echo "$(n)" | cut -d : -f 3); \
target_suffix=$${os}_$${arch};\ flags=''; \
echo "Build $${os}-$${arch}...";\ target_suffix=$${os}_$${arch}; \
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} GOMIPS=$${gomips} go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_$${target_suffix} ./cmd/frpc;\ if [ "$${os}" = "linux" ] && [ "$${arch}" = "arm" ] && [ "$${extra}" != "" ] ; then \
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} GOMIPS=$${gomips} go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_$${target_suffix} ./cmd/frps;\ if [ "$${extra}" = "7" ]; then \
echo "Build $${os}-$${arch} done";\ flags=GOARM=7; \
target_suffix=$${os}_arm_hf; \
elif [ "$${extra}" = "5" ]; then \
flags=GOARM=5; \
target_suffix=$${os}_arm; \
fi; \
elif [ "$${os}" = "linux" ] && ([ "$${arch}" = "mips" ] || [ "$${arch}" = "mipsle" ]) && [ "$${extra}" != "" ] ; then \
flags=GOMIPS=$${extra}; \
fi; \
echo "Build $${os}-$${arch}$${extra:+ ($${extra})}..."; \
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $${flags} go build -trimpath -ldflags "$(LDFLAGS)" -tags frpc -o ./release/frpc_$${target_suffix} ./cmd/frpc; \
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $${flags} go build -trimpath -ldflags "$(LDFLAGS)" -tags frps -o ./release/frps_$${target_suffix} ./cmd/frps; \
echo "Build $${os}-$${arch}$${extra:+ ($${extra})} done"; \
) )
@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

View File

@@ -2,6 +2,8 @@
[![Build Status](https://circleci.com/gh/fatedier/frp.svg?style=shield)](https://circleci.com/gh/fatedier/frp) [![Build Status](https://circleci.com/gh/fatedier/frp.svg?style=shield)](https://circleci.com/gh/fatedier/frp)
[![GitHub release](https://img.shields.io/github/tag/fatedier/frp.svg?label=release)](https://github.com/fatedier/frp/releases) [![GitHub release](https://img.shields.io/github/tag/fatedier/frp.svg?label=release)](https://github.com/fatedier/frp/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/fatedier/frp)](https://goreportcard.com/report/github.com/fatedier/frp)
[![GitHub Releases Stats](https://img.shields.io/github/downloads/fatedier/frp/total.svg?logo=github)](https://somsubhra.github.io/github-release-stats/?username=fatedier&repository=frp)
[README](README.md) | [中文文档](README_zh.md) [README](README.md) | [中文文档](README_zh.md)
@@ -11,6 +13,10 @@
<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="350px" 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>
<a>&nbsp</a>
<a href="https://github.com/daytonaio/daytona" target="_blank">
<img width="360px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_daytona.png">
</a>
</p> </p>
<!--gold sponsors end--> <!--gold sponsors end-->
@@ -72,9 +78,11 @@ frp also offers a P2P connect mode.
* [URL Routing](#url-routing) * [URL Routing](#url-routing)
* [TCP Port Multiplexing](#tcp-port-multiplexing) * [TCP Port Multiplexing](#tcp-port-multiplexing)
* [Connecting to frps via PROXY](#connecting-to-frps-via-proxy) * [Connecting to frps via PROXY](#connecting-to-frps-via-proxy)
* [Port range mapping](#port-range-mapping)
* [Client Plugins](#client-plugins) * [Client Plugins](#client-plugins)
* [Server Manage Plugins](#server-manage-plugins) * [Server Manage Plugins](#server-manage-plugins)
* [SSH Tunnel Gateway](#ssh-tunnel-gateway) * [SSH Tunnel Gateway](#ssh-tunnel-gateway)
* [Releated Projects](#releated-projects)
* [Contributing](#contributing) * [Contributing](#contributing)
* [Donation](#donation) * [Donation](#donation)
* [GitHub Sponsors](#github-sponsors) * [GitHub Sponsors](#github-sponsors)
@@ -344,7 +352,6 @@ You may substitute `https2https` for the plugin, and point the `localAddr` to a
# frpc.toml # frpc.toml
serverAddr = "x.x.x.x" serverAddr = "x.x.x.x"
serverPort = 7000 serverPort = 7000
vhostHTTPSPort = 443
[[proxies]] [[proxies]]
name = "test_https2http" name = "test_https2http"
@@ -797,7 +804,7 @@ You can disable this feature by modify `frps.toml` and `frpc.toml`:
```toml ```toml
# frps.toml and frpc.toml, must be same # frps.toml and frpc.toml, must be same
tcpMux = false transport.tcpMux = false
``` ```
### Support KCP Protocol ### Support KCP Protocol
@@ -976,7 +983,7 @@ The HTTP request will have the `Host` header rewritten to `Host: dev.example.com
### Setting other HTTP Headers ### Setting other HTTP Headers
Similar to `Host`, You can override other HTTP request headers with proxy type `http`. Similar to `Host`, You can override other HTTP request and response headers with proxy type `http`.
```toml ```toml
# frpc.toml # frpc.toml
@@ -988,15 +995,16 @@ localPort = 80
customDomains = ["test.example.com"] customDomains = ["test.example.com"]
hostHeaderRewrite = "dev.example.com" hostHeaderRewrite = "dev.example.com"
requestHeaders.set.x-from-where = "frp" requestHeaders.set.x-from-where = "frp"
responseHeaders.set.foo = "bar"
``` ```
In this example, it will set header `x-from-where: frp` in the HTTP request. In this example, it will set header `x-from-where: frp` in the HTTP request and `foo: bar` in the HTTP response.
### Get Real IP ### Get Real IP
#### HTTP X-Forwarded-For #### HTTP X-Forwarded-For
This feature is for http proxy only. This feature is for `http` proxies or proxies with the `https2http` and `https2https` plugins enabled.
You can get user's real IP from HTTP request headers `X-Forwarded-For`. You can get user's real IP from HTTP request headers `X-Forwarded-For`.
@@ -1152,6 +1160,24 @@ serverPort = 7000
transport.proxyURL = "http://user:pwd@192.168.1.128:8080" transport.proxyURL = "http://user:pwd@192.168.1.128:8080"
``` ```
### Port range mapping
*Added in v0.56.0*
We can use the range syntax of Go template combined with the built-in `parseNumberRangePair` function to achieve port range mapping.
The following example, when run, will create 8 proxies named `test-6000, test-6001 ... test-6007`, each mapping the remote port to the local port.
```
{{- range $_, $v := parseNumberRangePair "6000-6006,6007" "6000-6006,6007" }}
[[proxies]]
name = "tcp-{{ $v.First }}"
type = "tcp"
localPort = {{ $v.First }}
remotePort = {{ $v.Second }}
{{- end }}
```
### Client Plugins ### Client Plugins
frpc only forwards requests to local TCP or UDP ports by default. frpc only forwards requests to local TCP or UDP ports by default.
@@ -1219,6 +1245,11 @@ frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote
Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information. Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information.
## Releated Projects
* [gofrp/plugin](https://github.com/gofrp/plugin) - A repository for frp plugins that contains a variety of plugins implemented based on the frp extension mechanism, meeting the customization needs of different scenarios.
* [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - A lightweight version of the frp client (around 3.5MB at minimum) implemented using the ssh protocol, supporting some of the most commonly used features, suitable for devices with limited resources.
## Contributing ## Contributing
Interested in getting involved? We would like to help you! Interested in getting involved? We would like to help you!

View File

@@ -2,6 +2,8 @@
[![Build Status](https://circleci.com/gh/fatedier/frp.svg?style=shield)](https://circleci.com/gh/fatedier/frp) [![Build Status](https://circleci.com/gh/fatedier/frp.svg?style=shield)](https://circleci.com/gh/fatedier/frp)
[![GitHub release](https://img.shields.io/github/tag/fatedier/frp.svg?label=release)](https://github.com/fatedier/frp/releases) [![GitHub release](https://img.shields.io/github/tag/fatedier/frp.svg?label=release)](https://github.com/fatedier/frp/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/fatedier/frp)](https://goreportcard.com/report/github.com/fatedier/frp)
[![GitHub Releases Stats](https://img.shields.io/github/downloads/fatedier/frp/total.svg?logo=github)](https://somsubhra.github.io/github-release-stats/?username=fatedier&repository=frp)
[README](README.md) | [中文文档](README_zh.md) [README](README.md) | [中文文档](README_zh.md)
@@ -13,6 +15,10 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP
<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="350px" 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>
<a>&nbsp</a>
<a href="https://github.com/daytonaio/daytona" target="_blank">
<img width="360px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_daytona.png">
</a>
</p> </p>
<!--gold sponsors end--> <!--gold sponsors end-->
@@ -66,7 +72,12 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
* 贡献代码请提交 PR 至 dev 分支master 分支仅用于发布稳定可用版本。 * 贡献代码请提交 PR 至 dev 分支master 分支仅用于发布稳定可用版本。
* 如果你有任何其他方面的问题或合作,欢迎发送邮件至 fatedier@gmail.com 。 * 如果你有任何其他方面的问题或合作,欢迎发送邮件至 fatedier@gmail.com 。
**提醒:和项目相关的问题最好在 [issues](https://github.com/fatedier/frp/issues) 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。** **提醒:和项目相关的问题在 [issues](https://github.com/fatedier/frp/issues) 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。**
## 关联项目
* [gofrp/plugin](https://github.com/gofrp/plugin) - frp 插件仓库,收录了基于 frp 扩展机制实现的各种插件,满足各种场景下的定制化需求。
* [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - 基于 ssh 协议实现的 frp 客户端的精简版本(最低约 3.5MB 左右),支持常用的部分功能,适用于资源有限的设备。
## 赞助 ## 赞助
@@ -87,7 +98,3 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
如果您想了解更多 frp 相关技术以及更新详解,或者寻求任何 frp 使用方面的帮助,都可以通过微信扫描下方的二维码付费加入知识星球的官方社群: 如果您想了解更多 frp 相关技术以及更新详解,或者寻求任何 frp 使用方面的帮助,都可以通过微信扫描下方的二维码付费加入知识星球的官方社群:
![zsxq](/doc/pic/zsxq.jpg) ![zsxq](/doc/pic/zsxq.jpg)
### 微信支付捐赠
![donate-wechatpay](/doc/pic/donate-wechatpay.png)

View File

@@ -1,3 +1,9 @@
### Features ### Fixes
* Proxy supports configuring annotations, which will be displayed in the frps dashboard. * Fixed an issue where HTTP/2 was not enabled for https2http and https2https plugins.
* Fixed the issue where the default values of INI configuration parameters are inconsistent with other configuration formats.
### Changes
* Updated the default value of `transport.tcpMuxKeepaliveInterval` from 60 to 30.
* On the Android platform, the Google DNS server is used only when the default DNS server cannot be obtained.

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>frps dashboard</title> <title>frps dashboard</title>
<script type="module" crossorigin src="./index-ky4re_ta.js"></script> <script type="module" crossorigin src="./index-82-40HIG.js"></script>
<link rel="stylesheet" crossorigin href="./index-rzPDshRD.css"> <link rel="stylesheet" crossorigin href="./index-rzPDshRD.css">
</head> </head>

View File

@@ -15,19 +15,17 @@
package client package client
import ( import (
"cmp"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"net" "net"
"net/http" "net/http"
"os" "os"
"sort" "slices"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/samber/lo"
"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/config/v1/validation" "github.com/fatedier/frp/pkg/config/v1/validation"
@@ -78,9 +76,9 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
strictConfigMode, _ = strconv.ParseBool(strictStr) strictConfigMode, _ = strconv.ParseBool(strictStr)
} }
log.Info("api request [/api/reload]") log.Infof("api request [/api/reload]")
defer func() { defer func() {
log.Info("api response [/api/reload], code [%d]", res.Code) log.Infof("api response [/api/reload], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
@@ -91,32 +89,32 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
res.Code = 400 res.Code = 400
res.Msg = err.Error() res.Msg = err.Error()
log.Warn("reload frpc proxy config error: %s", res.Msg) log.Warnf("reload frpc proxy config error: %s", res.Msg)
return return
} }
if _, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs); err != nil { if _, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs); err != nil {
res.Code = 400 res.Code = 400
res.Msg = err.Error() res.Msg = err.Error()
log.Warn("reload frpc proxy config error: %s", res.Msg) log.Warnf("reload frpc proxy config error: %s", res.Msg)
return return
} }
if err := svr.UpdateAllConfigurer(proxyCfgs, visitorCfgs); err != nil { if err := svr.UpdateAllConfigurer(proxyCfgs, visitorCfgs); err != nil {
res.Code = 500 res.Code = 500
res.Msg = err.Error() res.Msg = err.Error()
log.Warn("reload frpc proxy config error: %s", res.Msg) log.Warnf("reload frpc proxy config error: %s", res.Msg)
return return
} }
log.Info("success reload conf") log.Infof("success reload conf")
} }
// POST /api/stop // POST /api/stop
func (svr *Service) apiStop(w http.ResponseWriter, _ *http.Request) { func (svr *Service) apiStop(w http.ResponseWriter, _ *http.Request) {
res := GeneralResponse{Code: 200} res := GeneralResponse{Code: 200}
log.Info("api request [/api/stop]") log.Infof("api request [/api/stop]")
defer func() { defer func() {
log.Info("api response [/api/stop], code [%d]", res.Code) log.Infof("api response [/api/stop], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
@@ -153,7 +151,7 @@ func NewProxyStatusResp(status *proxy.WorkingStatus, serverAddr string) ProxySta
if status.Err == "" { if status.Err == "" {
psr.RemoteAddr = status.RemoteAddr psr.RemoteAddr = status.RemoteAddr
if lo.Contains([]string{"tcp", "udp"}, status.Type) { if slices.Contains([]string{"tcp", "udp"}, status.Type) {
psr.RemoteAddr = serverAddr + psr.RemoteAddr psr.RemoteAddr = serverAddr + psr.RemoteAddr
} }
} }
@@ -167,9 +165,9 @@ func (svr *Service) apiStatus(w http.ResponseWriter, _ *http.Request) {
res StatusResp = make(map[string][]ProxyStatusResp) res StatusResp = make(map[string][]ProxyStatusResp)
) )
log.Info("Http request [/api/status]") log.Infof("Http request [/api/status]")
defer func() { defer func() {
log.Info("Http response [/api/status]") log.Infof("Http response [/api/status]")
buf, _ = json.Marshal(&res) buf, _ = json.Marshal(&res)
_, _ = w.Write(buf) _, _ = w.Write(buf)
}() }()
@@ -190,8 +188,8 @@ func (svr *Service) apiStatus(w http.ResponseWriter, _ *http.Request) {
if len(arrs) <= 1 { if len(arrs) <= 1 {
continue continue
} }
sort.Slice(arrs, func(i, j int) bool { slices.SortFunc(arrs, func(a, b ProxyStatusResp) int {
return strings.Compare(arrs[i].Name, arrs[j].Name) < 0 return cmp.Compare(a.Name, b.Name)
}) })
} }
} }
@@ -200,9 +198,9 @@ func (svr *Service) apiStatus(w http.ResponseWriter, _ *http.Request) {
func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) { func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
res := GeneralResponse{Code: 200} res := GeneralResponse{Code: 200}
log.Info("Http get request [/api/config]") log.Infof("Http get request [/api/config]")
defer func() { defer func() {
log.Info("Http get response [/api/config], code [%d]", res.Code) log.Infof("Http get response [/api/config], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
@@ -212,7 +210,7 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
if svr.configFilePath == "" { if svr.configFilePath == "" {
res.Code = 400 res.Code = 400
res.Msg = "frpc has no config file path" res.Msg = "frpc has no config file path"
log.Warn("%s", res.Msg) log.Warnf("%s", res.Msg)
return return
} }
@@ -220,7 +218,7 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
if err != nil { if err != nil {
res.Code = 400 res.Code = 400
res.Msg = err.Error() res.Msg = err.Error()
log.Warn("load frpc config file error: %s", res.Msg) log.Warnf("load frpc config file error: %s", res.Msg)
return return
} }
res.Msg = string(content) res.Msg = string(content)
@@ -230,9 +228,9 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) { func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
res := GeneralResponse{Code: 200} res := GeneralResponse{Code: 200}
log.Info("Http put request [/api/config]") log.Infof("Http put request [/api/config]")
defer func() { defer func() {
log.Info("Http put response [/api/config], code [%d]", res.Code) log.Infof("Http put response [/api/config], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
@@ -244,21 +242,21 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
res.Code = 400 res.Code = 400
res.Msg = fmt.Sprintf("read request body error: %v", err) res.Msg = fmt.Sprintf("read request body error: %v", err)
log.Warn("%s", res.Msg) log.Warnf("%s", res.Msg)
return return
} }
if len(body) == 0 { if len(body) == 0 {
res.Code = 400 res.Code = 400
res.Msg = "body can't be empty" res.Msg = "body can't be empty"
log.Warn("%s", res.Msg) log.Warnf("%s", res.Msg)
return return
} }
if err := os.WriteFile(svr.configFilePath, body, 0o644); err != nil { if err := os.WriteFile(svr.configFilePath, body, 0o600); err != nil {
res.Code = 500 res.Code = 500
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err) res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
log.Warn("%s", res.Msg) log.Warnf("%s", res.Msg)
return return
} }
} }

View File

@@ -24,7 +24,7 @@ import (
"sync" "sync"
"time" "time"
libdial "github.com/fatedier/golib/net/dial" libnet "github.com/fatedier/golib/net"
fmux "github.com/hashicorp/yamux" fmux "github.com/hashicorp/yamux"
quic "github.com/quic-go/quic-go" quic "github.com/quic-go/quic-go"
"github.com/samber/lo" "github.com/samber/lo"
@@ -84,7 +84,7 @@ func (c *defaultConnectorImpl) Open() error {
tlsConfig, err = transport.NewClientTLSConfig("", "", "", sn) tlsConfig, err = transport.NewClientTLSConfig("", "", "", sn)
} }
if err != nil { if err != nil {
xl.Warn("fail to build tls configuration, err: %v", err) xl.Warnf("fail to build tls configuration, err: %v", err)
return err return err
} }
tlsConfig.NextProtos = []string{"frp"} tlsConfig.NextProtos = []string{"frp"}
@@ -164,49 +164,49 @@ func (c *defaultConnectorImpl) realConnect() (net.Conn, error) {
c.cfg.Transport.TLS.TrustedCaFile, c.cfg.Transport.TLS.TrustedCaFile,
sn) sn)
if err != nil { if err != nil {
xl.Warn("fail to build tls configuration, err: %v", err) xl.Warnf("fail to build tls configuration, err: %v", err)
return nil, err return nil, err
} }
} }
proxyType, addr, auth, err := libdial.ParseProxyURL(c.cfg.Transport.ProxyURL) proxyType, addr, auth, err := libnet.ParseProxyURL(c.cfg.Transport.ProxyURL)
if err != nil { if err != nil {
xl.Error("fail to parse proxy url") xl.Errorf("fail to parse proxy url")
return nil, err return nil, err
} }
dialOptions := []libdial.DialOption{} dialOptions := []libnet.DialOption{}
protocol := c.cfg.Transport.Protocol protocol := c.cfg.Transport.Protocol
switch protocol { switch protocol {
case "websocket": case "websocket":
protocol = "tcp" protocol = "tcp"
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")})) dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{ dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)), Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
})) }))
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig)) dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
case "wss": case "wss":
protocol = "tcp" protocol = "tcp"
dialOptions = append(dialOptions, libdial.WithTLSConfigAndPriority(100, tlsConfig)) dialOptions = append(dialOptions, libnet.WithTLSConfigAndPriority(100, tlsConfig))
// Make sure that if it is wss, the websocket hook is executed after the tls hook. // Make sure that if it is wss, the websocket hook is executed after the tls hook.
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110})) dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
default: default:
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{ dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)), Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
})) }))
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig)) dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
} }
if c.cfg.Transport.ConnectServerLocalIP != "" { if c.cfg.Transport.ConnectServerLocalIP != "" {
dialOptions = append(dialOptions, libdial.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP)) dialOptions = append(dialOptions, libnet.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
} }
dialOptions = append(dialOptions, dialOptions = append(dialOptions,
libdial.WithProtocol(protocol), libnet.WithProtocol(protocol),
libdial.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second), libnet.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
libdial.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second), libnet.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
libdial.WithProxy(proxyType, addr), libnet.WithProxy(proxyType, addr),
libdial.WithProxyAuth(auth), libnet.WithProxyAuth(auth),
) )
conn, err := libdial.DialContext( conn, err := libnet.DialContext(
c.ctx, c.ctx,
net.JoinHostPort(c.cfg.ServerAddr, strconv.Itoa(c.cfg.ServerPort)), net.JoinHostPort(c.cfg.ServerAddr, strconv.Itoa(c.cfg.ServerPort)),
dialOptions..., dialOptions...,

View File

@@ -20,8 +20,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/samber/lo"
"github.com/fatedier/frp/client/proxy" "github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/client/visitor" "github.com/fatedier/frp/client/visitor"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
@@ -124,7 +122,7 @@ func (ctl *Control) handleReqWorkConn(_ msg.Message) {
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) xl.Warnf("start new connection to server error: %v", err)
return return
} }
@@ -132,24 +130,24 @@ func (ctl *Control) handleReqWorkConn(_ msg.Message) {
RunID: ctl.sessionCtx.RunID, RunID: ctl.sessionCtx.RunID,
} }
if err = ctl.sessionCtx.AuthSetter.SetNewWorkConn(m); err != nil { if err = ctl.sessionCtx.AuthSetter.SetNewWorkConn(m); err != nil {
xl.Warn("error during NewWorkConn authentication: %v", err) xl.Warnf("error during NewWorkConn authentication: %v", err)
workConn.Close() workConn.Close()
return return
} }
if err = msg.WriteMsg(workConn, m); err != nil { if err = msg.WriteMsg(workConn, m); err != nil {
xl.Warn("work connection write to server error: %v", err) xl.Warnf("work connection write to server error: %v", err)
workConn.Close() workConn.Close()
return return
} }
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.Trace("work connection closed before response StartWorkConn message: %v", err) xl.Tracef("work connection closed before response StartWorkConn message: %v", err)
workConn.Close() workConn.Close()
return return
} }
if startMsg.Error != "" { if startMsg.Error != "" {
xl.Error("StartWorkConn contains error: %s", startMsg.Error) xl.Errorf("StartWorkConn contains error: %s", startMsg.Error)
workConn.Close() workConn.Close()
return return
} }
@@ -165,9 +163,9 @@ func (ctl *Control) handleNewProxyResp(m msg.Message) {
// Start a new proxy handler if no error got // Start a new proxy handler if no error got
err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error) err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error)
if err != nil { if err != nil {
xl.Warn("[%s] start error: %v", inMsg.ProxyName, err) xl.Warnf("[%s] start error: %v", inMsg.ProxyName, err)
} else { } else {
xl.Info("[%s] start proxy success", inMsg.ProxyName) xl.Infof("[%s] start proxy success", inMsg.ProxyName)
} }
} }
@@ -178,7 +176,7 @@ func (ctl *Control) handleNatHoleResp(m msg.Message) {
// Dispatch the NatHoleResp message to the related proxy. // Dispatch the NatHoleResp message to the related proxy.
ok := ctl.msgTransporter.DispatchWithType(inMsg, msg.TypeNameNatHoleResp, inMsg.TransactionID) ok := ctl.msgTransporter.DispatchWithType(inMsg, msg.TypeNameNatHoleResp, inMsg.TransactionID)
if !ok { if !ok {
xl.Trace("dispatch NatHoleResp message to related proxy error") xl.Tracef("dispatch NatHoleResp message to related proxy error")
} }
} }
@@ -187,12 +185,12 @@ func (ctl *Control) handlePong(m msg.Message) {
inMsg := m.(*msg.Pong) inMsg := m.(*msg.Pong)
if inMsg.Error != "" { if inMsg.Error != "" {
xl.Error("Pong message contains error: %s", inMsg.Error) xl.Errorf("Pong message contains error: %s", inMsg.Error)
ctl.closeSession() ctl.closeSession()
return return
} }
ctl.lastPong.Store(time.Now()) ctl.lastPong.Store(time.Now())
xl.Debug("receive heartbeat from server") xl.Debugf("receive heartbeat from server")
} }
// closeSession closes the control connection. // closeSession closes the control connection.
@@ -236,15 +234,13 @@ func (ctl *Control) registerMsgHandlers() {
func (ctl *Control) heartbeatWorker() { func (ctl *Control) heartbeatWorker() {
xl := ctl.xl xl := ctl.xl
// TODO(fatedier): Change default value of HeartbeatInterval to -1 if tcpmux is enabled.
// Users can still enable heartbeat feature by setting HeartbeatInterval to a positive value.
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 { if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 {
// send heartbeat to server // Send heartbeat to server.
sendHeartBeat := func() (bool, error) { sendHeartBeat := func() (bool, error) {
xl.Debug("send heartbeat to server") xl.Debugf("send heartbeat to server")
pingMsg := &msg.Ping{} pingMsg := &msg.Ping{}
if err := ctl.sessionCtx.AuthSetter.SetPing(pingMsg); err != nil { if err := ctl.sessionCtx.AuthSetter.SetPing(pingMsg); err != nil {
xl.Warn("error during ping authentication: %v, skip sending ping message", err) xl.Warnf("error during ping authentication: %v, skip sending ping message", err)
return false, err return false, err
} }
_ = ctl.msgDispatcher.Send(pingMsg) _ = ctl.msgDispatcher.Send(pingMsg)
@@ -263,13 +259,11 @@ func (ctl *Control) heartbeatWorker() {
) )
} }
// Check heartbeat timeout only if TCPMux is not enabled and users don't disable heartbeat feature. // Check heartbeat timeout.
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 && if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 {
!lo.FromPtr(ctl.sessionCtx.Common.Transport.TCPMux) {
go wait.Until(func() { go wait.Until(func() {
if time.Since(ctl.lastPong.Load().(time.Time)) > time.Duration(ctl.sessionCtx.Common.Transport.HeartbeatTimeout)*time.Second { if time.Since(ctl.lastPong.Load().(time.Time)) > time.Duration(ctl.sessionCtx.Common.Transport.HeartbeatTimeout)*time.Second {
xl.Warn("heartbeat timeout") xl.Warnf("heartbeat timeout")
ctl.closeSession() ctl.closeSession()
return return
} }

View File

@@ -40,8 +40,8 @@ type Monitor struct {
addr string addr string
// For http // For http
url string url string
header http.Header
failedTimes uint64 failedTimes uint64
statusOK bool statusOK bool
statusNormalFn func() statusNormalFn func()
@@ -73,6 +73,11 @@ func NewMonitor(ctx context.Context, cfg v1.HealthCheckConfig, addr string,
} }
url = s + cfg.Path url = s + cfg.Path
} }
header := make(http.Header)
for _, h := range cfg.HTTPHeaders {
header.Set(h.Name, h.Value)
}
return &Monitor{ return &Monitor{
checkType: cfg.Type, checkType: cfg.Type,
interval: time.Duration(cfg.IntervalSeconds) * time.Second, interval: time.Duration(cfg.IntervalSeconds) * time.Second,
@@ -80,6 +85,7 @@ func NewMonitor(ctx context.Context, cfg v1.HealthCheckConfig, addr string,
maxFailedTimes: cfg.MaxFailed, maxFailedTimes: cfg.MaxFailed,
addr: addr, addr: addr,
url: url, url: url,
header: header,
statusOK: false, statusOK: false,
statusNormalFn: statusNormalFn, statusNormalFn: statusNormalFn,
statusFailedFn: statusFailedFn, statusFailedFn: statusFailedFn,
@@ -112,17 +118,17 @@ func (monitor *Monitor) checkWorker() {
} }
if err == nil { if err == nil {
xl.Trace("do one health check success") xl.Tracef("do one health check success")
if !monitor.statusOK && monitor.statusNormalFn != nil { if !monitor.statusOK && monitor.statusNormalFn != nil {
xl.Info("health check status change to success") xl.Infof("health check status change to success")
monitor.statusOK = true monitor.statusOK = true
monitor.statusNormalFn() monitor.statusNormalFn()
} }
} else { } else {
xl.Warn("do one health check failed: %v", err) xl.Warnf("do one health check failed: %v", err)
monitor.failedTimes++ monitor.failedTimes++
if monitor.statusOK && int(monitor.failedTimes) >= monitor.maxFailedTimes && monitor.statusFailedFn != nil { if monitor.statusOK && int(monitor.failedTimes) >= monitor.maxFailedTimes && monitor.statusFailedFn != nil {
xl.Warn("health check status change to failed") xl.Warnf("health check status change to failed")
monitor.statusOK = false monitor.statusOK = false
monitor.statusFailedFn() monitor.statusFailedFn()
} }
@@ -163,6 +169,8 @@ func (monitor *Monitor) doHTTPCheck(ctx context.Context) error {
if err != nil { if err != nil {
return err return err
} }
req.Header = monitor.header
req.Host = monitor.header.Get("Host")
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return err return err

View File

@@ -25,7 +25,7 @@ import (
"time" "time"
libio "github.com/fatedier/golib/io" libio "github.com/fatedier/golib/io"
libdial "github.com/fatedier/golib/net/dial" libnet "github.com/fatedier/golib/net"
pp "github.com/pires/go-proxyproto" pp "github.com/pires/go-proxyproto"
"golang.org/x/time/rate" "golang.org/x/time/rate"
@@ -141,13 +141,13 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
}) })
} }
xl.Trace("handle tcp work connection, useEncryption: %t, useCompression: %t", xl.Tracef("handle tcp work connection, useEncryption: %t, useCompression: %t",
baseCfg.Transport.UseEncryption, baseCfg.Transport.UseCompression) baseCfg.Transport.UseEncryption, baseCfg.Transport.UseCompression)
if baseCfg.Transport.UseEncryption { if baseCfg.Transport.UseEncryption {
remote, err = libio.WithEncryption(remote, encKey) remote, err = libio.WithEncryption(remote, encKey)
if err != nil { if err != nil {
workConn.Close() workConn.Close()
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }
@@ -158,68 +158,70 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
// check if we need to send proxy protocol info // check if we need to send proxy protocol info
var extraInfo plugin.ExtraInfo var extraInfo plugin.ExtraInfo
if baseCfg.Transport.ProxyProtocolVersion != "" { if m.SrcAddr != "" && m.SrcPort != 0 {
if m.SrcAddr != "" && m.SrcPort != 0 { if m.DstAddr == "" {
if m.DstAddr == "" { m.DstAddr = "127.0.0.1"
m.DstAddr = "127.0.0.1"
}
srcAddr, _ := net.ResolveTCPAddr("tcp", net.JoinHostPort(m.SrcAddr, strconv.Itoa(int(m.SrcPort))))
dstAddr, _ := net.ResolveTCPAddr("tcp", net.JoinHostPort(m.DstAddr, strconv.Itoa(int(m.DstPort))))
h := &pp.Header{
Command: pp.PROXY,
SourceAddr: srcAddr,
DestinationAddr: dstAddr,
}
if strings.Contains(m.SrcAddr, ".") {
h.TransportProtocol = pp.TCPv4
} else {
h.TransportProtocol = pp.TCPv6
}
if baseCfg.Transport.ProxyProtocolVersion == "v1" {
h.Version = 1
} else if baseCfg.Transport.ProxyProtocolVersion == "v2" {
h.Version = 2
}
extraInfo.ProxyProtocolHeader = h
} }
srcAddr, _ := net.ResolveTCPAddr("tcp", net.JoinHostPort(m.SrcAddr, strconv.Itoa(int(m.SrcPort))))
dstAddr, _ := net.ResolveTCPAddr("tcp", net.JoinHostPort(m.DstAddr, strconv.Itoa(int(m.DstPort))))
extraInfo.SrcAddr = srcAddr
extraInfo.DstAddr = dstAddr
}
if baseCfg.Transport.ProxyProtocolVersion != "" && m.SrcAddr != "" && m.SrcPort != 0 {
h := &pp.Header{
Command: pp.PROXY,
SourceAddr: extraInfo.SrcAddr,
DestinationAddr: extraInfo.DstAddr,
}
if strings.Contains(m.SrcAddr, ".") {
h.TransportProtocol = pp.TCPv4
} else {
h.TransportProtocol = pp.TCPv6
}
if baseCfg.Transport.ProxyProtocolVersion == "v1" {
h.Version = 1
} else if baseCfg.Transport.ProxyProtocolVersion == "v2" {
h.Version = 2
}
extraInfo.ProxyProtocolHeader = h
} }
if pxy.proxyPlugin != nil { if pxy.proxyPlugin != nil {
// if plugin is set, let plugin handle connection first // if plugin is set, let plugin handle connection first
xl.Debug("handle by plugin: %s", pxy.proxyPlugin.Name()) xl.Debugf("handle by plugin: %s", pxy.proxyPlugin.Name())
pxy.proxyPlugin.Handle(remote, workConn, &extraInfo) pxy.proxyPlugin.Handle(remote, workConn, &extraInfo)
xl.Debug("handle by plugin finished") xl.Debugf("handle by plugin finished")
return return
} }
localConn, err := libdial.Dial( localConn, err := libnet.Dial(
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)), net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
libdial.WithTimeout(10*time.Second), libnet.WithTimeout(10*time.Second),
) )
if err != nil { if err != nil {
workConn.Close() workConn.Close()
xl.Error("connect to local service [%s:%d] error: %v", baseCfg.LocalIP, baseCfg.LocalPort, err) xl.Errorf("connect to local service [%s:%d] error: %v", baseCfg.LocalIP, baseCfg.LocalPort, err)
return return
} }
xl.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(), xl.Debugf("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String()) localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
if extraInfo.ProxyProtocolHeader != nil { if extraInfo.ProxyProtocolHeader != nil {
if _, err := extraInfo.ProxyProtocolHeader.WriteTo(localConn); err != nil { if _, err := extraInfo.ProxyProtocolHeader.WriteTo(localConn); err != nil {
workConn.Close() workConn.Close()
xl.Error("write proxy protocol header to local conn error: %v", err) xl.Errorf("write proxy protocol header to local conn error: %v", err)
return return
} }
} }
_, _, errs := libio.Join(localConn, remote) _, _, errs := libio.Join(localConn, remote)
xl.Debug("join connections closed") xl.Debugf("join connections closed")
if len(errs) > 0 { if len(errs) > 0 {
xl.Trace("join connections errors: %v", errs) xl.Tracef("join connections errors: %v", errs)
} }
if compressionResourceRecycleFn != nil { if compressionResourceRecycleFn != nil {
compressionResourceRecycleFn() compressionResourceRecycleFn()

View File

@@ -152,7 +152,7 @@ func (pm *Manager) UpdateAll(proxyCfgs []v1.ProxyConfigurer) {
} }
} }
if len(delPxyNames) > 0 { if len(delPxyNames) > 0 {
xl.Info("proxy removed: %s", delPxyNames) xl.Infof("proxy removed: %s", delPxyNames)
} }
addPxyNames := make([]string, 0) addPxyNames := make([]string, 0)
@@ -170,6 +170,6 @@ func (pm *Manager) UpdateAll(proxyCfgs []v1.ProxyConfigurer) {
} }
} }
if len(addPxyNames) > 0 { if len(addPxyNames) > 0 {
xl.Info("proxy added: %s", addPxyNames) xl.Infof("proxy added: %s", addPxyNames)
} }
} }

View File

@@ -114,7 +114,7 @@ func NewWrapper(
addr := net.JoinHostPort(baseInfo.LocalIP, strconv.Itoa(baseInfo.LocalPort)) addr := net.JoinHostPort(baseInfo.LocalIP, strconv.Itoa(baseInfo.LocalPort))
pw.monitor = health.NewMonitor(pw.ctx, baseInfo.HealthCheck, addr, pw.monitor = health.NewMonitor(pw.ctx, baseInfo.HealthCheck, addr,
pw.statusNormalCallback, pw.statusFailedCallback) pw.statusNormalCallback, pw.statusFailedCallback)
xl.Trace("enable health check monitor") xl.Tracef("enable health check monitor")
} }
pw.pxy = NewProxy(pw.ctx, pw.Cfg, clientCfg, pw.msgTransporter) pw.pxy = NewProxy(pw.ctx, pw.Cfg, clientCfg, pw.msgTransporter)
@@ -197,7 +197,7 @@ func (pw *Wrapper) checkWorker() {
(pw.Phase == ProxyPhaseWaitStart && now.After(pw.lastSendStartMsg.Add(waitResponseTimeout))) || (pw.Phase == ProxyPhaseWaitStart && now.After(pw.lastSendStartMsg.Add(waitResponseTimeout))) ||
(pw.Phase == ProxyPhaseStartErr && now.After(pw.lastStartErr.Add(startErrTimeout))) { (pw.Phase == ProxyPhaseStartErr && now.After(pw.lastStartErr.Add(startErrTimeout))) {
xl.Trace("change status from [%s] to [%s]", pw.Phase, ProxyPhaseWaitStart) xl.Tracef("change status from [%s] to [%s]", pw.Phase, ProxyPhaseWaitStart)
pw.Phase = ProxyPhaseWaitStart pw.Phase = ProxyPhaseWaitStart
var newProxyMsg msg.NewProxy var newProxyMsg msg.NewProxy
@@ -212,7 +212,7 @@ func (pw *Wrapper) checkWorker() {
pw.mu.Lock() pw.mu.Lock()
if pw.Phase == ProxyPhaseRunning || pw.Phase == ProxyPhaseWaitStart { if pw.Phase == ProxyPhaseRunning || pw.Phase == ProxyPhaseWaitStart {
pw.close() pw.close()
xl.Trace("change status from [%s] to [%s]", pw.Phase, ProxyPhaseCheckFailed) xl.Tracef("change status from [%s] to [%s]", pw.Phase, ProxyPhaseCheckFailed)
pw.Phase = ProxyPhaseCheckFailed pw.Phase = ProxyPhaseCheckFailed
} }
pw.mu.Unlock() pw.mu.Unlock()
@@ -236,7 +236,7 @@ func (pw *Wrapper) statusNormalCallback() {
default: default:
} }
}) })
xl.Info("health check success") xl.Infof("health check success")
} }
func (pw *Wrapper) statusFailedCallback() { func (pw *Wrapper) statusFailedCallback() {
@@ -248,7 +248,7 @@ func (pw *Wrapper) statusFailedCallback() {
default: default:
} }
}) })
xl.Info("health check failed") xl.Infof("health check failed")
} }
func (pw *Wrapper) InWorkConn(workConn net.Conn, m *msg.StartWorkConn) { func (pw *Wrapper) InWorkConn(workConn net.Conn, m *msg.StartWorkConn) {
@@ -257,7 +257,7 @@ func (pw *Wrapper) InWorkConn(workConn net.Conn, m *msg.StartWorkConn) {
pxy := pw.pxy pxy := pw.pxy
pw.mu.RUnlock() pw.mu.RUnlock()
if pxy != nil && pw.Phase == ProxyPhaseRunning { if pxy != nil && pw.Phase == ProxyPhaseRunning {
xl.Debug("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String()) xl.Debugf("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
go pxy.InWorkConn(workConn, m) go pxy.InWorkConn(workConn, m)
} else { } else {
workConn.Close() workConn.Close()

View File

@@ -81,7 +81,7 @@ func (pxy *SUDPProxy) Close() {
func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) { func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
xl := pxy.xl xl := pxy.xl
xl.Info("incoming a new work connection for sudp proxy, %s", conn.RemoteAddr().String()) xl.Infof("incoming a new work connection for sudp proxy, %s", conn.RemoteAddr().String())
var rwc io.ReadWriteCloser = conn var rwc io.ReadWriteCloser = conn
var err error var err error
@@ -94,7 +94,7 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
rwc, err = libio.WithEncryption(rwc, []byte(pxy.clientCfg.Auth.Token)) rwc, err = libio.WithEncryption(rwc, []byte(pxy.clientCfg.Auth.Token))
if err != nil { if err != nil {
conn.Close() conn.Close()
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }
@@ -133,21 +133,21 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
// first to check sudp proxy is closed or not // first to check sudp proxy is closed or not
select { select {
case <-pxy.closeCh: case <-pxy.closeCh:
xl.Trace("frpc sudp proxy is closed") xl.Tracef("frpc sudp proxy is closed")
return return
default: default:
} }
var udpMsg msg.UDPPacket var udpMsg msg.UDPPacket
if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil { if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
xl.Warn("read from workConn for sudp error: %v", errRet) xl.Warnf("read from workConn for sudp error: %v", errRet)
return return
} }
if errRet := errors.PanicToError(func() { if errRet := errors.PanicToError(func() {
readCh <- &udpMsg readCh <- &udpMsg
}); errRet != nil { }); errRet != nil {
xl.Warn("reader goroutine for sudp work connection closed: %v", errRet) xl.Warnf("reader goroutine for sudp work connection closed: %v", errRet)
return return
} }
} }
@@ -157,21 +157,21 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) { workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
defer func() { defer func() {
closeFn() closeFn()
xl.Info("writer goroutine for sudp work connection closed") xl.Infof("writer goroutine for sudp work connection closed")
}() }()
var errRet error var errRet error
for rawMsg := range sendCh { for rawMsg := range sendCh {
switch m := rawMsg.(type) { switch m := rawMsg.(type) {
case *msg.UDPPacket: case *msg.UDPPacket:
xl.Trace("frpc send udp package to frpc visitor, [udp local: %v, remote: %v], [tcp work conn local: %v, remote: %v]", xl.Tracef("frpc send udp package to frpc visitor, [udp local: %v, remote: %v], [tcp work conn local: %v, remote: %v]",
m.LocalAddr.String(), m.RemoteAddr.String(), conn.LocalAddr().String(), conn.RemoteAddr().String()) m.LocalAddr.String(), m.RemoteAddr.String(), conn.LocalAddr().String(), conn.RemoteAddr().String())
case *msg.Ping: case *msg.Ping:
xl.Trace("frpc send ping message to frpc visitor") xl.Tracef("frpc send ping message to frpc visitor")
} }
if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil { if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
xl.Error("sudp work write error: %v", errRet) xl.Errorf("sudp work write error: %v", errRet)
return return
} }
} }
@@ -191,11 +191,11 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
if errRet = errors.PanicToError(func() { if errRet = errors.PanicToError(func() {
sendCh <- &msg.Ping{} sendCh <- &msg.Ping{}
}); errRet != nil { }); errRet != nil {
xl.Warn("heartbeat goroutine for sudp work connection closed") xl.Warnf("heartbeat goroutine for sudp work connection closed")
return return
} }
case <-pxy.closeCh: case <-pxy.closeCh:
xl.Trace("frpc sudp proxy is closed") xl.Tracef("frpc sudp proxy is closed")
return return
} }
} }

View File

@@ -90,7 +90,7 @@ func (pxy *UDPProxy) Close() {
func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) { func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
xl := pxy.xl xl := pxy.xl
xl.Info("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String()) xl.Infof("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
// close resources related with old workConn // close resources related with old workConn
pxy.Close() pxy.Close()
@@ -105,7 +105,7 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
rwc, err = libio.WithEncryption(rwc, []byte(pxy.clientCfg.Auth.Token)) rwc, err = libio.WithEncryption(rwc, []byte(pxy.clientCfg.Auth.Token))
if err != nil { if err != nil {
conn.Close() conn.Close()
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }
@@ -125,32 +125,32 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
for { for {
var udpMsg msg.UDPPacket var udpMsg msg.UDPPacket
if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil { if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
xl.Warn("read from workConn for udp error: %v", errRet) xl.Warnf("read from workConn for udp error: %v", errRet)
return return
} }
if errRet := errors.PanicToError(func() { if errRet := errors.PanicToError(func() {
xl.Trace("get udp package from workConn: %s", udpMsg.Content) xl.Tracef("get udp package from workConn: %s", udpMsg.Content)
readCh <- &udpMsg readCh <- &udpMsg
}); errRet != nil { }); errRet != nil {
xl.Info("reader goroutine for udp work connection closed: %v", errRet) xl.Infof("reader goroutine for udp work connection closed: %v", errRet)
return return
} }
} }
} }
workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) { workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
defer func() { defer func() {
xl.Info("writer goroutine for udp work connection closed") xl.Infof("writer goroutine for udp work connection closed")
}() }()
var errRet error var errRet error
for rawMsg := range sendCh { for rawMsg := range sendCh {
switch m := rawMsg.(type) { switch m := rawMsg.(type) {
case *msg.UDPPacket: case *msg.UDPPacket:
xl.Trace("send udp package to workConn: %s", m.Content) xl.Tracef("send udp package to workConn: %s", m.Content)
case *msg.Ping: case *msg.Ping:
xl.Trace("send ping message to udp workConn") xl.Tracef("send ping message to udp workConn")
} }
if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil { if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
xl.Error("udp work write error: %v", errRet) xl.Errorf("udp work write error: %v", errRet)
return return
} }
} }
@@ -162,7 +162,7 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
if errRet = errors.PanicToError(func() { if errRet = errors.PanicToError(func() {
sendCh <- &msg.Ping{} sendCh <- &msg.Ping{}
}); errRet != nil { }); errRet != nil {
xl.Trace("heartbeat goroutine for udp work connection closed") xl.Tracef("heartbeat goroutine for udp work connection closed")
break break
} }
} }

View File

@@ -59,17 +59,17 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
var natHoleSidMsg msg.NatHoleSid var natHoleSidMsg msg.NatHoleSid
err := msg.ReadMsgInto(conn, &natHoleSidMsg) err := msg.ReadMsgInto(conn, &natHoleSidMsg)
if err != nil { if err != nil {
xl.Error("xtcp read from workConn error: %v", err) xl.Errorf("xtcp read from workConn error: %v", err)
return return
} }
xl.Trace("nathole prepare start") xl.Tracef("nathole prepare start")
prepareResult, err := nathole.Prepare([]string{pxy.clientCfg.NatHoleSTUNServer}) prepareResult, err := nathole.Prepare([]string{pxy.clientCfg.NatHoleSTUNServer})
if err != nil { if err != nil {
xl.Warn("nathole prepare error: %v", err) xl.Warnf("nathole prepare error: %v", err)
return return
} }
xl.Info("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v", xl.Infof("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v",
prepareResult.NatType, prepareResult.Behavior, prepareResult.Addrs, prepareResult.AssistedAddrs) prepareResult.NatType, prepareResult.Behavior, prepareResult.Addrs, prepareResult.AssistedAddrs)
defer prepareResult.ListenConn.Close() defer prepareResult.ListenConn.Close()
@@ -83,14 +83,14 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
AssistedAddrs: prepareResult.AssistedAddrs, AssistedAddrs: prepareResult.AssistedAddrs,
} }
xl.Trace("nathole exchange info start") xl.Tracef("nathole exchange info start")
natHoleRespMsg, err := nathole.ExchangeInfo(pxy.ctx, pxy.msgTransporter, transactionID, natHoleClientMsg, 5*time.Second) natHoleRespMsg, err := nathole.ExchangeInfo(pxy.ctx, pxy.msgTransporter, transactionID, natHoleClientMsg, 5*time.Second)
if err != nil { if err != nil {
xl.Warn("nathole exchange info error: %v", err) xl.Warnf("nathole exchange info error: %v", err)
return return
} }
xl.Info("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v", xl.Infof("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v",
natHoleRespMsg.Sid, natHoleRespMsg.Protocol, natHoleRespMsg.CandidateAddrs, natHoleRespMsg.Sid, natHoleRespMsg.Protocol, natHoleRespMsg.CandidateAddrs,
natHoleRespMsg.AssistedAddrs, natHoleRespMsg.DetectBehavior) natHoleRespMsg.AssistedAddrs, natHoleRespMsg.DetectBehavior)
@@ -98,7 +98,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
newListenConn, raddr, err := nathole.MakeHole(pxy.ctx, listenConn, natHoleRespMsg, []byte(pxy.cfg.Secretkey)) newListenConn, raddr, err := nathole.MakeHole(pxy.ctx, listenConn, natHoleRespMsg, []byte(pxy.cfg.Secretkey))
if err != nil { if err != nil {
listenConn.Close() listenConn.Close()
xl.Warn("make hole error: %v", err) xl.Warnf("make hole error: %v", err)
_ = pxy.msgTransporter.Send(&msg.NatHoleReport{ _ = pxy.msgTransporter.Send(&msg.NatHoleReport{
Sid: natHoleRespMsg.Sid, Sid: natHoleRespMsg.Sid,
Success: false, Success: false,
@@ -106,7 +106,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
return return
} }
listenConn = newListenConn listenConn = newListenConn
xl.Info("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr) xl.Infof("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr)
_ = pxy.msgTransporter.Send(&msg.NatHoleReport{ _ = pxy.msgTransporter.Send(&msg.NatHoleReport{
Sid: natHoleRespMsg.Sid, Sid: natHoleRespMsg.Sid,
@@ -128,14 +128,14 @@ func (pxy *XTCPProxy) listenByKCP(listenConn *net.UDPConn, raddr *net.UDPAddr, s
laddr, _ := net.ResolveUDPAddr("udp", listenConn.LocalAddr().String()) laddr, _ := net.ResolveUDPAddr("udp", listenConn.LocalAddr().String())
lConn, err := net.DialUDP("udp", laddr, raddr) lConn, err := net.DialUDP("udp", laddr, raddr)
if err != nil { if err != nil {
xl.Warn("dial udp error: %v", err) xl.Warnf("dial udp error: %v", err)
return return
} }
defer lConn.Close() defer lConn.Close()
remote, err := netpkg.NewKCPConnFromUDP(lConn, true, raddr.String()) remote, err := netpkg.NewKCPConnFromUDP(lConn, true, raddr.String())
if err != nil { if err != nil {
xl.Warn("create kcp connection from udp connection error: %v", err) xl.Warnf("create kcp connection from udp connection error: %v", err)
return return
} }
@@ -145,7 +145,7 @@ func (pxy *XTCPProxy) listenByKCP(listenConn *net.UDPConn, raddr *net.UDPAddr, s
fmuxCfg.LogOutput = io.Discard fmuxCfg.LogOutput = io.Discard
session, err := fmux.Server(remote, fmuxCfg) session, err := fmux.Server(remote, fmuxCfg)
if err != nil { if err != nil {
xl.Error("create mux session error: %v", err) xl.Errorf("create mux session error: %v", err)
return return
} }
defer session.Close() defer session.Close()
@@ -153,7 +153,7 @@ func (pxy *XTCPProxy) listenByKCP(listenConn *net.UDPConn, raddr *net.UDPAddr, s
for { for {
muxConn, err := session.Accept() muxConn, err := session.Accept()
if err != nil { if err != nil {
xl.Error("accept connection error: %v", err) xl.Errorf("accept connection error: %v", err)
return return
} }
go pxy.HandleTCPWorkConnection(muxConn, startWorkConnMsg, []byte(pxy.cfg.Secretkey)) go pxy.HandleTCPWorkConnection(muxConn, startWorkConnMsg, []byte(pxy.cfg.Secretkey))
@@ -166,7 +166,7 @@ func (pxy *XTCPProxy) listenByQUIC(listenConn *net.UDPConn, _ *net.UDPAddr, star
tlsConfig, err := transport.NewServerTLSConfig("", "", "") tlsConfig, err := transport.NewServerTLSConfig("", "", "")
if err != nil { if err != nil {
xl.Warn("create tls config error: %v", err) xl.Warnf("create tls config error: %v", err)
return return
} }
tlsConfig.NextProtos = []string{"frp"} tlsConfig.NextProtos = []string{"frp"}
@@ -178,19 +178,19 @@ func (pxy *XTCPProxy) listenByQUIC(listenConn *net.UDPConn, _ *net.UDPAddr, star
}, },
) )
if err != nil { if err != nil {
xl.Warn("dial quic error: %v", err) xl.Warnf("dial quic error: %v", err)
return return
} }
// only accept one connection from raddr // only accept one connection from raddr
c, err := quicListener.Accept(pxy.ctx) c, err := quicListener.Accept(pxy.ctx)
if err != nil { if err != nil {
xl.Error("quic accept connection error: %v", err) xl.Errorf("quic accept connection error: %v", err)
return return
} }
for { for {
stream, err := c.AcceptStream(pxy.ctx) stream, err := c.AcceptStream(pxy.ctx)
if err != nil { if err != nil {
xl.Debug("quic accept stream error: %v", err) xl.Debugf("quic accept stream error: %v", err)
_ = c.CloseWithError(0, "") _ = c.CloseWithError(0, "")
return return
} }

View File

@@ -19,6 +19,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"os"
"runtime" "runtime"
"sync" "sync"
"time" "time"
@@ -40,6 +41,12 @@ import (
func init() { func init() {
crypto.DefaultSalt = "frp" crypto.DefaultSalt = "frp"
// Disable quic-go's receive buffer warning.
os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true")
// Disable quic-go's ECN support by default. It may cause issues on certain operating systems.
if os.Getenv("QUIC_GO_DISABLE_ECN") == "" {
os.Setenv("QUIC_GO_DISABLE_ECN", "true")
}
} }
type cancelErr struct { type cancelErr struct {
@@ -174,9 +181,9 @@ func (svr *Service) Run(ctx context.Context) error {
if svr.webServer != nil { if svr.webServer != nil {
go func() { go func() {
log.Info("admin server listen on %s", svr.webServer.Address()) log.Infof("admin server listen on %s", svr.webServer.Address())
if err := svr.webServer.Run(); err != nil { if err := svr.webServer.Run(); err != nil {
log.Warn("admin server exit with error: %v", err) log.Warnf("admin server exit with error: %v", err)
} }
}() }()
} }
@@ -269,14 +276,14 @@ func (svr *Service) login() (conn net.Conn, connector Connector, err error) {
if loginRespMsg.Error != "" { if loginRespMsg.Error != "" {
err = fmt.Errorf("%s", loginRespMsg.Error) err = fmt.Errorf("%s", loginRespMsg.Error)
xl.Error("%s", loginRespMsg.Error) xl.Errorf("%s", loginRespMsg.Error)
return return
} }
svr.runID = loginRespMsg.RunID svr.runID = loginRespMsg.RunID
xl.AddPrefix(xlog.LogPrefix{Name: "runID", Value: svr.runID}) xl.AddPrefix(xlog.LogPrefix{Name: "runID", Value: svr.runID})
xl.Info("login to server success, get run id [%s]", loginRespMsg.RunID) xl.Infof("login to server success, get run id [%s]", loginRespMsg.RunID)
return return
} }
@@ -284,10 +291,10 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE
xl := xlog.FromContextSafe(svr.ctx) xl := xlog.FromContextSafe(svr.ctx)
loginFunc := func() (bool, error) { loginFunc := func() (bool, error) {
xl.Info("try to connect to server...") xl.Infof("try to connect to server...")
conn, connector, err := svr.login() conn, connector, err := svr.login()
if err != nil { if err != nil {
xl.Warn("connect to server error: %v", err) xl.Warnf("connect to server error: %v", err)
if firstLoginExit { if firstLoginExit {
svr.cancel(cancelErr{Err: err}) svr.cancel(cancelErr{Err: err})
} }
@@ -313,7 +320,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE
ctl, err := NewControl(svr.ctx, sessionCtx) ctl, err := NewControl(svr.ctx, sessionCtx)
if err != nil { if err != nil {
conn.Close() conn.Close()
xl.Error("NewControl error: %v", err) xl.Errorf("NewControl error: %v", err)
return false, err return false, err
} }
ctl.SetInWorkConnCallback(svr.handleWorkConnCb) ctl.SetInWorkConnCallback(svr.handleWorkConnCb)
@@ -373,18 +380,31 @@ func (svr *Service) stop() {
} }
} }
// TODO(fatedier): Use StatusExporter to provide query interfaces instead of directly using methods from the Service. func (svr *Service) getProxyStatus(name string) (*proxy.WorkingStatus, bool) {
func (svr *Service) GetProxyStatus(name string) (*proxy.WorkingStatus, error) {
svr.ctlMu.RLock() svr.ctlMu.RLock()
ctl := svr.ctl ctl := svr.ctl
svr.ctlMu.RUnlock() svr.ctlMu.RUnlock()
if ctl == nil { if ctl == nil {
return nil, fmt.Errorf("control is not running") return nil, false
} }
ws, ok := ctl.pm.GetProxyStatus(name) return ctl.pm.GetProxyStatus(name)
if !ok { }
return nil, fmt.Errorf("proxy [%s] is not found", name)
} func (svr *Service) StatusExporter() StatusExporter {
return ws, nil return &statusExporterImpl{
getProxyStatusFunc: svr.getProxyStatus,
}
}
type StatusExporter interface {
GetProxyStatus(name string) (*proxy.WorkingStatus, bool)
}
type statusExporterImpl struct {
getProxyStatusFunc func(name string) (*proxy.WorkingStatus, bool)
}
func (s *statusExporterImpl) GetProxyStatus(name string) (*proxy.WorkingStatus, bool) {
return s.getProxyStatusFunc(name)
} }

View File

@@ -56,7 +56,7 @@ func (sv *STCPVisitor) worker() {
for { for {
conn, err := sv.l.Accept() conn, err := sv.l.Accept()
if err != nil { if err != nil {
xl.Warn("stcp local listener closed") xl.Warnf("stcp local listener closed")
return return
} }
go sv.handleConn(conn) go sv.handleConn(conn)
@@ -68,7 +68,7 @@ func (sv *STCPVisitor) internalConnWorker() {
for { for {
conn, err := sv.internalLn.Accept() conn, err := sv.internalLn.Accept()
if err != nil { if err != nil {
xl.Warn("stcp internal listener closed") xl.Warnf("stcp internal listener closed")
return return
} }
go sv.handleConn(conn) go sv.handleConn(conn)
@@ -79,7 +79,7 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
xl := xlog.FromContextSafe(sv.ctx) xl := xlog.FromContextSafe(sv.ctx)
defer userConn.Close() defer userConn.Close()
xl.Debug("get a new stcp user connection") xl.Debugf("get a new stcp user connection")
visitorConn, err := sv.helper.ConnectServer() visitorConn, err := sv.helper.ConnectServer()
if err != nil { if err != nil {
return return
@@ -97,7 +97,7 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
} }
err = msg.WriteMsg(visitorConn, newVisitorConnMsg) err = msg.WriteMsg(visitorConn, newVisitorConnMsg)
if err != nil { if err != nil {
xl.Warn("send newVisitorConnMsg to server error: %v", err) xl.Warnf("send newVisitorConnMsg to server error: %v", err)
return return
} }
@@ -105,13 +105,13 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
_ = visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second)) _ = visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
err = msg.ReadMsgInto(visitorConn, &newVisitorConnRespMsg) err = msg.ReadMsgInto(visitorConn, &newVisitorConnRespMsg)
if err != nil { if err != nil {
xl.Warn("get newVisitorConnRespMsg error: %v", err) xl.Warnf("get newVisitorConnRespMsg error: %v", err)
return return
} }
_ = visitorConn.SetReadDeadline(time.Time{}) _ = visitorConn.SetReadDeadline(time.Time{})
if newVisitorConnRespMsg.Error != "" { if newVisitorConnRespMsg.Error != "" {
xl.Warn("start new visitor connection error: %s", newVisitorConnRespMsg.Error) xl.Warnf("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
return return
} }
@@ -120,7 +120,7 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
if sv.cfg.Transport.UseEncryption { if sv.cfg.Transport.UseEncryption {
remote, err = libio.WithEncryption(remote, []byte(sv.cfg.SecretKey)) remote, err = libio.WithEncryption(remote, []byte(sv.cfg.SecretKey))
if err != nil { if err != nil {
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }

View File

@@ -62,7 +62,7 @@ func (sv *SUDPVisitor) Run() (err error) {
sv.sendCh = make(chan *msg.UDPPacket, 1024) sv.sendCh = make(chan *msg.UDPPacket, 1024)
sv.readCh = make(chan *msg.UDPPacket, 1024) sv.readCh = make(chan *msg.UDPPacket, 1024)
xl.Info("sudp start to work, listen on %s", addr) xl.Infof("sudp start to work, listen on %s", addr)
go sv.dispatcher() go sv.dispatcher()
go udp.ForwardUserConn(sv.udpConn, sv.readCh, sv.sendCh, int(sv.clientCfg.UDPPacketSize)) go udp.ForwardUserConn(sv.udpConn, sv.readCh, sv.sendCh, int(sv.clientCfg.UDPPacketSize))
@@ -84,17 +84,17 @@ func (sv *SUDPVisitor) dispatcher() {
select { select {
case firstPacket = <-sv.sendCh: case firstPacket = <-sv.sendCh:
if firstPacket == nil { if firstPacket == nil {
xl.Info("frpc sudp visitor proxy is closed") xl.Infof("frpc sudp visitor proxy is closed")
return return
} }
case <-sv.checkCloseCh: case <-sv.checkCloseCh:
xl.Info("frpc sudp visitor proxy is closed") xl.Infof("frpc sudp visitor proxy is closed")
return return
} }
visitorConn, err = sv.getNewVisitorConn() visitorConn, err = sv.getNewVisitorConn()
if err != nil { if err != nil {
xl.Warn("newVisitorConn to frps error: %v, try to reconnect", err) xl.Warnf("newVisitorConn to frps error: %v, try to reconnect", err)
continue continue
} }
@@ -111,7 +111,7 @@ func (sv *SUDPVisitor) dispatcher() {
func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) { func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
xl := xlog.FromContextSafe(sv.ctx) xl := xlog.FromContextSafe(sv.ctx)
xl.Debug("starting sudp proxy worker") xl.Debugf("starting sudp proxy worker")
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(2) wg.Add(2)
@@ -134,21 +134,21 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
// frpc will send heartbeat in workConn to frpc visitor for keeping alive // frpc will send heartbeat in workConn to frpc visitor for keeping alive
_ = conn.SetReadDeadline(time.Now().Add(60 * time.Second)) _ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil { if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil {
xl.Warn("read from workconn for user udp conn error: %v", errRet) xl.Warnf("read from workconn for user udp conn error: %v", errRet)
return return
} }
_ = conn.SetReadDeadline(time.Time{}) _ = conn.SetReadDeadline(time.Time{})
switch m := rawMsg.(type) { switch m := rawMsg.(type) {
case *msg.Ping: case *msg.Ping:
xl.Debug("frpc visitor get ping message from frpc") xl.Debugf("frpc visitor get ping message from frpc")
continue continue
case *msg.UDPPacket: case *msg.UDPPacket:
if errRet := errors.PanicToError(func() { if errRet := errors.PanicToError(func() {
sv.readCh <- m sv.readCh <- m
xl.Trace("frpc visitor get udp packet from workConn: %s", m.Content) xl.Tracef("frpc visitor get udp packet from workConn: %s", m.Content)
}); errRet != nil { }); errRet != nil {
xl.Info("reader goroutine for udp work connection closed") xl.Infof("reader goroutine for udp work connection closed")
return return
} }
} }
@@ -165,25 +165,25 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
var errRet error var errRet error
if firstPacket != nil { if firstPacket != nil {
if errRet = msg.WriteMsg(conn, firstPacket); errRet != nil { if errRet = msg.WriteMsg(conn, firstPacket); errRet != nil {
xl.Warn("sender goroutine for udp work connection closed: %v", errRet) xl.Warnf("sender goroutine for udp work connection closed: %v", errRet)
return return
} }
xl.Trace("send udp package to workConn: %s", firstPacket.Content) xl.Tracef("send udp package to workConn: %s", firstPacket.Content)
} }
for { for {
select { select {
case udpMsg, ok := <-sv.sendCh: case udpMsg, ok := <-sv.sendCh:
if !ok { if !ok {
xl.Info("sender goroutine for udp work connection closed") xl.Infof("sender goroutine for udp work connection closed")
return return
} }
if errRet = msg.WriteMsg(conn, udpMsg); errRet != nil { if errRet = msg.WriteMsg(conn, udpMsg); errRet != nil {
xl.Warn("sender goroutine for udp work connection closed: %v", errRet) xl.Warnf("sender goroutine for udp work connection closed: %v", errRet)
return return
} }
xl.Trace("send udp package to workConn: %s", udpMsg.Content) xl.Tracef("send udp package to workConn: %s", udpMsg.Content)
case <-closeCh: case <-closeCh:
return return
} }
@@ -194,7 +194,7 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
go workConnSenderFn(workConn) go workConnSenderFn(workConn)
wg.Wait() wg.Wait()
xl.Info("sudp worker is closed") xl.Infof("sudp worker is closed")
} }
func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) { func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) {
@@ -235,7 +235,7 @@ func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) {
if sv.cfg.Transport.UseEncryption { if sv.cfg.Transport.UseEncryption {
remote, err = libio.WithEncryption(remote, []byte(sv.cfg.SecretKey)) remote, err = libio.WithEncryption(remote, []byte(sv.cfg.SecretKey))
if err != nil { if err != nil {
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return nil, err return nil, err
} }
} }

View File

@@ -79,14 +79,14 @@ func (vm *Manager) keepVisitorsRunning() {
for { for {
select { select {
case <-vm.stopCh: case <-vm.stopCh:
xl.Trace("gracefully shutdown visitor manager") xl.Tracef("gracefully shutdown visitor manager")
return return
case <-ticker.C: case <-ticker.C:
vm.mu.Lock() vm.mu.Lock()
for _, cfg := range vm.cfgs { for _, cfg := range vm.cfgs {
name := cfg.GetBaseConfig().Name name := cfg.GetBaseConfig().Name
if _, exist := vm.visitors[name]; !exist { if _, exist := vm.visitors[name]; !exist {
xl.Info("try to start visitor [%s]", name) xl.Infof("try to start visitor [%s]", name)
_ = vm.startVisitor(cfg) _ = vm.startVisitor(cfg)
} }
} }
@@ -115,10 +115,10 @@ func (vm *Manager) startVisitor(cfg v1.VisitorConfigurer) (err error) {
visitor := NewVisitor(vm.ctx, cfg, vm.clientCfg, vm.helper) visitor := NewVisitor(vm.ctx, cfg, vm.clientCfg, vm.helper)
err = visitor.Run() err = visitor.Run()
if err != nil { if err != nil {
xl.Warn("start error: %v", err) xl.Warnf("start error: %v", err)
} else { } else {
vm.visitors[name] = visitor vm.visitors[name] = visitor
xl.Info("start visitor success") xl.Infof("start visitor success")
} }
return return
} }
@@ -156,7 +156,7 @@ func (vm *Manager) UpdateAll(cfgs []v1.VisitorConfigurer) {
} }
} }
if len(delNames) > 0 { if len(delNames) > 0 {
xl.Info("visitor removed: %v", delNames) xl.Infof("visitor removed: %v", delNames)
} }
addNames := make([]string, 0) addNames := make([]string, 0)
@@ -169,7 +169,7 @@ func (vm *Manager) UpdateAll(cfgs []v1.VisitorConfigurer) {
} }
} }
if len(addNames) > 0 { if len(addNames) > 0 {
xl.Info("visitor added: %v", addNames) xl.Infof("visitor added: %v", addNames)
} }
} }

View File

@@ -93,7 +93,7 @@ func (sv *XTCPVisitor) worker() {
for { for {
conn, err := sv.l.Accept() conn, err := sv.l.Accept()
if err != nil { if err != nil {
xl.Warn("xtcp local listener closed") xl.Warnf("xtcp local listener closed")
return return
} }
go sv.handleConn(conn) go sv.handleConn(conn)
@@ -105,7 +105,7 @@ func (sv *XTCPVisitor) internalConnWorker() {
for { for {
conn, err := sv.internalLn.Accept() conn, err := sv.internalLn.Accept()
if err != nil { if err != nil {
xl.Warn("xtcp internal listener closed") xl.Warnf("xtcp internal listener closed")
return return
} }
go sv.handleConn(conn) go sv.handleConn(conn)
@@ -140,14 +140,14 @@ func (sv *XTCPVisitor) keepTunnelOpenWorker() {
case <-sv.ctx.Done(): case <-sv.ctx.Done():
return return
case <-ticker.C: case <-ticker.C:
xl.Debug("keepTunnelOpenWorker try to check tunnel...") xl.Debugf("keepTunnelOpenWorker try to check tunnel...")
conn, err := sv.getTunnelConn() conn, err := sv.getTunnelConn()
if err != nil { if err != nil {
xl.Warn("keepTunnelOpenWorker get tunnel connection error: %v", err) xl.Warnf("keepTunnelOpenWorker get tunnel connection error: %v", err)
_ = sv.retryLimiter.Wait(sv.ctx) _ = sv.retryLimiter.Wait(sv.ctx)
continue continue
} }
xl.Debug("keepTunnelOpenWorker check success") xl.Debugf("keepTunnelOpenWorker check success")
if conn != nil { if conn != nil {
conn.Close() conn.Close()
} }
@@ -164,7 +164,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
} }
}() }()
xl.Debug("get a new xtcp user connection") xl.Debugf("get a new xtcp user connection")
// Open a tunnel connection to the server. If there is already a successful hole-punching connection, // Open a tunnel connection to the server. If there is already a successful hole-punching connection,
// it will be reused. Otherwise, it will block and wait for a successful hole-punching connection until timeout. // it will be reused. Otherwise, it will block and wait for a successful hole-punching connection until timeout.
@@ -176,15 +176,15 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
} }
tunnelConn, err := sv.openTunnel(ctx) tunnelConn, err := sv.openTunnel(ctx)
if err != nil { if err != nil {
xl.Error("open tunnel error: %v", err) xl.Errorf("open tunnel error: %v", err)
// no fallback, just return // no fallback, just return
if sv.cfg.FallbackTo == "" { if sv.cfg.FallbackTo == "" {
return return
} }
xl.Debug("try to transfer connection to visitor: %s", sv.cfg.FallbackTo) xl.Debugf("try to transfer connection to visitor: %s", sv.cfg.FallbackTo)
if err := sv.helper.TransferConn(sv.cfg.FallbackTo, userConn); err != nil { if err := sv.helper.TransferConn(sv.cfg.FallbackTo, userConn); err != nil {
xl.Error("transfer connection to visitor %s error: %v", sv.cfg.FallbackTo, err) xl.Errorf("transfer connection to visitor %s error: %v", sv.cfg.FallbackTo, err)
return return
} }
isConnTrasfered = true isConnTrasfered = true
@@ -195,7 +195,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
if sv.cfg.Transport.UseEncryption { if sv.cfg.Transport.UseEncryption {
muxConnRWCloser, err = libio.WithEncryption(muxConnRWCloser, []byte(sv.cfg.SecretKey)) muxConnRWCloser, err = libio.WithEncryption(muxConnRWCloser, []byte(sv.cfg.SecretKey))
if err != nil { if err != nil {
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }
@@ -206,9 +206,9 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
} }
_, _, errs := libio.Join(userConn, muxConnRWCloser) _, _, errs := libio.Join(userConn, muxConnRWCloser)
xl.Debug("join connections closed") xl.Debugf("join connections closed")
if len(errs) > 0 { if len(errs) > 0 {
xl.Trace("join connections errors: %v", errs) xl.Tracef("join connections errors: %v", errs)
} }
} }
@@ -239,7 +239,7 @@ func (sv *XTCPVisitor) openTunnel(ctx context.Context) (conn net.Conn, err error
if err != nil { if err != nil {
if err != ErrNoTunnelSession { if err != ErrNoTunnelSession {
xl.Warn("get tunnel connection error: %v", err) xl.Warnf("get tunnel connection error: %v", err)
} }
continue continue
} }
@@ -268,19 +268,19 @@ func (sv *XTCPVisitor) getTunnelConn() (net.Conn, error) {
// 4. Create a tunnel session using an underlying UDP connection. // 4. Create a tunnel session using an underlying UDP connection.
func (sv *XTCPVisitor) makeNatHole() { func (sv *XTCPVisitor) makeNatHole() {
xl := xlog.FromContextSafe(sv.ctx) xl := xlog.FromContextSafe(sv.ctx)
xl.Trace("makeNatHole start") xl.Tracef("makeNatHole start")
if err := nathole.PreCheck(sv.ctx, sv.helper.MsgTransporter(), sv.cfg.ServerName, 5*time.Second); err != nil { if err := nathole.PreCheck(sv.ctx, sv.helper.MsgTransporter(), sv.cfg.ServerName, 5*time.Second); err != nil {
xl.Warn("nathole precheck error: %v", err) xl.Warnf("nathole precheck error: %v", err)
return return
} }
xl.Trace("nathole prepare start") xl.Tracef("nathole prepare start")
prepareResult, err := nathole.Prepare([]string{sv.clientCfg.NatHoleSTUNServer}) prepareResult, err := nathole.Prepare([]string{sv.clientCfg.NatHoleSTUNServer})
if err != nil { if err != nil {
xl.Warn("nathole prepare error: %v", err) xl.Warnf("nathole prepare error: %v", err)
return return
} }
xl.Info("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v", xl.Infof("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v",
prepareResult.NatType, prepareResult.Behavior, prepareResult.Addrs, prepareResult.AssistedAddrs) prepareResult.NatType, prepareResult.Behavior, prepareResult.Addrs, prepareResult.AssistedAddrs)
listenConn := prepareResult.ListenConn listenConn := prepareResult.ListenConn
@@ -298,30 +298,30 @@ func (sv *XTCPVisitor) makeNatHole() {
AssistedAddrs: prepareResult.AssistedAddrs, AssistedAddrs: prepareResult.AssistedAddrs,
} }
xl.Trace("nathole exchange info start") xl.Tracef("nathole exchange info start")
natHoleRespMsg, err := nathole.ExchangeInfo(sv.ctx, sv.helper.MsgTransporter(), transactionID, natHoleVisitorMsg, 5*time.Second) natHoleRespMsg, err := nathole.ExchangeInfo(sv.ctx, sv.helper.MsgTransporter(), transactionID, natHoleVisitorMsg, 5*time.Second)
if err != nil { if err != nil {
listenConn.Close() listenConn.Close()
xl.Warn("nathole exchange info error: %v", err) xl.Warnf("nathole exchange info error: %v", err)
return return
} }
xl.Info("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v", xl.Infof("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v",
natHoleRespMsg.Sid, natHoleRespMsg.Protocol, natHoleRespMsg.CandidateAddrs, natHoleRespMsg.Sid, natHoleRespMsg.Protocol, natHoleRespMsg.CandidateAddrs,
natHoleRespMsg.AssistedAddrs, natHoleRespMsg.DetectBehavior) natHoleRespMsg.AssistedAddrs, natHoleRespMsg.DetectBehavior)
newListenConn, raddr, err := nathole.MakeHole(sv.ctx, listenConn, natHoleRespMsg, []byte(sv.cfg.SecretKey)) newListenConn, raddr, err := nathole.MakeHole(sv.ctx, listenConn, natHoleRespMsg, []byte(sv.cfg.SecretKey))
if err != nil { if err != nil {
listenConn.Close() listenConn.Close()
xl.Warn("make hole error: %v", err) xl.Warnf("make hole error: %v", err)
return return
} }
listenConn = newListenConn listenConn = newListenConn
xl.Info("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr) xl.Infof("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr)
if err := sv.session.Init(listenConn, raddr); err != nil { if err := sv.session.Init(listenConn, raddr); err != nil {
listenConn.Close() listenConn.Close()
xl.Warn("init tunnel session error: %v", err) xl.Warnf("init tunnel session error: %v", err)
return return
} }
} }

View File

@@ -17,8 +17,10 @@ package main
import ( import (
_ "github.com/fatedier/frp/assets/frpc" _ "github.com/fatedier/frp/assets/frpc"
"github.com/fatedier/frp/cmd/frpc/sub" "github.com/fatedier/frp/cmd/frpc/sub"
"github.com/fatedier/frp/pkg/util/system"
) )
func main() { func main() {
system.EnableCompatibilityMode()
sub.Execute() sub.Execute()
} }

View File

@@ -17,8 +17,8 @@ package sub
import ( import (
"fmt" "fmt"
"os" "os"
"slices"
"github.com/samber/lo"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
@@ -55,7 +55,7 @@ func init() {
config.RegisterProxyFlags(cmd, c) config.RegisterProxyFlags(cmd, c)
// add sub command for visitor // add sub command for visitor
if lo.Contains(visitorTypes, v1.VisitorType(typ)) { if slices.Contains(visitorTypes, v1.VisitorType(typ)) {
vc := v1.NewVisitorConfigurerByType(v1.VisitorType(typ)) vc := v1.NewVisitorConfigurerByType(v1.VisitorType(typ))
if vc == nil { if vc == nil {
panic("visitor type: " + typ + " not support") panic("visitor type: " + typ + " not support")

View File

@@ -46,7 +46,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "./frpc.ini", "config file of frpc") rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "./frpc.ini", "config file of frpc")
rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory") rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory")
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc") rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", false, "strict config parsing mode, unknown fields will cause an error") rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors")
} }
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
@@ -136,11 +136,11 @@ func startService(
visitorCfgs []v1.VisitorConfigurer, visitorCfgs []v1.VisitorConfigurer,
cfgFile string, cfgFile string,
) error { ) error {
log.InitLog(cfg.Log.To, cfg.Log.Level, cfg.Log.MaxDays, cfg.Log.DisablePrintColor) log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
if cfgFile != "" { if cfgFile != "" {
log.Info("start frpc service for config file [%s]", cfgFile) log.Infof("start frpc service for config file [%s]", cfgFile)
defer log.Info("frpc service for config file [%s] stopped", cfgFile) defer log.Infof("frpc service for config file [%s] stopped", cfgFile)
} }
svr, err := client.NewService(client.ServiceOptions{ svr, err := client.NewService(client.ServiceOptions{
Common: cfg, Common: cfg,

View File

@@ -15,13 +15,12 @@
package main package main
import ( import (
"github.com/fatedier/golib/crypto"
_ "github.com/fatedier/frp/assets/frps" _ "github.com/fatedier/frp/assets/frps"
_ "github.com/fatedier/frp/pkg/metrics" _ "github.com/fatedier/frp/pkg/metrics"
"github.com/fatedier/frp/pkg/util/system"
) )
func main() { func main() {
crypto.DefaultSalt = "frp" system.EnableCompatibilityMode()
Execute() Execute()
} }

View File

@@ -40,7 +40,7 @@ var (
func init() { func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file of frps") rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file of frps")
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frps") rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frps")
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", false, "strict config parsing mode, unknown fields will cause error") rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause errors")
config.RegisterServerConfigFlags(rootCmd, &serverCfg) config.RegisterServerConfigFlags(rootCmd, &serverCfg)
} }
@@ -99,19 +99,19 @@ func Execute() {
} }
func runServer(cfg *v1.ServerConfig) (err error) { func runServer(cfg *v1.ServerConfig) (err error) {
log.InitLog(cfg.Log.To, cfg.Log.Level, cfg.Log.MaxDays, cfg.Log.DisablePrintColor) log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
if cfgFile != "" { if cfgFile != "" {
log.Info("frps uses config file: %s", cfgFile) log.Infof("frps uses config file: %s", cfgFile)
} else { } else {
log.Info("frps uses command line arguments for config") log.Infof("frps uses command line arguments for config")
} }
svr, err := server.NewService(cfg) svr, err := server.NewService(cfg)
if err != nil { if err != nil {
return err return err
} }
log.Info("frps started successfully") log.Infof("frps started successfully")
svr.Run(context.Background()) svr.Run(context.Background())
return return
} }

View File

@@ -76,7 +76,7 @@ transport.poolCount = 5
# Specify keep alive interval for tcp mux. # Specify keep alive interval for tcp mux.
# only valid if tcpMux is enabled. # only valid if tcpMux is enabled.
# transport.tcpMuxKeepaliveInterval = 60 # transport.tcpMuxKeepaliveInterval = 30
# Communication protocol used to connect to server # Communication protocol used to connect to server
# supports tcp, kcp, quic, websocket and wss now, default is tcp # supports tcp, kcp, quic, websocket and wss now, default is tcp
@@ -209,6 +209,7 @@ locations = ["/", "/pic"]
# routeByHTTPUser = abc # routeByHTTPUser = abc
hostHeaderRewrite = "example.com" hostHeaderRewrite = "example.com"
requestHeaders.set.x-from-where = "frp" requestHeaders.set.x-from-where = "frp"
responseHeaders.set.foo = "bar"
healthCheck.type = "http" healthCheck.type = "http"
# frpc will send a GET http request '/status' to local http service # frpc will send a GET http request '/status' to local http service
# http service is alive when it return 2xx http response code # http service is alive when it return 2xx http response code
@@ -216,6 +217,10 @@ healthCheck.path = "/status"
healthCheck.intervalSeconds = 10 healthCheck.intervalSeconds = 10
healthCheck.maxFailed = 3 healthCheck.maxFailed = 3
healthCheck.timeoutSeconds = 3 healthCheck.timeoutSeconds = 3
# set health check headers
healthCheck.httpHeaders=[
{ name = "x-from-where", value = "frp" }
]
[[proxies]] [[proxies]]
name = "web02" name = "web02"

View File

@@ -34,7 +34,7 @@ transport.maxPoolCount = 5
# Specify keep alive interval for tcp mux. # Specify keep alive interval for tcp mux.
# only valid if tcpMux is true. # only valid if tcpMux is true.
# transport.tcpMuxKeepaliveInterval = 60 # transport.tcpMuxKeepaliveInterval = 30
# tcpKeepalive specifies the interval between keep-alive probes for an active network connection between frpc and frps. # tcpKeepalive specifies the interval between keep-alive probes for an active network connection between frpc and frps.
# If negative, keep-alive probes are disabled. # If negative, keep-alive probes are disabled.

BIN
doc/pic/sponsor_daytona.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

82
go.mod
View File

@@ -1,83 +1,81 @@
module github.com/fatedier/frp module github.com/fatedier/frp
go 1.21 go 1.22
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/v3 v3.6.0 github.com/coreos/go-oidc/v3 v3.10.0
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb github.com/fatedier/golib v0.5.0
github.com/fatedier/golib v0.1.1-0.20230725122706-dcbaee8eef40 github.com/google/uuid v1.6.0
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible github.com/gorilla/mux v1.8.1
github.com/google/uuid v1.3.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/v2 v2.11.0 github.com/onsi/ginkgo/v2 v2.17.1
github.com/onsi/gomega v1.27.8 github.com/onsi/gomega v1.32.0
github.com/pelletier/go-toml/v2 v2.1.0 github.com/pelletier/go-toml/v2 v2.2.0
github.com/pion/stun/v2 v2.0.0 github.com/pion/stun/v2 v2.0.0
github.com/pires/go-proxyproto v0.7.0 github.com/pires/go-proxyproto v0.7.0
github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_golang v1.19.0
github.com/quic-go/quic-go v0.41.0 github.com/quic-go/quic-go v0.42.0
github.com/rodaine/table v1.1.0 github.com/rodaine/table v1.2.0
github.com/samber/lo v1.38.1 github.com/samber/lo v1.39.0
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.17.1 github.com/tidwall/gjson v1.17.1
golang.org/x/crypto v0.17.0 github.com/xtaci/kcp-go/v5 v5.6.8
golang.org/x/net v0.17.0 golang.org/x/crypto v0.22.0
golang.org/x/oauth2 v0.10.0 golang.org/x/net v0.24.0
golang.org/x/sync v0.3.0 golang.org/x/oauth2 v0.16.0
golang.org/x/time v0.3.0 golang.org/x/sync v0.6.0
golang.org/x/time v0.5.0
gopkg.in/ini.v1 v1.67.0 gopkg.in/ini.v1 v1.67.0
k8s.io/apimachinery v0.27.4 k8s.io/apimachinery v0.28.8
k8s.io/client-go v0.27.4 k8s.io/client-go v0.28.8
) )
require ( require (
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.6 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/klauspost/reedsolomon v1.9.15 // indirect github.com/klauspost/reedsolomon v1.12.0 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/logging v0.2.2 // indirect github.com/pion/logging v0.2.2 // indirect
github.com/pion/transport/v2 v2.2.1 // indirect github.com/pion/transport/v2 v2.2.1 // indirect
github.com/pion/transport/v3 v3.0.1 // indirect github.com/pion/transport/v3 v3.0.1 // 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/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect github.com/templexxx/cpu v0.1.0 // indirect
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect github.com/templexxx/xorsimd v0.4.2 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/pretty v1.2.0 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect
go.uber.org/mock v0.3.0 // indirect go.uber.org/mock v0.4.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.11.0 // indirect golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.9.3 // indirect golang.org/x/tools v0.17.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/yaml v1.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect
) )

179
go.sum
View File

@@ -1,6 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
@@ -14,8 +14,8 @@ 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/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -24,27 +24,21 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/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/golib v0.5.0 h1:hNcH7hgfIFqVWbP+YojCCAj4eO94pPf4dEF8lmq2jWs=
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk= github.com/fatedier/golib v0.5.0/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ=
github.com/fatedier/golib v0.1.1-0.20230725122706-dcbaee8eef40 h1:BVdpWT6viE/mpuRa6txNyRNjtHa1Efrii9Du6/gHfJ0=
github.com/fatedier/golib v0.1.1-0.20230725122706-dcbaee8eef40/go.mod h1:Lmi9U4VfvdRvonSMh1FgXVy1hCXycVyJk4E9ktokknE=
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo=
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -52,47 +46,45 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
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.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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.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.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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= 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/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/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.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/reedsolomon v1.9.15 h1:g2erWKD2M6rgnPf89fCji6jNlhMKMdXcuNHMW1SYCIo= github.com/klauspost/reedsolomon v1.12.0 h1:I5FEp3xSwVCcEh3F5A7dofEfhXdF/bWhQWPH+XwBFno=
github.com/klauspost/reedsolomon v1.9.15/go.mod h1:eqPAcE7xar5CIzcdfwydOEdcmchAKAP/qs14y4GCBOk= github.com/klauspost/reedsolomon v1.12.0/go.mod h1:EPLZJeh4l27pUGC3aXOjheaoh1I9yut7xTURiW3LQ9Y=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
@@ -109,24 +101,26 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rodaine/table v1.1.0 h1:/fUlCSdjamMY8VifdQRIu3VWZXYLY7QHFkVorS8NTr4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rodaine/table v1.1.0/go.mod h1:Qu3q5wi1jTQD6B6HsP6szie/S4w1QUQ8pq22pz9iL8g= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rodaine/table v1.2.0 h1:38HEnwK4mKSHQJIkavVj+bst1TEY7j9zhLMWu4QJrMA=
github.com/rodaine/table v1.2.0/go.mod h1:wejb/q/Yd4T/SVmBSRMr7GCq3KlcZp3gyNYdLSBhkaE=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -134,16 +128,18 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI= github.com/templexxx/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI=
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -152,20 +148,21 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/xtaci/kcp-go/v5 v5.6.8 h1:jlI/0jAyjoOjT/SaGB58s4bQMJiNS41A2RKzR6TMWeI=
github.com/xtaci/kcp-go/v5 v5.6.8/go.mod h1:oE9j2NVqAkuKO5o8ByKGch3vgVX3BNf8zqP8JiGq0bM=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
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-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= 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/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
@@ -174,14 +171,13 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -190,19 +186,18 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
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.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -216,27 +211,27 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/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.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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -245,14 +240,14 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -267,8 +262,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-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=
@@ -281,12 +276,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= k8s.io/apimachinery v0.28.8 h1:hi/nrxHwk4QLV+W/SHve1bypTE59HCDorLY1stBIxKQ=
k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/apimachinery v0.28.8/go.mod h1:cBnwIM3fXoRo28SqbV/Ihxf/iviw85KyXOrzxvZQ83U=
k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= k8s.io/client-go v0.28.8 h1:TE59Tjd87WKvS2FPBTfIKLFX0nQJ4SSHsnDo5IHjgOw=
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= k8s.io/client-go v0.28.8/go.mod h1:uDVQ/rPzWpWIy40c6lZ4mUwaEvRWGnpoqSO4FM65P3o=
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=

View File

@@ -6,7 +6,7 @@ ROOT=$(unset CDPATH && cd "$(dirname "$SCRIPT")/.." && pwd)
ginkgo_command=$(which ginkgo 2>/dev/null) ginkgo_command=$(which ginkgo 2>/dev/null)
if [ -z "$ginkgo_command" ]; then if [ -z "$ginkgo_command" ]; then
echo "ginkgo not found, try to install..." echo "ginkgo not found, try to install..."
go install github.com/onsi/ginkgo/v2/ginkgo@v2.11.0 go install github.com/onsi/ginkgo/v2/ginkgo@v2.17.1
fi fi
debug=false debug=false

View File

@@ -1,3 +1,6 @@
#!/bin/sh
set -e
# compile for version # compile for version
make make
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@@ -14,50 +17,57 @@ make -f ./Makefile.cross-compiles
rm -rf ./release/packages rm -rf ./release/packages
mkdir -p ./release/packages mkdir -p ./release/packages
os_all='linux windows darwin freebsd' os_all='linux windows darwin freebsd android'
arch_all='386 amd64 arm arm64 mips64 mips64le mips mipsle riscv64' arch_all='386 amd64 arm arm64 mips64 mips64le mips mipsle riscv64'
extra_all='_ hf'
cd ./release cd ./release
for os in $os_all; do for os in $os_all; do
for arch in $arch_all; do for arch in $arch_all; do
frp_dir_name="frp_${frp_version}_${os}_${arch}" for extra in $extra_all; do
frp_path="./packages/frp_${frp_version}_${os}_${arch}" suffix="${os}_${arch}"
if [ "x${extra}" != x"_" ]; then
suffix="${os}_${arch}_${extra}"
fi
frp_dir_name="frp_${frp_version}_${suffix}"
frp_path="./packages/frp_${frp_version}_${suffix}"
if [ "x${os}" = x"windows" ]; then if [ "x${os}" = x"windows" ]; then
if [ ! -f "./frpc_${os}_${arch}.exe" ]; then if [ ! -f "./frpc_${os}_${arch}.exe" ]; then
continue continue
fi fi
if [ ! -f "./frps_${os}_${arch}.exe" ]; then if [ ! -f "./frps_${os}_${arch}.exe" ]; then
continue continue
fi fi
mkdir ${frp_path} mkdir ${frp_path}
mv ./frpc_${os}_${arch}.exe ${frp_path}/frpc.exe mv ./frpc_${os}_${arch}.exe ${frp_path}/frpc.exe
mv ./frps_${os}_${arch}.exe ${frp_path}/frps.exe mv ./frps_${os}_${arch}.exe ${frp_path}/frps.exe
else else
if [ ! -f "./frpc_${os}_${arch}" ]; then if [ ! -f "./frpc_${suffix}" ]; then
continue continue
fi fi
if [ ! -f "./frps_${os}_${arch}" ]; then if [ ! -f "./frps_${suffix}" ]; then
continue continue
fi fi
mkdir ${frp_path} mkdir ${frp_path}
mv ./frpc_${os}_${arch} ${frp_path}/frpc mv ./frpc_${suffix} ${frp_path}/frpc
mv ./frps_${os}_${arch} ${frp_path}/frps mv ./frps_${suffix} ${frp_path}/frps
fi fi
cp ../LICENSE ${frp_path} cp ../LICENSE ${frp_path}
cp -f ../conf/frpc.toml ${frp_path} cp -f ../conf/frpc.toml ${frp_path}
cp -f ../conf/frps.toml ${frp_path} cp -f ../conf/frps.toml ${frp_path}
# packages # packages
cd ./packages cd ./packages
if [ "x${os}" = x"windows" ]; then if [ "x${os}" = x"windows" ]; then
zip -rq ${frp_dir_name}.zip ${frp_dir_name} zip -rq ${frp_dir_name}.zip ${frp_dir_name}
else else
tar -zcf ${frp_dir_name}.tar.gz ${frp_dir_name} tar -zcf ${frp_dir_name}.tar.gz ${frp_dir_name}
fi fi
cd .. cd ..
rm -rf ${frp_path} rm -rf ${frp_path}
done
done done
done done

View File

@@ -17,9 +17,9 @@ package auth
import ( import (
"context" "context"
"fmt" "fmt"
"slices"
"github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-oidc/v3/oidc"
"github.com/samber/lo"
"golang.org/x/oauth2/clientcredentials" "golang.org/x/oauth2/clientcredentials"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
@@ -70,7 +70,7 @@ func (auth *OidcAuthProvider) SetLogin(loginMsg *msg.Login) (err error) {
} }
func (auth *OidcAuthProvider) SetPing(pingMsg *msg.Ping) (err error) { func (auth *OidcAuthProvider) SetPing(pingMsg *msg.Ping) (err error) {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
return nil return nil
} }
@@ -79,7 +79,7 @@ func (auth *OidcAuthProvider) SetPing(pingMsg *msg.Ping) (err error) {
} }
func (auth *OidcAuthProvider) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) { func (auth *OidcAuthProvider) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
return nil return nil
} }
@@ -135,7 +135,7 @@ func (auth *OidcAuthConsumer) verifyPostLoginToken(privilegeKey string) (err err
} }
func (auth *OidcAuthConsumer) VerifyPing(pingMsg *msg.Ping) (err error) { func (auth *OidcAuthConsumer) VerifyPing(pingMsg *msg.Ping) (err error) {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
return nil return nil
} }
@@ -143,7 +143,7 @@ func (auth *OidcAuthConsumer) VerifyPing(pingMsg *msg.Ping) (err error) {
} }
func (auth *OidcAuthConsumer) VerifyNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) { func (auth *OidcAuthConsumer) VerifyNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
return nil return nil
} }

View File

@@ -16,10 +16,9 @@ package auth
import ( import (
"fmt" "fmt"
"slices"
"time" "time"
"github.com/samber/lo"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
@@ -43,7 +42,7 @@ func (auth *TokenAuthSetterVerifier) SetLogin(loginMsg *msg.Login) error {
} }
func (auth *TokenAuthSetterVerifier) SetPing(pingMsg *msg.Ping) error { func (auth *TokenAuthSetterVerifier) SetPing(pingMsg *msg.Ping) error {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
return nil return nil
} }
@@ -53,7 +52,7 @@ func (auth *TokenAuthSetterVerifier) SetPing(pingMsg *msg.Ping) error {
} }
func (auth *TokenAuthSetterVerifier) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) error { func (auth *TokenAuthSetterVerifier) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) error {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
return nil return nil
} }
@@ -70,7 +69,7 @@ func (auth *TokenAuthSetterVerifier) VerifyLogin(m *msg.Login) error {
} }
func (auth *TokenAuthSetterVerifier) VerifyPing(m *msg.Ping) error { func (auth *TokenAuthSetterVerifier) VerifyPing(m *msg.Ping) error {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
return nil return nil
} }
@@ -81,7 +80,7 @@ func (auth *TokenAuthSetterVerifier) VerifyPing(m *msg.Ping) error {
} }
func (auth *TokenAuthSetterVerifier) VerifyNewWorkConn(m *msg.NewWorkConn) error { func (auth *TokenAuthSetterVerifier) VerifyNewWorkConn(m *msg.NewWorkConn) error {
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) { if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
return nil return nil
} }

View File

@@ -18,9 +18,9 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"slices"
"strings" "strings"
"github.com/samber/lo"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
legacyauth "github.com/fatedier/frp/pkg/auth/legacy" legacyauth "github.com/fatedier/frp/pkg/auth/legacy"
@@ -345,35 +345,19 @@ func copySection(source, target *ini.Section) {
} }
// GetDefaultClientConf returns a client configuration with default values. // GetDefaultClientConf returns a client configuration with default values.
// Note: Some default values here will be set to empty and will be converted to them
// new configuration through the 'Complete' function to set them as the default
// values of the new configuration.
func GetDefaultClientConf() ClientCommonConf { func GetDefaultClientConf() ClientCommonConf {
return ClientCommonConf{ return ClientCommonConf{
ClientConfig: legacyauth.GetDefaultClientConf(), ClientConfig: legacyauth.GetDefaultClientConf(),
ServerAddr: "0.0.0.0",
ServerPort: 7000,
NatHoleSTUNServer: "stun.easyvoip.com:3478",
DialServerTimeout: 10,
DialServerKeepAlive: 7200,
HTTPProxy: os.Getenv("http_proxy"),
LogFile: "console",
LogWay: "console",
LogLevel: "info",
LogMaxDays: 3,
AdminAddr: "127.0.0.1",
PoolCount: 1,
TCPMux: true, TCPMux: true,
TCPMuxKeepaliveInterval: 60,
LoginFailExit: true, LoginFailExit: true,
Start: make([]string, 0),
Protocol: "tcp", Protocol: "tcp",
QUICKeepalivePeriod: 10, Start: make([]string, 0),
QUICMaxIdleTimeout: 30,
QUICMaxIncomingStreams: 100000,
TLSEnable: true, TLSEnable: true,
DisableCustomTLSFirstByte: true, DisableCustomTLSFirstByte: true,
HeartbeatInterval: 30,
HeartbeatTimeout: 90,
Metas: make(map[string]string), Metas: make(map[string]string),
UDPPacketSize: 1500,
IncludeConfigFiles: make([]string, 0), IncludeConfigFiles: make([]string, 0),
} }
} }
@@ -399,7 +383,7 @@ func (cfg *ClientCommonConf) Validate() error {
} }
} }
if !lo.Contains([]string{"tcp", "kcp", "quic", "websocket", "wss"}, cfg.Protocol) { if !slices.Contains([]string{"tcp", "kcp", "quic", "websocket", "wss"}, cfg.Protocol) {
return fmt.Errorf("invalid protocol") return fmt.Errorf("invalid protocol")
} }

View File

@@ -200,34 +200,20 @@ type ServerCommonConf struct {
NatHoleAnalysisDataReserveHours int64 `ini:"nat_hole_analysis_data_reserve_hours" json:"nat_hole_analysis_data_reserve_hours"` NatHoleAnalysisDataReserveHours int64 `ini:"nat_hole_analysis_data_reserve_hours" json:"nat_hole_analysis_data_reserve_hours"`
} }
// GetDefaultServerConf returns a server configuration with reasonable // GetDefaultServerConf returns a server configuration with reasonable defaults.
// defaults. // Note: Some default values here will be set to empty and will be converted to them
// new configuration through the 'Complete' function to set them as the default
// values of the new configuration.
func GetDefaultServerConf() ServerCommonConf { func GetDefaultServerConf() ServerCommonConf {
return ServerCommonConf{ return ServerCommonConf{
ServerConfig: legacyauth.GetDefaultServerConf(), ServerConfig: legacyauth.GetDefaultServerConf(),
BindAddr: "0.0.0.0", DashboardAddr: "0.0.0.0",
BindPort: 7000, LogFile: "console",
QUICKeepalivePeriod: 10, LogWay: "console",
QUICMaxIdleTimeout: 30, DetailedErrorsToClient: true,
QUICMaxIncomingStreams: 100000, TCPMux: true,
VhostHTTPTimeout: 60, AllowPorts: make(map[int]struct{}),
DashboardAddr: "0.0.0.0", HTTPPlugins: make(map[string]HTTPPluginOptions),
LogFile: "console",
LogWay: "console",
LogLevel: "info",
LogMaxDays: 3,
DetailedErrorsToClient: true,
TCPMux: true,
TCPMuxKeepaliveInterval: 60,
TCPKeepAlive: 7200,
AllowPorts: make(map[int]struct{}),
MaxPoolCount: 5,
MaxPortsPerClient: 0,
HeartbeatTimeout: 90,
UserConnTimeout: 10,
HTTPPlugins: make(map[string]HTTPPluginOptions),
UDPPacketSize: 1500,
NatHoleAnalysisDataReserveHours: 7 * 24,
} }
} }

View File

@@ -80,7 +80,10 @@ func DetectLegacyINIFormatFromFile(path string) bool {
} }
func RenderWithTemplate(in []byte, values *Values) ([]byte, error) { func RenderWithTemplate(in []byte, values *Values) ([]byte, error) {
tmpl, err := template.New("frp").Parse(string(in)) tmpl, err := template.New("frp").Funcs(template.FuncMap{
"parseNumberRange": parseNumberRange,
"parseNumberRangePair": parseNumberRangePair,
}).Parse(string(in))
if err != nil { if err != nil {
return nil, err return nil, err
} }

52
pkg/config/template.go Normal file
View File

@@ -0,0 +1,52 @@
// Copyright 2024 The frp Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"fmt"
"github.com/fatedier/frp/pkg/util/util"
)
type NumberPair struct {
First int64
Second int64
}
func parseNumberRangePair(firstRangeStr, secondRangeStr string) ([]NumberPair, error) {
firstRangeNumbers, err := util.ParseRangeNumbers(firstRangeStr)
if err != nil {
return nil, err
}
secondRangeNumbers, err := util.ParseRangeNumbers(secondRangeStr)
if err != nil {
return nil, err
}
if len(firstRangeNumbers) != len(secondRangeNumbers) {
return nil, fmt.Errorf("first and second range numbers are not in pairs")
}
pairs := make([]NumberPair, 0, len(firstRangeNumbers))
for i := 0; i < len(firstRangeNumbers); i++ {
pairs = append(pairs, NumberPair{
First: firstRangeNumbers[i],
Second: secondRangeNumbers[i],
})
}
return pairs, nil
}
func parseNumberRange(firstRangeStr string) ([]int64, error) {
return util.ParseRangeNumbers(firstRangeStr)
}

View File

@@ -45,15 +45,6 @@ func NewBandwidthQuantity(s string) (BandwidthQuantity, error) {
return q, nil return q, nil
} }
func MustBandwidthQuantity(s string) BandwidthQuantity {
q := BandwidthQuantity{}
err := q.UnmarshalString(s)
if err != nil {
panic(err)
}
return q
}
func (q *BandwidthQuantity) Equal(u *BandwidthQuantity) bool { func (q *BandwidthQuantity) Equal(u *BandwidthQuantity) bool {
if q == nil && u == nil { if q == nil && u == nil {
return true return true

View File

@@ -135,9 +135,15 @@ func (c *ClientTransportConfig) Complete() {
c.ProxyURL = util.EmptyOr(c.ProxyURL, os.Getenv("http_proxy")) c.ProxyURL = util.EmptyOr(c.ProxyURL, os.Getenv("http_proxy"))
c.PoolCount = util.EmptyOr(c.PoolCount, 1) c.PoolCount = util.EmptyOr(c.PoolCount, 1)
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true)) c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))
c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60) c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 30)
c.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, 30) if lo.FromPtr(c.TCPMux) {
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90) // If TCPMux is enabled, heartbeat of application layer is unnecessary because we can rely on heartbeat in tcpmux.
c.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, -1)
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, -1)
} else {
c.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, 30)
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90)
}
c.QUIC.Complete() c.QUIC.Complete()
c.TLS.Complete() c.TLS.Complete()
} }

View File

@@ -129,3 +129,8 @@ type HTTPPluginOptions struct {
type HeaderOperations struct { type HeaderOperations struct {
Set map[string]string `json:"set,omitempty"` Set map[string]string `json:"set,omitempty"`
} }
type HTTPHeader struct {
Name string `json:"name"`
Value string `json:"value"`
}

View File

@@ -17,6 +17,7 @@ package v1
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"reflect" "reflect"
) )
@@ -42,7 +43,7 @@ func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
c.Type = typeStruct.Type c.Type = typeStruct.Type
if c.Type == "" { if c.Type == "" {
return nil return errors.New("plugin type is empty")
} }
v, ok := clientPluginOptionsTypeMap[typeStruct.Type] v, ok := clientPluginOptionsTypeMap[typeStruct.Type]
@@ -57,12 +58,16 @@ func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
} }
if err := decoder.Decode(options); err != nil { if err := decoder.Decode(options); err != nil {
return err return fmt.Errorf("unmarshal ClientPluginOptions error: %v", err)
} }
c.ClientPluginOptions = options c.ClientPluginOptions = options
return nil return nil
} }
func (c *TypedClientPluginOptions) MarshalJSON() ([]byte, error) {
return json.Marshal(c.ClientPluginOptions)
}
const ( const (
PluginHTTP2HTTPS = "http2https" PluginHTTP2HTTPS = "http2https"
PluginHTTPProxy = "http_proxy" PluginHTTPProxy = "http_proxy"

View File

@@ -97,6 +97,9 @@ type HealthCheckConfig struct {
// Path specifies the path to send health checks to if the // Path specifies the path to send health checks to if the
// health check type is "http". // health check type is "http".
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
// HTTPHeaders specifies the headers to send with the health request, if
// the health check type is "http".
HTTPHeaders []HTTPHeader `json:"httpHeaders,omitempty"`
} }
type DomainConfig struct { type DomainConfig struct {
@@ -186,12 +189,16 @@ func (c *TypedProxyConfig) UnmarshalJSON(b []byte) error {
decoder.DisallowUnknownFields() decoder.DisallowUnknownFields()
} }
if err := decoder.Decode(configurer); err != nil { if err := decoder.Decode(configurer); err != nil {
return err return fmt.Errorf("unmarshal ProxyConfig error: %v", err)
} }
c.ProxyConfigurer = configurer c.ProxyConfigurer = configurer
return nil return nil
} }
func (c *TypedProxyConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(c.ProxyConfigurer)
}
type ProxyConfigurer interface { type ProxyConfigurer interface {
Complete(namePrefix string) Complete(namePrefix string)
GetBaseConfig() *ProxyBaseConfig GetBaseConfig() *ProxyBaseConfig
@@ -288,6 +295,7 @@ type HTTPProxyConfig struct {
HTTPPassword string `json:"httpPassword,omitempty"` HTTPPassword string `json:"httpPassword,omitempty"`
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
ResponseHeaders HeaderOperations `json:"responseHeaders,omitempty"`
RouteByHTTPUser string `json:"routeByHTTPUser,omitempty"` RouteByHTTPUser string `json:"routeByHTTPUser,omitempty"`
} }
@@ -301,6 +309,7 @@ func (c *HTTPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
m.HTTPUser = c.HTTPUser m.HTTPUser = c.HTTPUser
m.HTTPPwd = c.HTTPPassword m.HTTPPwd = c.HTTPPassword
m.Headers = c.RequestHeaders.Set m.Headers = c.RequestHeaders.Set
m.ResponseHeaders = c.ResponseHeaders.Set
m.RouteByHTTPUser = c.RouteByHTTPUser m.RouteByHTTPUser = c.RouteByHTTPUser
} }
@@ -314,6 +323,7 @@ func (c *HTTPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
c.HTTPUser = m.HTTPUser c.HTTPUser = m.HTTPUser
c.HTTPPassword = m.HTTPPwd c.HTTPPassword = m.HTTPPwd
c.RequestHeaders.Set = m.Headers c.RequestHeaders.Set = m.Headers
c.ResponseHeaders.Set = m.ResponseHeaders
c.RouteByHTTPUser = m.RouteByHTTPUser c.RouteByHTTPUser = m.RouteByHTTPUser
} }

View File

@@ -176,10 +176,15 @@ type ServerTransportConfig struct {
func (c *ServerTransportConfig) Complete() { func (c *ServerTransportConfig) Complete() {
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true)) c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))
c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60) c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 30)
c.TCPKeepAlive = util.EmptyOr(c.TCPKeepAlive, 7200) c.TCPKeepAlive = util.EmptyOr(c.TCPKeepAlive, 7200)
c.MaxPoolCount = util.EmptyOr(c.MaxPoolCount, 5) c.MaxPoolCount = util.EmptyOr(c.MaxPoolCount, 5)
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90) if lo.FromPtr(c.TCPMux) {
// If TCPMux is enabled, heartbeat of application layer is unnecessary because we can rely on heartbeat in tcpmux.
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, -1)
} else {
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90)
}
c.QUIC.Complete() c.QUIC.Complete()
if c.TLS.TrustedCaFile != "" { if c.TLS.TrustedCaFile != "" {
c.TLS.Force = true c.TLS.Force = true

View File

@@ -18,6 +18,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"slices"
"github.com/samber/lo" "github.com/samber/lo"
@@ -29,7 +30,7 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
warnings Warning warnings Warning
errs error errs error
) )
if !lo.Contains(SupportedAuthMethods, c.Auth.Method) { if !slices.Contains(SupportedAuthMethods, c.Auth.Method) {
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods)) errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
} }
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) { if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
@@ -63,7 +64,7 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.Transport.TLS.TrustedCaFile)) warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.Transport.TLS.TrustedCaFile))
} }
if !lo.Contains(SupportedTransportProtocols, c.Transport.Protocol) { if !slices.Contains(SupportedTransportProtocols, c.Transport.Protocol) {
errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols)) errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols))
} }

View File

@@ -16,8 +16,7 @@ package validation
import ( import (
"fmt" "fmt"
"slices"
"github.com/samber/lo"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
) )
@@ -44,7 +43,7 @@ func ValidatePort(port int, fieldPath string) error {
} }
func validateLogConfig(c *v1.LogConfig) error { func validateLogConfig(c *v1.LogConfig) error {
if !lo.Contains(SupportedLogLevels, c.Level) { if !slices.Contains(SupportedLogLevels, c.Level) {
return fmt.Errorf("invalid log level, optional values are %v", SupportedLogLevels) return fmt.Errorf("invalid log level, optional values are %v", SupportedLogLevels)
} }
return nil return nil

View File

@@ -17,9 +17,9 @@ package validation
import ( import (
"errors" "errors"
"fmt" "fmt"
"slices"
"strings" "strings"
"github.com/samber/lo"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
@@ -33,10 +33,10 @@ func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
if err := ValidateAnnotations(c.Annotations); err != nil { if err := ValidateAnnotations(c.Annotations); err != nil {
return err return err
} }
if !lo.Contains([]string{"", "v1", "v2"}, c.Transport.ProxyProtocolVersion) { if !slices.Contains([]string{"", "v1", "v2"}, c.Transport.ProxyProtocolVersion) {
return fmt.Errorf("not support proxy protocol version: %s", c.Transport.ProxyProtocolVersion) return fmt.Errorf("not support proxy protocol version: %s", c.Transport.ProxyProtocolVersion)
} }
if !lo.Contains([]string{"client", "server"}, c.Transport.BandwidthLimitMode) { if !slices.Contains([]string{"client", "server"}, c.Transport.BandwidthLimitMode) {
return fmt.Errorf("bandwidth limit mode should be client or server") return fmt.Errorf("bandwidth limit mode should be client or server")
} }
@@ -46,7 +46,7 @@ func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
} }
} }
if !lo.Contains([]string{"", "tcp", "http"}, c.HealthCheck.Type) { if !slices.Contains([]string{"", "tcp", "http"}, c.HealthCheck.Type) {
return fmt.Errorf("not support health check type: %s", c.HealthCheck.Type) return fmt.Errorf("not support health check type: %s", c.HealthCheck.Type)
} }
if c.HealthCheck.Type != "" { if c.HealthCheck.Type != "" {
@@ -139,7 +139,7 @@ func validateTCPMuxProxyConfigForClient(c *v1.TCPMuxProxyConfig) error {
return err return err
} }
if !lo.Contains([]string{string(v1.TCPMultiplexerHTTPConnect)}, c.Multiplexer) { if !slices.Contains([]string{string(v1.TCPMultiplexerHTTPConnect)}, c.Multiplexer) {
return fmt.Errorf("not support multiplexer: %s", c.Multiplexer) return fmt.Errorf("not support multiplexer: %s", c.Multiplexer)
} }
return nil return nil

View File

@@ -16,6 +16,7 @@ package validation
import ( import (
"fmt" "fmt"
"slices"
"github.com/samber/lo" "github.com/samber/lo"
@@ -27,7 +28,7 @@ func ValidateServerConfig(c *v1.ServerConfig) (Warning, error) {
warnings Warning warnings Warning
errs error errs error
) )
if !lo.Contains(SupportedAuthMethods, c.Auth.Method) { if !slices.Contains(SupportedAuthMethods, c.Auth.Method) {
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods)) errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
} }
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) { if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {

View File

@@ -17,8 +17,7 @@ package validation
import ( import (
"errors" "errors"
"fmt" "fmt"
"slices"
"github.com/samber/lo"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
) )
@@ -56,7 +55,7 @@ func validateVisitorBaseConfig(c *v1.VisitorBaseConfig) error {
} }
func validateXTCPVisitorConfig(c *v1.XTCPVisitorConfig) error { func validateXTCPVisitorConfig(c *v1.XTCPVisitorConfig) error {
if !lo.Contains([]string{"kcp", "quic"}, c.Protocol) { if !slices.Contains([]string{"kcp", "quic"}, c.Protocol) {
return fmt.Errorf("protocol should be kcp or quic") return fmt.Errorf("protocol should be kcp or quic")
} }
return nil return nil

View File

@@ -114,12 +114,16 @@ func (c *TypedVisitorConfig) UnmarshalJSON(b []byte) error {
decoder.DisallowUnknownFields() decoder.DisallowUnknownFields()
} }
if err := decoder.Decode(configurer); err != nil { if err := decoder.Decode(configurer); err != nil {
return err return fmt.Errorf("unmarshal VisitorConfig error: %v", err)
} }
c.VisitorConfigurer = configurer c.VisitorConfigurer = configurer
return nil return nil
} }
func (c *TypedVisitorConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(c.VisitorConfigurer)
}
func NewVisitorConfigurerByType(t VisitorType) VisitorConfigurer { func NewVisitorConfigurerByType(t VisitorType) VisitorConfigurer {
v, ok := visitorConfigTypeMap[t] v, ok := visitorConfigTypeMap[t]
if !ok { if !ok {

View File

@@ -62,7 +62,7 @@ func (m *serverMetrics) run() {
time.Sleep(12 * time.Hour) time.Sleep(12 * time.Hour)
start := time.Now() start := time.Now()
count, total := m.clearUselessInfo(time.Duration(7*24) * time.Hour) count, total := m.clearUselessInfo(time.Duration(7*24) * time.Hour)
log.Debug("clear useless proxy statistics data count %d/%d, cost %v", count, total, time.Since(start)) log.Debugf("clear useless proxy statistics data count %d/%d, cost %v", count, total, time.Since(start))
} }
}() }()
} }
@@ -80,7 +80,7 @@ func (m *serverMetrics) clearUselessInfo(continuousOfflineDuration time.Duration
time.Since(data.LastCloseTime) > continuousOfflineDuration { time.Since(data.LastCloseTime) > continuousOfflineDuration {
delete(m.info.ProxyStatistics, name) delete(m.info.ProxyStatistics, name)
count++ count++
log.Trace("clear proxy [%s]'s statistics data, lastCloseTime: [%s]", name, data.LastCloseTime.String()) log.Tracef("clear proxy [%s]'s statistics data, lastCloseTime: [%s]", name, data.LastCloseTime.String())
} }
} }
return count, total return count, total

View File

@@ -42,7 +42,3 @@ func ReadMsgInto(c io.Reader, msg Message) (err error) {
func WriteMsg(c io.Writer, msg interface{}) (err error) { func WriteMsg(c io.Writer, msg interface{}) (err error) {
return msgCtl.WriteMsg(c, msg) return msgCtl.WriteMsg(c, msg)
} }
func Pack(msg interface{}) (data []byte, err error) {
return msgCtl.Pack(msg)
}

View File

@@ -121,6 +121,7 @@ type NewProxy struct {
HTTPPwd string `json:"http_pwd,omitempty"` HTTPPwd string `json:"http_pwd,omitempty"`
HostHeaderRewrite string `json:"host_header_rewrite,omitempty"` HostHeaderRewrite string `json:"host_header_rewrite,omitempty"`
Headers map[string]string `json:"headers,omitempty"` Headers map[string]string `json:"headers,omitempty"`
ResponseHeaders map[string]string `json:"response_headers,omitempty"`
RouteByHTTPUser string `json:"route_by_http_user,omitempty"` RouteByHTTPUser string `json:"route_by_http_user,omitempty"`
// stcp, sudp, xtcp // stcp, sudp, xtcp

View File

@@ -15,6 +15,8 @@
package nathole package nathole
import ( import (
"cmp"
"slices"
"sync" "sync"
"time" "time"
@@ -233,12 +235,12 @@ func (mhr *MakeHoleRecords) Recommand() (mode, index int) {
mhr.mu.Lock() mhr.mu.Lock()
defer mhr.mu.Unlock() defer mhr.mu.Unlock()
maxScore := lo.MaxBy(mhr.scores, func(item, max *BehaviorScore) bool { if len(mhr.scores) == 0 {
return item.Score > max.Score
})
if maxScore == nil {
return 0, 0 return 0, 0
} }
maxScore := slices.MaxFunc(mhr.scores, func(a, b *BehaviorScore) int {
return cmp.Compare(a.Score, b.Score)
})
maxScore.Score-- maxScore.Score--
mhr.LastUpdateTime = time.Now() mhr.LastUpdateTime = time.Now()
return maxScore.Mode, maxScore.Index return maxScore.Mode, maxScore.Index

View File

@@ -17,9 +17,8 @@ package nathole
import ( import (
"fmt" "fmt"
"net" "net"
"slices"
"strconv" "strconv"
"github.com/samber/lo"
) )
const ( const (
@@ -59,7 +58,7 @@ func ClassifyNATFeature(addresses []string, localIPs []string) (*NatFeature, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
if lo.Contains(localIPs, ip) { if slices.Contains(localIPs, ip) {
natFeature.PublicNetwork = true natFeature.PublicNetwork = true
} }

View File

@@ -20,6 +20,7 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"net" "net"
"slices"
"strconv" "strconv"
"sync" "sync"
"time" "time"
@@ -72,7 +73,7 @@ type Session struct {
func (s *Session) genAnalysisKey() { func (s *Session) genAnalysisKey() {
hash := md5.New() hash := md5.New()
vIPs := lo.Uniq(parseIPs(s.visitorMsg.MappedAddrs)) vIPs := slices.Compact(parseIPs(s.visitorMsg.MappedAddrs))
if len(vIPs) > 0 { if len(vIPs) > 0 {
hash.Write([]byte(vIPs[0])) hash.Write([]byte(vIPs[0]))
} }
@@ -80,7 +81,7 @@ func (s *Session) genAnalysisKey() {
hash.Write([]byte(s.vNatFeature.Behavior)) hash.Write([]byte(s.vNatFeature.Behavior))
hash.Write([]byte(strconv.FormatBool(s.vNatFeature.RegularPortsChange))) hash.Write([]byte(strconv.FormatBool(s.vNatFeature.RegularPortsChange)))
cIPs := lo.Uniq(parseIPs(s.clientMsg.MappedAddrs)) cIPs := slices.Compact(parseIPs(s.clientMsg.MappedAddrs))
if len(cIPs) > 0 { if len(cIPs) > 0 {
hash.Write([]byte(cIPs[0])) hash.Write([]byte(cIPs[0]))
} }
@@ -114,7 +115,7 @@ func (c *Controller) CleanWorker(ctx context.Context) {
case <-ticker.C: case <-ticker.C:
start := time.Now() start := time.Now()
count, total := c.analyzer.Clean() count, total := c.analyzer.Clean()
log.Trace("clean %d/%d nathole analysis data, cost %v", count, total, time.Since(start)) log.Tracef("clean %d/%d nathole analysis data, cost %v", count, total, time.Since(start))
case <-ctx.Done(): case <-ctx.Done():
return return
} }
@@ -156,7 +157,7 @@ func (c *Controller) HandleVisitor(m *msg.NatHoleVisitor, transporter transport.
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, fmt.Sprintf("xtcp server for [%s] doesn't exist", m.ProxyName))) _ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, fmt.Sprintf("xtcp server for [%s] doesn't exist", m.ProxyName)))
return return
} }
if !lo.Contains(cfg.allowUsers, visitorUser) && !lo.Contains(cfg.allowUsers, "*") { if !slices.Contains(cfg.allowUsers, visitorUser) && !slices.Contains(cfg.allowUsers, "*") {
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, fmt.Sprintf("xtcp visitor user [%s] not allowed for [%s]", visitorUser, m.ProxyName))) _ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, fmt.Sprintf("xtcp visitor user [%s] not allowed for [%s]", visitorUser, m.ProxyName)))
return return
} }
@@ -190,11 +191,11 @@ func (c *Controller) HandleVisitor(m *msg.NatHoleVisitor, transporter transport.
return nil return nil
}() }()
if err != nil { if err != nil {
log.Warn("handle visitorMsg error: %v", err) log.Warnf("handle visitorMsg error: %v", err)
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, err.Error())) _ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, err.Error()))
return return
} }
log.Trace("handle visitor message, sid [%s], server name: %s", sid, m.ProxyName) log.Tracef("handle visitor message, sid [%s], server name: %s", sid, m.ProxyName)
defer func() { defer func() {
c.mu.Lock() c.mu.Lock()
@@ -212,14 +213,14 @@ func (c *Controller) HandleVisitor(m *msg.NatHoleVisitor, transporter transport.
select { select {
case <-session.notifyCh: case <-session.notifyCh:
case <-time.After(time.Duration(NatHoleTimeout) * time.Second): case <-time.After(time.Duration(NatHoleTimeout) * time.Second):
log.Debug("wait for NatHoleClient message timeout, sid [%s]", sid) log.Debugf("wait for NatHoleClient message timeout, sid [%s]", sid)
return return
} }
// Make hole-punching decisions based on the NAT information of the client and visitor. // Make hole-punching decisions based on the NAT information of the client and visitor.
vResp, cResp, err := c.analysis(session) vResp, cResp, err := c.analysis(session)
if err != nil { if err != nil {
log.Debug("sid [%s] analysis error: %v", err) log.Debugf("sid [%s] analysis error: %v", err)
vResp = c.GenNatHoleResponse(session.visitorMsg.TransactionID, nil, err.Error()) vResp = c.GenNatHoleResponse(session.visitorMsg.TransactionID, nil, err.Error())
cResp = c.GenNatHoleResponse(session.clientMsg.TransactionID, nil, err.Error()) cResp = c.GenNatHoleResponse(session.clientMsg.TransactionID, nil, err.Error())
} }
@@ -256,7 +257,7 @@ func (c *Controller) HandleClient(m *msg.NatHoleClient, transporter transport.Me
if !ok { if !ok {
return return
} }
log.Trace("handle client message, sid [%s], server name: %s", session.sid, m.ProxyName) log.Tracef("handle client message, sid [%s], server name: %s", session.sid, m.ProxyName)
session.clientMsg = m session.clientMsg = m
session.clientTransporter = transporter session.clientTransporter = transporter
select { select {
@@ -270,13 +271,13 @@ func (c *Controller) HandleReport(m *msg.NatHoleReport) {
session, ok := c.sessions[m.Sid] session, ok := c.sessions[m.Sid]
c.mu.RUnlock() c.mu.RUnlock()
if !ok { if !ok {
log.Trace("sid [%s] report make hole success: %v, but session not found", m.Sid, m.Success) log.Tracef("sid [%s] report make hole success: %v, but session not found", m.Sid, m.Success)
return return
} }
if m.Success { if m.Success {
c.analyzer.ReportSuccess(session.analysisKey, session.recommandMode, session.recommandIndex) c.analyzer.ReportSuccess(session.analysisKey, session.recommandMode, session.recommandIndex)
} }
log.Info("sid [%s] report make hole success: %v, mode %v, index %v", log.Infof("sid [%s] report make hole success: %v, mode %v, index %v",
m.Sid, m.Success, session.recommandMode, session.recommandIndex) m.Sid, m.Success, session.recommandMode, session.recommandIndex)
} }
@@ -327,8 +328,8 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
TransactionID: vm.TransactionID, TransactionID: vm.TransactionID,
Sid: session.sid, Sid: session.sid,
Protocol: protocol, Protocol: protocol,
CandidateAddrs: lo.Uniq(cm.MappedAddrs), CandidateAddrs: slices.Compact(cm.MappedAddrs),
AssistedAddrs: lo.Uniq(cm.AssistedAddrs), AssistedAddrs: slices.Compact(cm.AssistedAddrs),
DetectBehavior: msg.NatHoleDetectBehavior{ DetectBehavior: msg.NatHoleDetectBehavior{
Mode: mode, Mode: mode,
Role: vBehavior.Role, Role: vBehavior.Role,
@@ -344,8 +345,8 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
TransactionID: cm.TransactionID, TransactionID: cm.TransactionID,
Sid: session.sid, Sid: session.sid,
Protocol: protocol, Protocol: protocol,
CandidateAddrs: lo.Uniq(vm.MappedAddrs), CandidateAddrs: slices.Compact(vm.MappedAddrs),
AssistedAddrs: lo.Uniq(vm.AssistedAddrs), AssistedAddrs: slices.Compact(vm.AssistedAddrs),
DetectBehavior: msg.NatHoleDetectBehavior{ DetectBehavior: msg.NatHoleDetectBehavior{
Mode: mode, Mode: mode,
Role: cBehavior.Role, Role: cBehavior.Role,
@@ -358,10 +359,10 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
}, },
} }
log.Debug("sid [%s] visitor nat: %+v, candidateAddrs: %v; client nat: %+v, candidateAddrs: %v, protocol: %s", log.Debugf("sid [%s] visitor nat: %+v, candidateAddrs: %v; client nat: %+v, candidateAddrs: %v, protocol: %s",
session.sid, *vNatFeature, vm.MappedAddrs, *cNatFeature, cm.MappedAddrs, protocol) session.sid, *vNatFeature, vm.MappedAddrs, *cNatFeature, cm.MappedAddrs, protocol)
log.Debug("sid [%s] visitor detect behavior: %+v", session.sid, vResp.DetectBehavior) log.Debugf("sid [%s] visitor detect behavior: %+v", session.sid, vResp.DetectBehavior)
log.Debug("sid [%s] client detect behavior: %+v", session.sid, cResp.DetectBehavior) log.Debugf("sid [%s] client detect behavior: %+v", session.sid, cResp.DetectBehavior)
return vResp, cResp, nil return vResp, cResp, nil
} }

View File

@@ -17,14 +17,14 @@ package nathole
import ( import (
"context" "context"
"fmt" "fmt"
"math/rand" "math/rand/v2"
"net" "net"
"slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/fatedier/golib/pool" "github.com/fatedier/golib/pool"
"github.com/samber/lo"
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
@@ -204,7 +204,7 @@ func MakeHole(ctx context.Context, listenConn *net.UDPConn, m *msg.NatHoleResp,
for i := 0; i < m.DetectBehavior.ListenRandomPorts; i++ { for i := 0; i < m.DetectBehavior.ListenRandomPorts; i++ {
tmpConn, err := net.ListenUDP("udp4", nil) tmpConn, err := net.ListenUDP("udp4", nil)
if err != nil { if err != nil {
xl.Warn("listen random udp addr error: %v", err) xl.Warnf("listen random udp addr error: %v", err)
continue continue
} }
listenConns = append(listenConns, tmpConn) listenConns = append(listenConns, tmpConn)
@@ -212,11 +212,11 @@ func MakeHole(ctx context.Context, listenConn *net.UDPConn, m *msg.NatHoleResp,
} }
} }
detectAddrs = lo.Uniq(detectAddrs) detectAddrs = slices.Compact(detectAddrs)
for _, detectAddr := range detectAddrs { for _, detectAddr := range detectAddrs {
for _, conn := range listenConns { for _, conn := range listenConns {
if err := sendSidMessage(ctx, conn, m.Sid, transactionID, detectAddr, key, m.DetectBehavior.TTL); err != nil { if err := sendSidMessage(ctx, conn, m.Sid, transactionID, detectAddr, key, m.DetectBehavior.TTL); err != nil {
xl.Trace("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err) xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
} }
} }
} }
@@ -289,16 +289,16 @@ func waitDetectMessage(
if err != nil { if err != nil {
return nil, err return nil, err
} }
xl.Debug("get udp message local %s, from %s", conn.LocalAddr(), raddr) xl.Debugf("get udp message local %s, from %s", conn.LocalAddr(), raddr)
var m msg.NatHoleSid var m msg.NatHoleSid
if err := DecodeMessageInto(buf[:n], key, &m); err != nil { if err := DecodeMessageInto(buf[:n], key, &m); err != nil {
xl.Warn("decode sid message error: %v", err) xl.Warnf("decode sid message error: %v", err)
continue continue
} }
pool.PutBuf(buf) pool.PutBuf(buf)
if m.Sid != sid { if m.Sid != sid {
xl.Warn("get sid message with wrong sid: %s, expect: %s", m.Sid, sid) xl.Warnf("get sid message with wrong sid: %s, expect: %s", m.Sid, sid)
continue continue
} }
@@ -311,7 +311,7 @@ func waitDetectMessage(
m.Response = true m.Response = true
buf2, err := EncodeMessage(&m, key) buf2, err := EncodeMessage(&m, key)
if err != nil { if err != nil {
xl.Warn("encode sid message error: %v", err) xl.Warnf("encode sid message error: %v", err)
continue continue
} }
_, _ = conn.WriteToUDP(buf2, raddr) _, _ = conn.WriteToUDP(buf2, raddr)
@@ -329,7 +329,7 @@ func sendSidMessage(
if ttl > 0 { if ttl > 0 {
ttlStr = fmt.Sprintf(" with ttl %d", ttl) ttlStr = fmt.Sprintf(" with ttl %d", ttl)
} }
xl.Trace("send sid message from %s to %s%s", conn.LocalAddr(), addr, ttlStr) xl.Tracef("send sid message from %s to %s%s", conn.LocalAddr(), addr, ttlStr)
raddr, err := net.ResolveUDPAddr("udp4", addr) raddr, err := net.ResolveUDPAddr("udp4", addr)
if err != nil { if err != nil {
return err return err
@@ -341,7 +341,7 @@ func sendSidMessage(
TransactionID: transactionID, TransactionID: transactionID,
Sid: sid, Sid: sid,
Response: false, Response: false,
Nonce: strings.Repeat("0", rand.Intn(20)), Nonce: strings.Repeat("0", rand.IntN(20)),
} }
buf, err := EncodeMessage(m, key) buf, err := EncodeMessage(m, key)
if err != nil { if err != nil {
@@ -351,14 +351,14 @@ func sendSidMessage(
uConn := ipv4.NewConn(conn) uConn := ipv4.NewConn(conn)
original, err := uConn.TTL() original, err := uConn.TTL()
if err != nil { if err != nil {
xl.Trace("get ttl error %v", err) xl.Tracef("get ttl error %v", err)
return err return err
} }
xl.Trace("original ttl %d", original) xl.Tracef("original ttl %d", original)
err = uConn.SetTTL(ttl) err = uConn.SetTTL(ttl)
if err != nil { if err != nil {
xl.Trace("set ttl error %v", err) xl.Tracef("set ttl error %v", err)
} else { } else {
defer func() { defer func() {
_ = uConn.SetTTL(original) _ = uConn.SetTTL(original)
@@ -377,12 +377,12 @@ func sendSidMessageToRangePorts(
sendFunc func(*net.UDPConn, string) error, sendFunc func(*net.UDPConn, string) error,
) { ) {
xl := xlog.FromContextSafe(ctx) xl := xlog.FromContextSafe(ctx)
for _, ip := range lo.Uniq(parseIPs(addrs)) { for _, ip := range slices.Compact(parseIPs(addrs)) {
for _, portsRange := range ports { for _, portsRange := range ports {
for i := portsRange.From; i <= portsRange.To; i++ { for i := portsRange.From; i <= portsRange.To; i++ {
detectAddr := net.JoinHostPort(ip, strconv.Itoa(i)) detectAddr := net.JoinHostPort(ip, strconv.Itoa(i))
if err := sendFunc(conn, detectAddr); err != nil { if err := sendFunc(conn, detectAddr); err != nil {
xl.Trace("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err) xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
} }
time.Sleep(2 * time.Millisecond) time.Sleep(2 * time.Millisecond)
} }
@@ -398,7 +398,7 @@ func sendSidMessageToRandomPorts(
used := sets.New[int]() used := sets.New[int]()
getUnusedPort := func() int { getUnusedPort := func() int {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
port := rand.Intn(65535-1024) + 1024 port := rand.IntN(65535-1024) + 1024
if !used.Has(port) { if !used.Has(port) {
used.Insert(port) used.Insert(port)
return port return port
@@ -419,10 +419,10 @@ func sendSidMessageToRandomPorts(
continue continue
} }
for _, ip := range lo.Uniq(parseIPs(addrs)) { for _, ip := range slices.Compact(parseIPs(addrs)) {
detectAddr := net.JoinHostPort(ip, strconv.Itoa(port)) detectAddr := net.JoinHostPort(ip, strconv.Itoa(port))
if err := sendFunc(conn, detectAddr); err != nil { if err := sendFunc(conn, detectAddr); err != nil {
xl.Trace("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err) xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
} }
time.Sleep(time.Millisecond * 15) time.Sleep(time.Millisecond * 15)
} }

View File

@@ -19,11 +19,15 @@ package plugin
import ( import (
"crypto/tls" "crypto/tls"
"io" "io"
stdlog "log"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"github.com/fatedier/golib/pool"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/util/log"
netpkg "github.com/fatedier/frp/pkg/util/net" netpkg "github.com/fatedier/frp/pkg/util/net"
) )
@@ -54,6 +58,9 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
rp := &httputil.ReverseProxy{ rp := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) { Rewrite: func(r *httputil.ProxyRequest) {
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
r.Out.Header["X-Forwarded-Host"] = r.In.Header["X-Forwarded-Host"]
r.Out.Header["X-Forwarded-Proto"] = r.In.Header["X-Forwarded-Proto"]
req := r.Out req := r.Out
req.URL.Scheme = "https" req.URL.Scheme = "https"
req.URL.Host = p.opts.LocalAddr req.URL.Host = p.opts.LocalAddr
@@ -64,7 +71,9 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
req.Header.Set(k, v) req.Header.Set(k, v)
} }
}, },
Transport: tr, Transport: tr,
BufferPool: pool.NewBuffer(32 * 1024),
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
} }
p.s = &http.Server{ p.s = &http.Server{

View File

@@ -54,7 +54,8 @@ func NewHTTPProxyPlugin(options v1.ClientPluginOptions) (Plugin, error) {
} }
hp.s = &http.Server{ hp.s = &http.Server{
Handler: hp, Handler: hp,
ReadHeaderTimeout: 60 * time.Second,
} }
go func() { go func() {

View File

@@ -20,12 +20,17 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io" "io"
stdlog "log"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"time"
"github.com/fatedier/golib/pool"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/transport" "github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/pkg/util/log"
netpkg "github.com/fatedier/frp/pkg/util/net" netpkg "github.com/fatedier/frp/pkg/util/net"
) )
@@ -51,6 +56,8 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
rp := &httputil.ReverseProxy{ rp := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) { Rewrite: func(r *httputil.ProxyRequest) {
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
r.SetXForwarded()
req := r.Out req := r.Out
req.URL.Scheme = "http" req.URL.Scheme = "http"
req.URL.Host = p.opts.LocalAddr req.URL.Host = p.opts.LocalAddr
@@ -61,10 +68,8 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
req.Header.Set(k, v) req.Header.Set(k, v)
} }
}, },
} BufferPool: pool.NewBuffer(32 * 1024),
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
p.s = &http.Server{
Handler: rp,
} }
var ( var (
@@ -80,10 +85,15 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("gen TLS config error: %v", err) return nil, fmt.Errorf("gen TLS config error: %v", err)
} }
ln := tls.NewListener(listener, tlsConfig)
p.s = &http.Server{
Handler: rp,
ReadHeaderTimeout: 60 * time.Second,
TLSConfig: tlsConfig,
}
go func() { go func() {
_ = p.s.Serve(ln) _ = p.s.ServeTLS(listener, "", "")
}() }()
return p, nil return p, nil
} }
@@ -98,8 +108,11 @@ func (p *HTTPS2HTTPPlugin) genTLSConfig() (*tls.Config, error) {
return config, nil return config, nil
} }
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) {
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
if extra.SrcAddr != nil {
wrapConn.SetRemoteAddr(extra.SrcAddr)
}
_ = p.l.PutConn(wrapConn) _ = p.l.PutConn(wrapConn)
} }

View File

@@ -20,12 +20,17 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"io" "io"
stdlog "log"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"time"
"github.com/fatedier/golib/pool"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/transport" "github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/pkg/util/log"
netpkg "github.com/fatedier/frp/pkg/util/net" netpkg "github.com/fatedier/frp/pkg/util/net"
) )
@@ -56,6 +61,8 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
rp := &httputil.ReverseProxy{ rp := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) { Rewrite: func(r *httputil.ProxyRequest) {
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
r.SetXForwarded()
req := r.Out req := r.Out
req.URL.Scheme = "https" req.URL.Scheme = "https"
req.URL.Host = p.opts.LocalAddr req.URL.Host = p.opts.LocalAddr
@@ -66,11 +73,9 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
req.Header.Set(k, v) req.Header.Set(k, v)
} }
}, },
Transport: tr, Transport: tr,
} BufferPool: pool.NewBuffer(32 * 1024),
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
p.s = &http.Server{
Handler: rp,
} }
var ( var (
@@ -86,10 +91,15 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("gen TLS config error: %v", err) return nil, fmt.Errorf("gen TLS config error: %v", err)
} }
ln := tls.NewListener(listener, tlsConfig)
p.s = &http.Server{
Handler: rp,
ReadHeaderTimeout: 60 * time.Second,
TLSConfig: tlsConfig,
}
go func() { go func() {
_ = p.s.Serve(ln) _ = p.s.ServeTLS(listener, "", "")
}() }()
return p, nil return p, nil
} }
@@ -104,8 +114,11 @@ func (p *HTTPS2HTTPSPlugin) genTLSConfig() (*tls.Config, error) {
return config, nil return config, nil
} }
func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) {
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
if extra.SrcAddr != nil {
wrapConn.SetRemoteAddr(extra.SrcAddr)
}
_ = p.l.PutConn(wrapConn) _ = p.l.PutConn(wrapConn)
} }

View File

@@ -50,6 +50,8 @@ func Create(name string, options v1.ClientPluginOptions) (p Plugin, err error) {
type ExtraInfo struct { type ExtraInfo struct {
ProxyProtocolHeader *pp.Header ProxyProtocolHeader *pp.Header
SrcAddr net.Addr
DstAddr net.Addr
} }
type Plugin interface { type Plugin interface {

View File

@@ -60,7 +60,8 @@ func NewStaticFilePlugin(options v1.ClientPluginOptions) (Plugin, error) {
router.Use(netpkg.NewHTTPAuthMiddleware(opts.HTTPUser, opts.HTTPPassword).SetAuthFailDelay(200 * time.Millisecond).Middleware) router.Use(netpkg.NewHTTPAuthMiddleware(opts.HTTPUser, opts.HTTPPassword).SetAuthFailDelay(200 * time.Millisecond).Middleware)
router.PathPrefix(prefix).Handler(netpkg.MakeHTTPGzipHandler(http.StripPrefix(prefix, http.FileServer(http.Dir(opts.LocalPath))))).Methods("GET") router.PathPrefix(prefix).Handler(netpkg.MakeHTTPGzipHandler(http.StripPrefix(prefix, http.FileServer(http.Dir(opts.LocalPath))))).Methods("GET")
sp.s = &http.Server{ sp.s = &http.Server{
Handler: router, Handler: router,
ReadHeaderTimeout: 60 * time.Second,
} }
go func() { go func() {
_ = sp.s.Serve(listener) _ = sp.s.Serve(listener)

View File

@@ -86,7 +86,7 @@ func (m *Manager) Login(content *LoginContent) (*LoginContent, error) {
for _, p := range m.loginPlugins { for _, p := range m.loginPlugins {
res, retContent, err = p.Handle(ctx, OpLogin, *content) res, retContent, err = p.Handle(ctx, OpLogin, *content)
if err != nil { if err != nil {
xl.Warn("send Login request to plugin [%s] error: %v", p.Name(), err) xl.Warnf("send Login request to plugin [%s] error: %v", p.Name(), err)
return nil, errors.New("send Login request to plugin error") return nil, errors.New("send Login request to plugin error")
} }
if res.Reject { if res.Reject {
@@ -120,7 +120,7 @@ func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) {
for _, p := range m.newProxyPlugins { for _, p := range m.newProxyPlugins {
res, retContent, err = p.Handle(ctx, OpNewProxy, *content) res, retContent, err = p.Handle(ctx, OpNewProxy, *content)
if err != nil { if err != nil {
xl.Warn("send NewProxy request to plugin [%s] error: %v", p.Name(), err) xl.Warnf("send NewProxy request to plugin [%s] error: %v", p.Name(), err)
return nil, errors.New("send NewProxy request to plugin error") return nil, errors.New("send NewProxy request to plugin error")
} }
if res.Reject { if res.Reject {
@@ -147,7 +147,7 @@ func (m *Manager) CloseProxy(content *CloseProxyContent) error {
for _, p := range m.closeProxyPlugins { for _, p := range m.closeProxyPlugins {
_, _, err := p.Handle(ctx, OpCloseProxy, *content) _, _, err := p.Handle(ctx, OpCloseProxy, *content)
if err != nil { if err != nil {
xl.Warn("send CloseProxy request to plugin [%s] error: %v", p.Name(), err) xl.Warnf("send CloseProxy request to plugin [%s] error: %v", p.Name(), err)
errs = append(errs, fmt.Sprintf("[%s]: %v", p.Name(), err)) errs = append(errs, fmt.Sprintf("[%s]: %v", p.Name(), err))
} }
} }
@@ -179,7 +179,7 @@ func (m *Manager) Ping(content *PingContent) (*PingContent, error) {
for _, p := range m.pingPlugins { for _, p := range m.pingPlugins {
res, retContent, err = p.Handle(ctx, OpPing, *content) res, retContent, err = p.Handle(ctx, OpPing, *content)
if err != nil { if err != nil {
xl.Warn("send Ping request to plugin [%s] error: %v", p.Name(), err) xl.Warnf("send Ping request to plugin [%s] error: %v", p.Name(), err)
return nil, errors.New("send Ping request to plugin error") return nil, errors.New("send Ping request to plugin error")
} }
if res.Reject { if res.Reject {
@@ -213,7 +213,7 @@ func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent,
for _, p := range m.newWorkConnPlugins { for _, p := range m.newWorkConnPlugins {
res, retContent, err = p.Handle(ctx, OpNewWorkConn, *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.Warnf("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")
} }
if res.Reject { if res.Reject {
@@ -247,7 +247,7 @@ func (m *Manager) NewUserConn(content *NewUserConnContent) (*NewUserConnContent,
for _, p := range m.newUserConnPlugins { for _, p := range m.newUserConnPlugins {
res, retContent, err = p.Handle(ctx, OpNewUserConn, *content) res, retContent, err = p.Handle(ctx, OpNewUserConn, *content)
if err != nil { if err != nil {
xl.Info("send NewUserConn request to plugin [%s] error: %v", p.Name(), err) xl.Infof("send NewUserConn request to plugin [%s] error: %v", p.Name(), err)
return nil, errors.New("send NewUserConn request to plugin error") return nil, errors.New("send NewUserConn request to plugin error")
} }
if res.Reject { if res.Reject {

View File

@@ -75,7 +75,7 @@ func NewGateway(
sshConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { sshConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
authorizedKeysMap, err := loadAuthorizedKeysFromFile(cfg.AuthorizedKeysFile) authorizedKeysMap, err := loadAuthorizedKeysFromFile(cfg.AuthorizedKeysFile)
if err != nil { if err != nil {
log.Error("load authorized keys file error: %v", err) log.Errorf("load authorized keys file error: %v", err)
return nil, fmt.Errorf("internal error") return nil, fmt.Errorf("internal error")
} }
@@ -120,7 +120,7 @@ func (g *Gateway) handleConn(conn net.Conn) {
return return
} }
if err := ts.Run(); err != nil { if err := ts.Run(); err != nil {
log.Error("ssh tunnel server run error: %v", err) log.Errorf("ssh tunnel server run error: %v", err)
} }
} }

View File

@@ -20,12 +20,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"slices"
"strings" "strings"
"sync" "sync"
"time" "time"
libio "github.com/fatedier/golib/io" libio "github.com/fatedier/golib/io"
"github.com/samber/lo"
"github.com/spf13/cobra" "github.com/spf13/cobra"
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@@ -123,7 +123,7 @@ func (s *TunnelServer) Run() error {
// join workConn and ssh channel // join workConn and ssh channel
c, err := s.openConn(addr) c, err := s.openConn(addr)
if err != nil { if err != nil {
log.Trace("open conn error: %v", err) log.Tracef("open conn error: %v", err)
workConn.Close() workConn.Close()
return false return false
} }
@@ -167,7 +167,7 @@ func (s *TunnelServer) Run() error {
if ps, err := s.waitProxyStatusReady(pc.GetBaseConfig().Name, time.Second); err != nil { if ps, err := s.waitProxyStatusReady(pc.GetBaseConfig().Name, time.Second); err != nil {
s.writeToClient(err.Error()) s.writeToClient(err.Error())
log.Warn("wait proxy status ready error: %v", err) log.Warnf("wait proxy status ready error: %v", err)
} else { } else {
// success // success
s.writeToClient(createSuccessInfo(clientCfg.User, pc, ps)) s.writeToClient(createSuccessInfo(clientCfg.User, pc, ps))
@@ -175,7 +175,7 @@ func (s *TunnelServer) Run() error {
} }
s.vc.Close() s.vc.Close()
log.Trace("ssh tunnel connection from %v closed", sshConn.RemoteAddr()) log.Tracef("ssh tunnel connection from %v closed", sshConn.RemoteAddr())
s.closeDoneChOnce.Do(func() { s.closeDoneChOnce.Do(func() {
_ = sshConn.Close() _ = sshConn.Close()
close(s.doneCh) close(s.doneCh)
@@ -262,7 +262,7 @@ func (s *TunnelServer) parseClientAndProxyConfigurer(_ *tcpipForward, extraPaylo
} }
proxyType := strings.TrimSpace(args[0]) proxyType := strings.TrimSpace(args[0])
supportTypes := []string{"tcp", "http", "https", "tcpmux", "stcp"} supportTypes := []string{"tcp", "http", "https", "tcpmux", "stcp"}
if !lo.Contains(supportTypes, proxyType) { if !slices.Contains(supportTypes, proxyType) {
return nil, nil, helpMessage, fmt.Errorf("invalid proxy type: %s, support types: %v", proxyType, supportTypes) return nil, nil, helpMessage, fmt.Errorf("invalid proxy type: %s, support types: %v", proxyType, supportTypes)
} }
pc := v1.NewProxyConfigurerByType(v1.ProxyType(proxyType)) pc := v1.NewProxyConfigurerByType(v1.ProxyType(proxyType))
@@ -363,11 +363,13 @@ func (s *TunnelServer) waitProxyStatusReady(name string, timeout time.Duration)
timer := time.NewTimer(timeout) timer := time.NewTimer(timeout)
defer timer.Stop() defer timer.Stop()
statusExporter := s.vc.Service().StatusExporter()
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
ps, err := s.vc.Service().GetProxyStatus(name) ps, ok := statusExporter.GetProxyStatus(name)
if err != nil { if !ok {
continue continue
} }
switch ps.Phase { switch ps.Phase {

View File

@@ -15,78 +15,95 @@
package log package log
import ( import (
"fmt" "bytes"
"os"
"github.com/fatedier/beego/logs" "github.com/fatedier/golib/log"
) )
// Log is the under log object var (
var Log *logs.BeeLogger TraceLevel = log.TraceLevel
DebugLevel = log.DebugLevel
InfoLevel = log.InfoLevel
WarnLevel = log.WarnLevel
ErrorLevel = log.ErrorLevel
)
var Logger *log.Logger
func init() { func init() {
Log = logs.NewLogger(200) Logger = log.New(
Log.EnableFuncCallDepth(true) log.WithCaller(true),
Log.SetLogFuncCallDepth(Log.GetLogFuncCallDepth() + 1) log.AddCallerSkip(1),
log.WithLevel(log.InfoLevel),
)
} }
func InitLog(logFile string, logLevel string, maxdays int64, disableLogColor bool) { func InitLogger(logPath string, levelStr string, maxDays int, disableLogColor bool) {
SetLogFile(logFile, maxdays, disableLogColor) options := []log.Option{}
SetLogLevel(logLevel) if logPath == "console" {
} if !disableLogColor {
options = append(options,
// SetLogFile to configure log params log.WithOutput(log.NewConsoleWriter(log.ConsoleConfig{
func SetLogFile(logFile string, maxdays int64, disableLogColor bool) { Colorful: true,
if logFile == "console" { }, os.Stdout)),
params := "" )
if disableLogColor {
params = `{"color": false}`
} }
_ = Log.SetLogger("console", params)
} else { } else {
params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays) writer := log.NewRotateFileWriter(log.RotateFileConfig{
_ = Log.SetLogger("file", params) FileName: logPath,
Mode: log.RotateFileModeDaily,
MaxDays: maxDays,
})
writer.Init()
options = append(options, log.WithOutput(writer))
}
level, err := log.ParseLevel(levelStr)
if err != nil {
level = log.InfoLevel
}
options = append(options, log.WithLevel(level))
Logger = Logger.WithOptions(options...)
}
func Errorf(format string, v ...interface{}) {
Logger.Errorf(format, v...)
}
func Warnf(format string, v ...interface{}) {
Logger.Warnf(format, v...)
}
func Infof(format string, v ...interface{}) {
Logger.Infof(format, v...)
}
func Debugf(format string, v ...interface{}) {
Logger.Debugf(format, v...)
}
func Tracef(format string, v ...interface{}) {
Logger.Tracef(format, v...)
}
func Logf(level log.Level, offset int, format string, v ...interface{}) {
Logger.Logf(level, offset, format, v...)
}
type WriteLogger struct {
level log.Level
offset int
}
func NewWriteLogger(level log.Level, offset int) *WriteLogger {
return &WriteLogger{
level: level,
offset: offset,
} }
} }
// SetLogLevel set log level, default is warning func (w *WriteLogger) Write(p []byte) (n int, err error) {
// value: error, warning, info, debug, trace Logger.Log(w.level, w.offset, string(bytes.TrimRight(p, "\n")))
func SetLogLevel(logLevel string) { return len(p), nil
var level int
switch logLevel {
case "error":
level = 3
case "warn":
level = 4
case "info":
level = 6
case "debug":
level = 7
case "trace":
level = 8
default:
level = 4 // warning
}
Log.SetLevel(level)
}
// wrap log
func Error(format string, v ...interface{}) {
Log.Error(format, v...)
}
func Warn(format string, v ...interface{}) {
Log.Warn(format, v...)
}
func Info(format string, v ...interface{}) {
Log.Info(format, v...)
}
func Debug(format string, v ...interface{}) {
Log.Debug(format, v...)
}
func Trace(format string, v ...interface{}) {
Log.Trace(format, v...)
} }

View File

@@ -76,9 +76,11 @@ type WrapReadWriteCloserConn struct {
io.ReadWriteCloser io.ReadWriteCloser
underConn net.Conn underConn net.Conn
remoteAddr net.Addr
} }
func WrapReadWriteCloserToConn(rwc io.ReadWriteCloser, underConn net.Conn) net.Conn { func WrapReadWriteCloserToConn(rwc io.ReadWriteCloser, underConn net.Conn) *WrapReadWriteCloserConn {
return &WrapReadWriteCloserConn{ return &WrapReadWriteCloserConn{
ReadWriteCloser: rwc, ReadWriteCloser: rwc,
underConn: underConn, underConn: underConn,
@@ -92,7 +94,14 @@ func (conn *WrapReadWriteCloserConn) LocalAddr() net.Addr {
return (*net.TCPAddr)(nil) return (*net.TCPAddr)(nil)
} }
func (conn *WrapReadWriteCloserConn) SetRemoteAddr(addr net.Addr) {
conn.remoteAddr = addr
}
func (conn *WrapReadWriteCloserConn) RemoteAddr() net.Addr { func (conn *WrapReadWriteCloserConn) RemoteAddr() net.Addr {
if conn.remoteAddr != nil {
return conn.remoteAddr
}
if conn.underConn != nil { if conn.underConn != nil {
return conn.underConn.RemoteAddr() return conn.underConn.RemoteAddr()
} }

View File

@@ -5,11 +5,11 @@ import (
"net" "net"
"net/url" "net/url"
libdial "github.com/fatedier/golib/net/dial" libnet "github.com/fatedier/golib/net"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libdial.AfterHookFunc { func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libnet.AfterHookFunc {
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) { return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
if enableTLS && !disableCustomTLSHeadByte { if enableTLS && !disableCustomTLSHeadByte {
_, err := c.Write([]byte{byte(FRPTLSHeadByte)}) _, err := c.Write([]byte{byte(FRPTLSHeadByte)})
@@ -21,7 +21,7 @@ func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) li
} }
} }
func DialHookWebsocket(protocol string, host string) libdial.AfterHookFunc { func DialHookWebsocket(protocol string, host string) libnet.AfterHookFunc {
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) { return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
if protocol != "wss" { if protocol != "wss" {
protocol = "ws" protocol = "ws"

View File

@@ -26,8 +26,8 @@ func SetDefaultDNSAddress(dnsAddress string) {
// Change default dns server // Change default dns server
net.DefaultResolver = &net.Resolver{ net.DefaultResolver = &net.Resolver{
PreferGo: true, PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) { Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
return net.Dial("udp", dnsAddress) return net.Dial(network, dnsAddress)
}, },
} }
} }

View File

@@ -24,30 +24,6 @@ import (
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
) )
type HTTPAuthWrapper struct {
h http.Handler
user string
passwd string
}
func NewHTTPBasicAuthWrapper(h http.Handler, user, passwd string) http.Handler {
return &HTTPAuthWrapper{
h: h,
user: user,
passwd: passwd,
}
}
func (aw *HTTPAuthWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user, passwd, hasAuth := r.BasicAuth()
if (aw.user == "" && aw.passwd == "") || (hasAuth && user == aw.user && passwd == aw.passwd) {
aw.h.ServeHTTP(w, r)
} else {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
type HTTPAuthMiddleware struct { type HTTPAuthMiddleware struct {
user string user string
passwd string passwd string

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"net" "net"
kcp "github.com/fatedier/kcp-go" kcp "github.com/xtaci/kcp-go/v5"
) )
type KCPListener struct { type KCPListener struct {
@@ -85,7 +85,15 @@ func (l *KCPListener) Addr() net.Addr {
} }
func NewKCPConnFromUDP(conn *net.UDPConn, connected bool, raddr string) (net.Conn, error) { func NewKCPConnFromUDP(conn *net.UDPConn, connected bool, raddr string) (net.Conn, error) {
kcpConn, err := kcp.NewConnEx(1, connected, raddr, nil, 10, 3, conn) udpAddr, err := net.ResolveUDPAddr("udp", raddr)
if err != nil {
return nil, err
}
var pConn net.PacketConn = conn
if connected {
pConn = &ConnectedUDPConn{conn}
}
kcpConn, err := kcp.NewConn3(1, udpAddr, nil, 10, 3, pConn)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -4,7 +4,7 @@ import (
"errors" "errors"
"net" "net"
"net/http" "net/http"
"strconv" "time"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
@@ -40,8 +40,9 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
})) }))
wl.server = &http.Server{ wl.server = &http.Server{
Addr: ln.Addr().String(), Addr: ln.Addr().String(),
Handler: muxer, Handler: muxer,
ReadHeaderTimeout: 60 * time.Second,
} }
go func() { go func() {
@@ -50,15 +51,6 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
return return
} }
func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error) {
tcpLn, err := net.Listen("tcp", net.JoinHostPort(bindAddr, strconv.Itoa(bindPort)))
if err != nil {
return nil, err
}
l := NewWebsocketListener(tcpLn)
return l, nil
}
func (p *WebsocketListener) Accept() (net.Conn, error) { func (p *WebsocketListener) Accept() (net.Conn, error) {
c, ok := <-p.acceptCh c, ok := <-p.acceptCh
if !ok { if !ok {

22
pkg/util/system/system.go Normal file
View File

@@ -0,0 +1,22 @@
// Copyright 2024 The frp Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !android
package system
// EnableCompatibilityMode enables compatibility mode for different system.
// For example, on Android, the inability to obtain the correct time zone will result in incorrect log time output.
func EnableCompatibilityMode() {
}

View File

@@ -0,0 +1,70 @@
// Copyright 2024 The frp Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package system
import (
"context"
"net"
"os/exec"
"strings"
"time"
)
func EnableCompatibilityMode() {
fixTimezone()
fixDNSResolver()
}
// fixTimezone is used to try our best to fix timezone issue on some Android devices.
func fixTimezone() {
out, err := exec.Command("/system/bin/getprop", "persist.sys.timezone").Output()
if err != nil {
return
}
loc, err := time.LoadLocation(strings.TrimSpace(string(out)))
if err != nil {
return
}
time.Local = loc
}
// fixDNSResolver will first attempt to resolve google.com to check if the current DNS is available.
// If it is not available, it will default to using 8.8.8.8 as the DNS server.
// This is a workaround for the issue that golang can't get the default DNS servers on Android.
func fixDNSResolver() {
// First, we attempt to resolve a domain. If resolution is successful, no modifications are necessary.
// In real-world scenarios, users may have already configured /etc/resolv.conf, or compiled directly
// in the Android environment instead of using cross-platform compilation, so this issue does not arise.
if net.DefaultResolver != nil {
timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
_, err := net.DefaultResolver.LookupHost(timeoutCtx, "google.com")
if err == nil {
return
}
}
// If the resolution fails, use 8.8.8.8 as the DNS server.
// Note: If there are other methods to obtain the default DNS servers, the default DNS servers should be used preferentially.
net.DefaultResolver = &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
if addr == "127.0.0.1:53" || addr == "[::1]:53" {
addr = "8.8.8.8:53"
}
var d net.Dialer
return d.DialContext(ctx, network, addr)
},
}
}

View File

@@ -20,7 +20,7 @@ import (
"crypto/subtle" "crypto/subtle"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
mathrand "math/rand" mathrand "math/rand/v2"
"net" "net"
"strconv" "strconv"
"strings" "strings"
@@ -47,16 +47,6 @@ func RandIDWithLen(idLen int) (id string, err error) {
return id[:idLen], nil return id[:idLen], nil
} }
// RandIDWithRandLen return a rand string with length between [start, end).
func RandIDWithRandLen(start, end int) (id string, err error) {
if start >= end {
err = fmt.Errorf("start should be less than end")
return
}
idLen := mathrand.Intn(end-start) + start
return RandIDWithLen(idLen)
}
func GetAuthKey(token string, timestamp int64) (key string) { func GetAuthKey(token string, timestamp int64) (key string) {
md5Ctx := md5.New() md5Ctx := md5.New()
md5Ctx.Write([]byte(token)) md5Ctx.Write([]byte(token))
@@ -134,7 +124,7 @@ func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Durati
if max <= min { if max <= min {
n = min n = min
} else { } else {
n = mathrand.Int63n(max-min) + min n = mathrand.Int64N(max-min) + min
} }
d := duration * time.Duration(n) / time.Duration(1000) d := duration * time.Duration(n) / time.Duration(1000)
time.Sleep(d) time.Sleep(d)

View File

@@ -14,48 +14,6 @@ func TestRandId(t *testing.T) {
assert.Equal(16, len(id)) assert.Equal(16, len(id))
} }
func TestRandIDWithRandLen(t *testing.T) {
tests := []struct {
name string
start int
end int
expectErr bool
}{
{
name: "start and end are equal",
start: 5,
end: 5,
expectErr: true,
},
{
name: "start is less than end",
start: 5,
end: 10,
expectErr: false,
},
{
name: "start is greater than end",
start: 10,
end: 5,
expectErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
id, err := RandIDWithRandLen(tt.start, tt.end)
if tt.expectErr {
assert.Error(err)
} else {
assert.NoError(err)
assert.GreaterOrEqual(len(id), tt.start)
assert.Less(len(id), tt.end)
}
})
}
}
func TestGetAuthKey(t *testing.T) { func TestGetAuthKey(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
key := GetAuthKey("1234", 1488720000) key := GetAuthKey("1234", 1488720000)

View File

@@ -14,34 +14,8 @@
package version package version
import ( var version = "0.58.1"
"strconv"
"strings"
)
var version = "0.54.0"
func Full() string { func Full() string {
return version return version
} }
func getSubVersion(v string, position int) int64 {
arr := strings.Split(v, ".")
if len(arr) < 3 {
return 0
}
res, _ := strconv.ParseInt(arr[position], 10, 64)
return res
}
func Proto(v string) int64 {
return getSubVersion(v, 0)
}
func Major(v string) int64 {
return getSubVersion(v, 1)
}
func Minor(v string) int64 {
return getSubVersion(v, 2)
}

View File

@@ -1,53 +0,0 @@
// Copyright 2016 fatedier, fatedier@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package version
import (
"fmt"
"strconv"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestFull(t *testing.T) {
assert := assert.New(t)
version := Full()
arr := strings.Split(version, ".")
assert.Equal(3, len(arr))
proto, err := strconv.ParseInt(arr[0], 10, 64)
assert.NoError(err)
assert.True(proto >= 0)
major, err := strconv.ParseInt(arr[1], 10, 64)
assert.NoError(err)
assert.True(major >= 0)
minor, err := strconv.ParseInt(arr[2], 10, 64)
assert.NoError(err)
assert.True(minor >= 0)
}
func TestVersion(t *testing.T) {
assert := assert.New(t)
proto := Proto(Full())
major := Major(Full())
minor := Minor(Full())
parseVersion := fmt.Sprintf("%d.%d.%d", proto, major, minor)
version := Full()
assert.Equal(parseVersion, version)
}

View File

@@ -15,12 +15,11 @@
package vhost package vhost
import ( import (
"bytes"
"context" "context"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"log" stdlog "log"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@@ -32,7 +31,7 @@ import (
"github.com/fatedier/golib/pool" "github.com/fatedier/golib/pool"
httppkg "github.com/fatedier/frp/pkg/util/http" httppkg "github.com/fatedier/frp/pkg/util/http"
logpkg "github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
) )
var ErrNoRouteFound = errors.New("no route found") var ErrNoRouteFound = errors.New("no route found")
@@ -59,13 +58,14 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
proxy := &httputil.ReverseProxy{ proxy := &httputil.ReverseProxy{
// Modify incoming requests by route policies. // Modify incoming requests by route policies.
Rewrite: func(r *httputil.ProxyRequest) { Rewrite: func(r *httputil.ProxyRequest) {
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
r.SetXForwarded() r.SetXForwarded()
req := r.Out req := r.Out
req.URL.Scheme = "http" req.URL.Scheme = "http"
reqRouteInfo := req.Context().Value(RouteInfoKey).(*RequestRouteInfo) reqRouteInfo := req.Context().Value(RouteInfoKey).(*RequestRouteInfo)
oldHost, _ := httppkg.CanonicalHost(reqRouteInfo.Host) originalHost, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
rc := rp.GetRouteConfig(oldHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser) rc := req.Context().Value(RouteConfigKey).(*RouteConfig)
if rc != nil { if rc != nil {
if rc.RewriteHost != "" { if rc.RewriteHost != "" {
req.Host = rc.RewriteHost req.Host = rc.RewriteHost
@@ -76,8 +76,8 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
// ignore error here, it will use CreateConnFn instead later // ignore error here, it will use CreateConnFn instead later
endpoint, _ = rc.ChooseEndpointFn() endpoint, _ = rc.ChooseEndpointFn()
reqRouteInfo.Endpoint = endpoint reqRouteInfo.Endpoint = endpoint
logpkg.Trace("choose endpoint name [%s] for http request host [%s] path [%s] httpuser [%s]", log.Tracef("choose endpoint name [%s] for http request host [%s] path [%s] httpuser [%s]",
endpoint, oldHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser) endpoint, originalHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
} }
// Set {domain}.{location}.{routeByHTTPUser}.{endpoint} as URL host here to let http transport reuse connections. // Set {domain}.{location}.{routeByHTTPUser}.{endpoint} as URL host here to let http transport reuse connections.
req.URL.Host = rc.Domain + "." + req.URL.Host = rc.Domain + "." +
@@ -92,6 +92,15 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
req.URL.Host = req.Host req.URL.Host = req.Host
} }
}, },
ModifyResponse: func(r *http.Response) error {
rc := r.Request.Context().Value(RouteConfigKey).(*RouteConfig)
if rc != nil {
for k, v := range rc.ResponseHeaders {
r.Header.Set(k, v)
}
}
return nil
},
// Create a connection to one proxy routed by route policy. // Create a connection to one proxy routed by route policy.
Transport: &http.Transport{ Transport: &http.Transport{
ResponseHeaderTimeout: rp.responseHeaderTimeout, ResponseHeaderTimeout: rp.responseHeaderTimeout,
@@ -115,10 +124,16 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
return nil, nil return nil, nil
}, },
}, },
BufferPool: newWrapPool(), BufferPool: pool.NewBuffer(32 * 1024),
ErrorLog: log.New(newWrapLogger(), "", 0), ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) { ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
logpkg.Warn("do http proxy request [host: %s] error: %v", req.Host, err) log.Logf(log.WarnLevel, 1, "do http proxy request [host: %s] error: %v", req.Host, err)
if err != nil {
if e, ok := err.(net.Error); ok && e.Timeout() {
rw.WriteHeader(http.StatusGatewayTimeout)
return
}
}
rw.WriteHeader(http.StatusNotFound) rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write(getNotFoundPageContent()) _, _ = rw.Write(getNotFoundPageContent())
}, },
@@ -145,20 +160,12 @@ func (rp *HTTPReverseProxy) UnRegister(routeCfg RouteConfig) {
func (rp *HTTPReverseProxy) GetRouteConfig(domain, location, routeByHTTPUser string) *RouteConfig { func (rp *HTTPReverseProxy) GetRouteConfig(domain, location, routeByHTTPUser string) *RouteConfig {
vr, ok := rp.getVhost(domain, location, routeByHTTPUser) vr, ok := rp.getVhost(domain, location, routeByHTTPUser)
if ok { if ok {
logpkg.Debug("get new HTTP request host [%s] path [%s] httpuser [%s]", domain, location, routeByHTTPUser) log.Debugf("get new HTTP request host [%s] path [%s] httpuser [%s]", domain, location, routeByHTTPUser)
return vr.payload.(*RouteConfig) return vr.payload.(*RouteConfig)
} }
return nil return nil
} }
func (rp *HTTPReverseProxy) GetHeaders(domain, location, routeByHTTPUser string) (headers map[string]string) {
vr, ok := rp.getVhost(domain, location, routeByHTTPUser)
if ok {
headers = vr.payload.(*RouteConfig).Headers
}
return
}
// CreateConnection create a new connection by route config // CreateConnection create a new connection by route config
func (rp *HTTPReverseProxy) CreateConnection(reqRouteInfo *RequestRouteInfo, byEndpoint bool) (net.Conn, error) { func (rp *HTTPReverseProxy) CreateConnection(reqRouteInfo *RequestRouteInfo, byEndpoint bool) (net.Conn, error) {
host, _ := httppkg.CanonicalHost(reqRouteInfo.Host) host, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
@@ -299,8 +306,13 @@ func (rp *HTTPReverseProxy) injectRequestInfoToCtx(req *http.Request) *http.Requ
RemoteAddr: req.RemoteAddr, RemoteAddr: req.RemoteAddr,
URLHost: req.URL.Host, URLHost: req.URL.Host,
} }
originalHost, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
rc := rp.GetRouteConfig(originalHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
newctx := req.Context() newctx := req.Context()
newctx = context.WithValue(newctx, RouteInfoKey, reqRouteInfo) newctx = context.WithValue(newctx, RouteInfoKey, reqRouteInfo)
newctx = context.WithValue(newctx, RouteConfigKey, rc)
return req.Clone(newctx) return req.Clone(newctx)
} }
@@ -321,20 +333,3 @@ func (rp *HTTPReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)
rp.proxy.ServeHTTP(rw, newreq) rp.proxy.ServeHTTP(rw, newreq)
} }
} }
type wrapPool struct{}
func newWrapPool() *wrapPool { return &wrapPool{} }
func (p *wrapPool) Get() []byte { return pool.GetBuf(32 * 1024) }
func (p *wrapPool) Put(buf []byte) { pool.PutBuf(buf) }
type wrapLogger struct{}
func newWrapLogger() *wrapLogger { return &wrapLogger{} }
func (l *wrapLogger) Write(p []byte) (n int, err error) {
logpkg.Warn("%s", string(bytes.TrimRight(p, "\n")))
return len(p), nil
}

View File

@@ -12,7 +12,7 @@ import (
func TestGetHTTPSHostname(t *testing.T) { func TestGetHTTPSHostname(t *testing.T) {
require := require.New(t) require := require.New(t)
l, err := net.Listen("tcp", ":") l, err := net.Listen("tcp", "127.0.0.1:")
require.NoError(err) require.NoError(err)
defer l.Close() defer l.Close()

View File

@@ -20,7 +20,7 @@ import (
"net/http" "net/http"
"os" "os"
logpkg "github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
) )
@@ -58,7 +58,7 @@ func getNotFoundPageContent() []byte {
if NotFoundPagePath != "" { if NotFoundPagePath != "" {
buf, err = os.ReadFile(NotFoundPagePath) buf, err = os.ReadFile(NotFoundPagePath)
if err != nil { if err != nil {
logpkg.Warn("read custom 404 page error: %v", err) log.Warnf("read custom 404 page error: %v", err)
buf = []byte(NotFound) buf = []byte(NotFound)
} }
} else { } else {

View File

@@ -1,8 +1,9 @@
package vhost package vhost
import ( import (
"cmp"
"errors" "errors"
"sort" "slices"
"strings" "strings"
"sync" "sync"
) )
@@ -58,7 +59,10 @@ func (r *Routers) Add(domain, location, httpUser string, payload interface{}) er
payload: payload, payload: payload,
} }
vrs = append(vrs, vr) vrs = append(vrs, vr)
sort.Sort(sort.Reverse(ByLocation(vrs)))
slices.SortFunc(vrs, func(a, b *Router) int {
return -cmp.Compare(a.location, b.location)
})
routersByHTTPUser[httpUser] = vrs routersByHTTPUser[httpUser] = vrs
r.indexByDomain[domain] = routersByHTTPUser r.indexByDomain[domain] = routersByHTTPUser
@@ -130,18 +134,3 @@ func (r *Routers) exist(host, path, httpUser string) (route *Router, exist bool)
} }
return return
} }
// sort by location
type ByLocation []*Router
func (a ByLocation) Len() int {
return len(a)
}
func (a ByLocation) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a ByLocation) Less(i, j int) bool {
return strings.Compare(a[i].location, a[j].location) < 0
}

View File

@@ -29,7 +29,8 @@ import (
type RouteInfo string type RouteInfo string
const ( const (
RouteInfoKey RouteInfo = "routeInfo" RouteInfoKey RouteInfo = "routeInfo"
RouteConfigKey RouteInfo = "routeConfig"
) )
type RequestRouteInfo struct { type RequestRouteInfo struct {
@@ -113,6 +114,7 @@ type RouteConfig struct {
Username string Username string
Password string Password string
Headers map[string]string Headers map[string]string
ResponseHeaders map[string]string
RouteByHTTPUser string RouteByHTTPUser string
CreateConnFn CreateConnFunc CreateConnFn CreateConnFunc
@@ -203,7 +205,7 @@ func (v *Muxer) handle(c net.Conn) {
sConn, reqInfoMap, err := v.vhostFunc(c) sConn, reqInfoMap, err := v.vhostFunc(c)
if err != nil { if err != nil {
log.Debug("get hostname from http/https request error: %v", err) log.Debugf("get hostname from http/https request error: %v", err)
_ = c.Close() _ = c.Close()
return return
} }
@@ -213,7 +215,7 @@ func (v *Muxer) handle(c net.Conn) {
httpUser := reqInfoMap["HTTPUser"] httpUser := reqInfoMap["HTTPUser"]
l, ok := v.getListener(name, path, httpUser) l, ok := v.getListener(name, path, httpUser)
if !ok { if !ok {
log.Debug("http request for host [%s] path [%s] httpUser [%s] not found", name, path, httpUser) log.Debugf("http request for host [%s] path [%s] httpUser [%s] not found", name, path, httpUser)
v.failHook(sConn) v.failHook(sConn)
return return
} }
@@ -221,7 +223,7 @@ func (v *Muxer) handle(c net.Conn) {
xl := xlog.FromContextSafe(l.ctx) xl := xlog.FromContextSafe(l.ctx)
if v.successHook != nil { if v.successHook != nil {
if err := v.successHook(c, reqInfoMap); err != nil { if err := v.successHook(c, reqInfoMap); err != nil {
xl.Info("success func failure on vhost connection: %v", err) xl.Infof("success func failure on vhost connection: %v", err)
_ = c.Close() _ = c.Close()
return return
} }
@@ -232,7 +234,7 @@ func (v *Muxer) handle(c net.Conn) {
if l.mux.checkAuth != nil && l.username != "" { if l.mux.checkAuth != nil && l.username != "" {
ok, err := l.mux.checkAuth(c, l.username, l.password, reqInfoMap) ok, err := l.mux.checkAuth(c, l.username, l.password, reqInfoMap)
if !ok || err != nil { if !ok || err != nil {
xl.Debug("auth failed for user: %s", l.username) xl.Debugf("auth failed for user: %s", l.username)
_ = c.Close() _ = c.Close()
return return
} }
@@ -244,12 +246,12 @@ func (v *Muxer) handle(c net.Conn) {
} }
c = sConn c = sConn
xl.Debug("new request host [%s] path [%s] httpUser [%s]", name, path, httpUser) xl.Debugf("new request host [%s] path [%s] httpUser [%s]", name, path, httpUser)
err = errors.PanicToError(func() { err = errors.PanicToError(func() {
l.accept <- c l.accept <- c
}) })
if err != nil { if err != nil {
xl.Warn("listener is already closed, ignore this request") xl.Warnf("listener is already closed, ignore this request")
} }
} }
@@ -278,10 +280,10 @@ func (l *Listener) Accept() (net.Conn, error) {
if l.mux.rewriteHost != nil { if l.mux.rewriteHost != nil {
sConn, err := l.mux.rewriteHost(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.Warnf("host header rewrite failed: %v", err)
return nil, fmt.Errorf("host header rewrite failed") return nil, fmt.Errorf("host header rewrite failed")
} }
xl.Debug("rewrite host to [%s] success", l.rewriteHost) xl.Debugf("rewrite host to [%s] success", l.rewriteHost)
conn = sConn conn = sConn
} }
return netpkg.NewContextConn(l.ctx, conn), nil return netpkg.NewContextConn(l.ctx, conn), nil

View File

@@ -15,8 +15,7 @@
package wait package wait
import ( import (
"math/rand" "math/rand/v2"
"sync"
"time" "time"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
@@ -174,21 +173,3 @@ func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
return period return period
}), true, stopCh) }), true, stopCh)
} }
func MergeAndCloseOnAnyStopChannel[T any](upstreams ...<-chan T) <-chan T {
out := make(chan T)
closeOnce := sync.Once{}
for _, upstream := range upstreams {
ch := upstream
go func() {
select {
case <-ch:
closeOnce.Do(func() {
close(out)
})
case <-out:
}
}()
}
return out
}

View File

@@ -15,7 +15,8 @@
package xlog package xlog
import ( import (
"sort" "cmp"
"slices"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
) )
@@ -77,8 +78,8 @@ func (l *Logger) AddPrefix(prefix LogPrefix) *Logger {
} }
func (l *Logger) renderPrefixString() { func (l *Logger) renderPrefixString() {
sort.SliceStable(l.prefixes, func(i, j int) bool { slices.SortStableFunc(l.prefixes, func(a, b LogPrefix) int {
return l.prefixes[i].Priority < l.prefixes[j].Priority return cmp.Compare(a.Priority, b.Priority)
}) })
l.prefixString = "" l.prefixString = ""
for _, v := range l.prefixes { for _, v := range l.prefixes {
@@ -93,22 +94,22 @@ func (l *Logger) Spawn() *Logger {
return nl return nl
} }
func (l *Logger) Error(format string, v ...interface{}) { func (l *Logger) Errorf(format string, v ...interface{}) {
log.Log.Error(l.prefixString+format, v...) log.Logger.Errorf(l.prefixString+format, v...)
} }
func (l *Logger) Warn(format string, v ...interface{}) { func (l *Logger) Warnf(format string, v ...interface{}) {
log.Log.Warn(l.prefixString+format, v...) log.Logger.Warnf(l.prefixString+format, v...)
} }
func (l *Logger) Info(format string, v ...interface{}) { func (l *Logger) Infof(format string, v ...interface{}) {
log.Log.Info(l.prefixString+format, v...) log.Logger.Infof(l.prefixString+format, v...)
} }
func (l *Logger) Debug(format string, v ...interface{}) { func (l *Logger) Debugf(format string, v ...interface{}) {
log.Log.Debug(l.prefixString+format, v...) log.Logger.Debugf(l.prefixString+format, v...)
} }
func (l *Logger) Trace(format string, v ...interface{}) { func (l *Logger) Tracef(format string, v ...interface{}) {
log.Log.Trace(l.prefixString+format, v...) log.Logger.Tracef(l.prefixString+format, v...)
} }

View File

@@ -224,7 +224,7 @@ func (ctl *Control) Close() error {
func (ctl *Control) Replaced(newCtl *Control) { func (ctl *Control) Replaced(newCtl *Control) {
xl := ctl.xl xl := ctl.xl
xl.Info("Replaced by client [%s]", newCtl.runID) xl.Infof("Replaced by client [%s]", newCtl.runID)
ctl.runID = "" ctl.runID = ""
ctl.conn.Close() ctl.conn.Close()
} }
@@ -233,17 +233,17 @@ func (ctl *Control) RegisterWorkConn(conn net.Conn) error {
xl := ctl.xl xl := ctl.xl
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
xl.Error("panic error: %v", err) xl.Errorf("panic error: %v", err)
xl.Error(string(debug.Stack())) xl.Errorf(string(debug.Stack()))
} }
}() }()
select { select {
case ctl.workConnCh <- conn: case ctl.workConnCh <- conn:
xl.Debug("new work connection registered") xl.Debugf("new work connection registered")
return nil return nil
default: default:
xl.Debug("work connection pool is full, discarding") xl.Debugf("work connection pool is full, discarding")
return fmt.Errorf("work connection pool is full, discarding") return fmt.Errorf("work connection pool is full, discarding")
} }
} }
@@ -256,8 +256,8 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
xl := ctl.xl xl := ctl.xl
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
xl.Error("panic error: %v", err) xl.Errorf("panic error: %v", err)
xl.Error(string(debug.Stack())) xl.Errorf(string(debug.Stack()))
} }
}() }()
@@ -269,7 +269,7 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
err = pkgerr.ErrCtlClosed err = pkgerr.ErrCtlClosed
return return
} }
xl.Debug("get work connection from pool") xl.Debugf("get work connection from pool")
default: default:
// no work connections available in the poll, send message to frpc to get more // no work connections available in the poll, send message to frpc to get more
if err := ctl.msgDispatcher.Send(&msg.ReqWorkConn{}); err != nil { if err := ctl.msgDispatcher.Send(&msg.ReqWorkConn{}); err != nil {
@@ -280,13 +280,13 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
case workConn, ok = <-ctl.workConnCh: case workConn, ok = <-ctl.workConnCh:
if !ok { if !ok {
err = pkgerr.ErrCtlClosed err = pkgerr.ErrCtlClosed
xl.Warn("no work connections available, %v", err) xl.Warnf("no work connections available, %v", err)
return return
} }
case <-time.After(time.Duration(ctl.serverCfg.UserConnTimeout) * time.Second): case <-time.After(time.Duration(ctl.serverCfg.UserConnTimeout) * time.Second):
err = fmt.Errorf("timeout trying to get work connection") err = fmt.Errorf("timeout trying to get work connection")
xl.Warn("%v", err) xl.Warnf("%v", err)
return return
} }
} }
@@ -297,20 +297,18 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
} }
func (ctl *Control) heartbeatWorker() { func (ctl *Control) heartbeatWorker() {
xl := ctl.xl if ctl.serverCfg.Transport.HeartbeatTimeout <= 0 {
return
// Don't need application heartbeat if TCPMux is enabled,
// yamux will do same thing.
// TODO(fatedier): let default HeartbeatTimeout to -1 if TCPMux is enabled. Users can still set it to positive value to enable it.
if !lo.FromPtr(ctl.serverCfg.Transport.TCPMux) && ctl.serverCfg.Transport.HeartbeatTimeout > 0 {
go wait.Until(func() {
if time.Since(ctl.lastPing.Load().(time.Time)) > time.Duration(ctl.serverCfg.Transport.HeartbeatTimeout)*time.Second {
xl.Warn("heartbeat timeout")
ctl.conn.Close()
return
}
}, time.Second, ctl.doneCh)
} }
xl := ctl.xl
go wait.Until(func() {
if time.Since(ctl.lastPing.Load().(time.Time)) > time.Duration(ctl.serverCfg.Transport.HeartbeatTimeout)*time.Second {
xl.Warnf("heartbeat timeout")
ctl.conn.Close()
return
}
}, time.Second, ctl.doneCh)
} }
// block until Control closed // block until Control closed
@@ -356,7 +354,7 @@ func (ctl *Control) worker() {
} }
metrics.Server.CloseClient() metrics.Server.CloseClient()
xl.Info("client exit success") xl.Infof("client exit success")
close(ctl.doneCh) close(ctl.doneCh)
} }
@@ -393,12 +391,12 @@ func (ctl *Control) handleNewProxy(m msg.Message) {
ProxyName: inMsg.ProxyName, ProxyName: inMsg.ProxyName,
} }
if err != nil { if err != nil {
xl.Warn("new proxy [%s] type [%s] error: %v", inMsg.ProxyName, inMsg.ProxyType, err) xl.Warnf("new proxy [%s] type [%s] error: %v", inMsg.ProxyName, inMsg.ProxyType, err)
resp.Error = util.GenerateResponseErrorString(fmt.Sprintf("new proxy [%s] error", inMsg.ProxyName), resp.Error = util.GenerateResponseErrorString(fmt.Sprintf("new proxy [%s] error", inMsg.ProxyName),
err, lo.FromPtr(ctl.serverCfg.DetailedErrorsToClient)) err, lo.FromPtr(ctl.serverCfg.DetailedErrorsToClient))
} else { } else {
resp.RemoteAddr = remoteAddr resp.RemoteAddr = remoteAddr
xl.Info("new proxy [%s] type [%s] success", inMsg.ProxyName, inMsg.ProxyType) xl.Infof("new proxy [%s] type [%s] success", inMsg.ProxyName, inMsg.ProxyType)
metrics.Server.NewProxy(inMsg.ProxyName, inMsg.ProxyType) metrics.Server.NewProxy(inMsg.ProxyName, inMsg.ProxyType)
} }
_ = ctl.msgDispatcher.Send(resp) _ = ctl.msgDispatcher.Send(resp)
@@ -422,14 +420,14 @@ func (ctl *Control) handlePing(m msg.Message) {
err = ctl.authVerifier.VerifyPing(inMsg) err = ctl.authVerifier.VerifyPing(inMsg)
} }
if err != nil { if err != nil {
xl.Warn("received invalid ping: %v", err) xl.Warnf("received invalid ping: %v", err)
_ = ctl.msgDispatcher.Send(&msg.Pong{ _ = ctl.msgDispatcher.Send(&msg.Pong{
Error: util.GenerateResponseErrorString("invalid ping", err, lo.FromPtr(ctl.serverCfg.DetailedErrorsToClient)), Error: util.GenerateResponseErrorString("invalid ping", err, lo.FromPtr(ctl.serverCfg.DetailedErrorsToClient)),
}) })
return return
} }
ctl.lastPing.Store(time.Now()) ctl.lastPing.Store(time.Now())
xl.Debug("receive heartbeat") xl.Debugf("receive heartbeat")
_ = ctl.msgDispatcher.Send(&msg.Pong{}) _ = ctl.msgDispatcher.Send(&msg.Pong{})
} }
@@ -452,7 +450,7 @@ func (ctl *Control) handleCloseProxy(m msg.Message) {
xl := ctl.xl xl := ctl.xl
inMsg := m.(*msg.CloseProxy) inMsg := m.(*msg.CloseProxy)
_ = ctl.CloseProxy(inMsg) _ = ctl.CloseProxy(inMsg)
xl.Info("close proxy [%s] success", inMsg.ProxyName) xl.Infof("close proxy [%s] success", inMsg.ProxyName)
} }
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) { func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {

View File

@@ -15,9 +15,10 @@
package server package server
import ( import (
"cmp"
"encoding/json" "encoding/json"
"net/http" "net/http"
"sort" "slices"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
@@ -31,8 +32,6 @@ import (
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
) )
// TODO(fatedier): add an API to clean status of all offline proxies.
type GeneralResponse struct { type GeneralResponse struct {
Code int Code int
Msg string Msg string
@@ -98,14 +97,14 @@ func (svr *Service) healthz(w http.ResponseWriter, _ *http.Request) {
func (svr *Service) apiServerInfo(w http.ResponseWriter, r *http.Request) { func (svr *Service) apiServerInfo(w http.ResponseWriter, r *http.Request) {
res := GeneralResponse{Code: 200} res := GeneralResponse{Code: 200}
defer func() { defer func() {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Infof("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Infof("Http request: [%s]", r.URL.Path)
serverStats := mem.StatsCollector.GetServer() serverStats := mem.StatsCollector.GetServer()
svrResp := serverInfoResp{ svrResp := serverInfoResp{
Version: version.Full(), Version: version.Full(),
@@ -145,7 +144,8 @@ type TCPOutConf struct {
type TCPMuxOutConf struct { type TCPMuxOutConf struct {
BaseOutConf BaseOutConf
v1.DomainConfig v1.DomainConfig
Multiplexer string `json:"multiplexer"` Multiplexer string `json:"multiplexer"`
RouteByHTTPUser string `json:"routeByHTTPUser"`
} }
type UDPOutConf struct { type UDPOutConf struct {
@@ -218,18 +218,18 @@ func (svr *Service) apiProxyByType(w http.ResponseWriter, r *http.Request) {
proxyType := params["type"] proxyType := params["type"]
defer func() { defer func() {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Infof("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Infof("Http request: [%s]", r.URL.Path)
proxyInfoResp := GetProxyInfoResp{} proxyInfoResp := GetProxyInfoResp{}
proxyInfoResp.Proxies = svr.getProxyStatsByType(proxyType) proxyInfoResp.Proxies = svr.getProxyStatsByType(proxyType)
sort.Slice(proxyInfoResp.Proxies, func(i, j int) bool { slices.SortFunc(proxyInfoResp.Proxies, func(a, b *ProxyStatsInfo) int {
return proxyInfoResp.Proxies[i].Name < proxyInfoResp.Proxies[j].Name return cmp.Compare(a.Name, b.Name)
}) })
buf, _ := json.Marshal(&proxyInfoResp) buf, _ := json.Marshal(&proxyInfoResp)
@@ -244,12 +244,12 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt
if pxy, ok := svr.pxyManager.GetByName(ps.Name); ok { if pxy, ok := svr.pxyManager.GetByName(ps.Name); ok {
content, err := json.Marshal(pxy.GetConfigurer()) content, err := json.Marshal(pxy.GetConfigurer())
if err != nil { if err != nil {
log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err) log.Warnf("marshal proxy [%s] conf info error: %v", ps.Name, err)
continue continue
} }
proxyInfo.Conf = getConfByType(ps.Type) proxyInfo.Conf = getConfByType(ps.Type)
if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil { if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err) log.Warnf("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
continue continue
} }
proxyInfo.Status = "online" proxyInfo.Status = "online"
@@ -290,13 +290,13 @@ func (svr *Service) apiProxyByTypeAndName(w http.ResponseWriter, r *http.Request
name := params["name"] name := params["name"]
defer func() { defer func() {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Infof("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Infof("Http request: [%s]", r.URL.Path)
var proxyStatsResp GetProxyStatsResp var proxyStatsResp GetProxyStatsResp
proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name) proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name)
@@ -318,14 +318,14 @@ func (svr *Service) getProxyStatsByTypeAndName(proxyType string, proxyName strin
if pxy, ok := svr.pxyManager.GetByName(proxyName); ok { if pxy, ok := svr.pxyManager.GetByName(proxyName); ok {
content, err := json.Marshal(pxy.GetConfigurer()) content, err := json.Marshal(pxy.GetConfigurer())
if err != nil { if err != nil {
log.Warn("marshal proxy [%s] conf info error: %v", ps.Name, err) log.Warnf("marshal proxy [%s] conf info error: %v", ps.Name, err)
code = 400 code = 400
msg = "parse conf error" msg = "parse conf error"
return return
} }
proxyInfo.Conf = getConfByType(ps.Type) proxyInfo.Conf = getConfByType(ps.Type)
if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil { if err = json.Unmarshal(content, &proxyInfo.Conf); err != nil {
log.Warn("unmarshal proxy [%s] conf info error: %v", ps.Name, err) log.Warnf("unmarshal proxy [%s] conf info error: %v", ps.Name, err)
code = 400 code = 400
msg = "parse conf error" msg = "parse conf error"
return return
@@ -358,13 +358,13 @@ func (svr *Service) apiProxyTraffic(w http.ResponseWriter, r *http.Request) {
name := params["name"] name := params["name"]
defer func() { defer func() {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Infof("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Infof("Http request: [%s]", r.URL.Path)
trafficResp := GetProxyTrafficResp{} trafficResp := GetProxyTrafficResp{}
trafficResp.Name = name trafficResp.Name = name
@@ -386,9 +386,9 @@ func (svr *Service) apiProxyTraffic(w http.ResponseWriter, r *http.Request) {
func (svr *Service) deleteProxies(w http.ResponseWriter, r *http.Request) { func (svr *Service) deleteProxies(w http.ResponseWriter, r *http.Request) {
res := GeneralResponse{Code: 200} res := GeneralResponse{Code: 200}
log.Info("Http request: [%s]", r.URL.Path) log.Infof("Http request: [%s]", r.URL.Path)
defer func() { defer func() {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Infof("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
_, _ = w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
@@ -402,5 +402,5 @@ func (svr *Service) deleteProxies(w http.ResponseWriter, r *http.Request) {
return return
} }
cleared, total := mem.StatsCollector.ClearOfflineProxies() cleared, total := mem.StatsCollector.ClearOfflineProxies()
log.Info("cleared [%d] offline proxies, total [%d] proxies", cleared, total) log.Infof("cleared [%d] offline proxies, total [%d] proxies", cleared, total)
} }

View File

@@ -58,6 +58,7 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
RewriteHost: pxy.cfg.HostHeaderRewrite, RewriteHost: pxy.cfg.HostHeaderRewrite,
RouteByHTTPUser: pxy.cfg.RouteByHTTPUser, RouteByHTTPUser: pxy.cfg.RouteByHTTPUser,
Headers: pxy.cfg.RequestHeaders.Set, Headers: pxy.cfg.RequestHeaders.Set,
ResponseHeaders: pxy.cfg.ResponseHeaders.Set,
Username: pxy.cfg.HTTPUser, Username: pxy.cfg.HTTPUser,
Password: pxy.cfg.HTTPPassword, Password: pxy.cfg.HTTPPassword,
CreateConnFn: pxy.GetRealConn, CreateConnFn: pxy.GetRealConn,
@@ -107,7 +108,7 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
}) })
} }
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPPort)) addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPPort))
xl.Info("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]", xl.Infof("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]",
routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser) routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser)
} }
} }
@@ -140,7 +141,7 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
} }
addrs = append(addrs, util.CanonicalAddr(tmpRouteConfig.Domain, pxy.serverCfg.VhostHTTPPort)) addrs = append(addrs, util.CanonicalAddr(tmpRouteConfig.Domain, pxy.serverCfg.VhostHTTPPort))
xl.Info("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]", xl.Infof("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]",
routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser) routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser)
} }
} }
@@ -152,7 +153,7 @@ func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err err
xl := pxy.xl xl := pxy.xl
rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr) rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr)
if errRet != nil { if errRet != nil {
xl.Warn("resolve TCP addr [%s] error: %v", remoteAddr, errRet) xl.Warnf("resolve TCP addr [%s] error: %v", remoteAddr, errRet)
// we do not return error here since remoteAddr is not necessary for proxies without proxy protocol enabled // we do not return error here since remoteAddr is not necessary for proxies without proxy protocol enabled
} }
@@ -166,7 +167,7 @@ func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err err
if pxy.cfg.Transport.UseEncryption { if pxy.cfg.Transport.UseEncryption {
rwc, err = libio.WithEncryption(rwc, []byte(pxy.serverCfg.Auth.Token)) rwc, err = libio.WithEncryption(rwc, []byte(pxy.serverCfg.Auth.Token))
if err != nil { if err != nil {
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }

View File

@@ -64,7 +64,7 @@ func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) {
err = errRet err = errRet
return return
} }
xl.Info("https proxy listen for host [%s]", routeConfig.Domain) xl.Infof("https proxy listen for host [%s]", routeConfig.Domain)
pxy.listeners = append(pxy.listeners, l) pxy.listeners = append(pxy.listeners, l)
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPSPort)) addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPSPort))
} }
@@ -76,7 +76,7 @@ func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) {
err = errRet err = errRet
return return
} }
xl.Info("https proxy listen for host [%s]", routeConfig.Domain) xl.Infof("https proxy listen for host [%s]", routeConfig.Domain)
pxy.listeners = append(pxy.listeners, l) pxy.listeners = append(pxy.listeners, l)
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPSPort)) addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPSPort))
} }

View File

@@ -112,7 +112,7 @@ func (pxy *BaseProxy) GetConfigurer() v1.ProxyConfigurer {
func (pxy *BaseProxy) Close() { func (pxy *BaseProxy) Close() {
xl := xlog.FromContextSafe(pxy.ctx) xl := xlog.FromContextSafe(pxy.ctx)
xl.Info("proxy closing") xl.Infof("proxy closing")
for _, l := range pxy.listeners { for _, l := range pxy.listeners {
l.Close() l.Close()
} }
@@ -125,10 +125,10 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
// try all connections from the pool // try all connections from the pool
for i := 0; i < pxy.poolCount+1; i++ { for i := 0; i < pxy.poolCount+1; i++ {
if workConn, err = pxy.getWorkConnFn(); err != nil { if workConn, err = pxy.getWorkConnFn(); err != nil {
xl.Warn("failed to get work connection: %v", err) xl.Warnf("failed to get work connection: %v", err)
return return
} }
xl.Debug("get a new work connection: [%s]", workConn.RemoteAddr().String()) xl.Debugf("get a new work connection: [%s]", workConn.RemoteAddr().String())
xl.Spawn().AppendPrefix(pxy.GetName()) xl.Spawn().AppendPrefix(pxy.GetName())
workConn = netpkg.NewContextConn(pxy.ctx, workConn) workConn = netpkg.NewContextConn(pxy.ctx, workConn)
@@ -158,7 +158,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
Error: "", Error: "",
}) })
if err != nil { if err != nil {
xl.Warn("failed to send message to work connection from pool: %v, times: %d", err, i) xl.Warnf("failed to send message to work connection from pool: %v, times: %d", err, i)
workConn.Close() workConn.Close()
} else { } else {
break break
@@ -166,7 +166,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
} }
if err != nil { if err != nil {
xl.Error("try to get work connection failed in the end") xl.Errorf("try to get work connection failed in the end")
return return
} }
return return
@@ -193,15 +193,15 @@ func (pxy *BaseProxy) startCommonTCPListenersHandler() {
if max := 1 * time.Second; tempDelay > max { if max := 1 * time.Second; tempDelay > max {
tempDelay = max tempDelay = max
} }
xl.Info("met temporary error: %s, sleep for %s ...", err, tempDelay) xl.Infof("met temporary error: %s, sleep for %s ...", err, tempDelay)
time.Sleep(tempDelay) time.Sleep(tempDelay)
continue continue
} }
xl.Warn("listener is closed: %s", err) xl.Warnf("listener is closed: %s", err)
return return
} }
xl.Info("get a user connection [%s]", c.RemoteAddr().String()) xl.Infof("get a user connection [%s]", c.RemoteAddr().String())
go pxy.handleUserTCPConnection(c) go pxy.handleUserTCPConnection(c)
} }
}(listener) }(listener)
@@ -225,7 +225,7 @@ func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
} }
_, err := rc.PluginManager.NewUserConn(content) _, err := rc.PluginManager.NewUserConn(content)
if err != nil { if err != nil {
xl.Warn("the user conn [%s] was rejected, err:%v", content.RemoteAddr, err) xl.Warnf("the user conn [%s] was rejected, err:%v", content.RemoteAddr, err)
return return
} }
@@ -237,12 +237,12 @@ func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
defer workConn.Close() defer workConn.Close()
var local io.ReadWriteCloser = workConn var local io.ReadWriteCloser = workConn
xl.Trace("handler user tcp connection, use_encryption: %t, use_compression: %t", xl.Tracef("handler user tcp connection, use_encryption: %t, use_compression: %t",
cfg.Transport.UseEncryption, cfg.Transport.UseCompression) cfg.Transport.UseEncryption, cfg.Transport.UseCompression)
if cfg.Transport.UseEncryption { if cfg.Transport.UseEncryption {
local, err = libio.WithEncryption(local, []byte(serverCfg.Auth.Token)) local, err = libio.WithEncryption(local, []byte(serverCfg.Auth.Token))
if err != nil { if err != nil {
xl.Error("create encryption stream error: %v", err) xl.Errorf("create encryption stream error: %v", err)
return return
} }
} }
@@ -258,7 +258,7 @@ func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
}) })
} }
xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(), xl.Debugf("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())
name := pxy.GetName() name := pxy.GetName()
@@ -268,7 +268,7 @@ func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
metrics.Server.CloseConnection(name, proxyType) metrics.Server.CloseConnection(name, proxyType)
metrics.Server.AddTrafficIn(name, proxyType, inCount) metrics.Server.AddTrafficIn(name, proxyType, inCount)
metrics.Server.AddTrafficOut(name, proxyType, outCount) metrics.Server.AddTrafficOut(name, proxyType, outCount)
xl.Debug("join connections closed") xl.Debugf("join connections closed")
} }
type Options struct { type Options struct {

View File

@@ -53,7 +53,7 @@ func (pxy *STCPProxy) Run() (remoteAddr string, err error) {
return return
} }
pxy.listeners = append(pxy.listeners, listener) pxy.listeners = append(pxy.listeners, listener)
xl.Info("stcp proxy custom listen success") xl.Infof("stcp proxy custom listen success")
pxy.startCommonTCPListenersHandler() pxy.startCommonTCPListenersHandler()
return return

View File

@@ -53,7 +53,7 @@ func (pxy *SUDPProxy) Run() (remoteAddr string, err error) {
return return
} }
pxy.listeners = append(pxy.listeners, listener) pxy.listeners = append(pxy.listeners, listener)
xl.Info("sudp proxy custom listen success") xl.Infof("sudp proxy custom listen success")
pxy.startCommonTCPListenersHandler() pxy.startCommonTCPListenersHandler()
return return

View File

@@ -62,7 +62,7 @@ func (pxy *TCPProxy) Run() (remoteAddr string, err error) {
}() }()
pxy.realBindPort = realBindPort pxy.realBindPort = realBindPort
pxy.listeners = append(pxy.listeners, l) pxy.listeners = append(pxy.listeners, l)
xl.Info("tcp proxy listen port [%d] in group [%s]", pxy.cfg.RemotePort, pxy.cfg.LoadBalancer.Group) xl.Infof("tcp proxy listen port [%d] in group [%s]", pxy.cfg.RemotePort, pxy.cfg.LoadBalancer.Group)
} else { } else {
pxy.realBindPort, err = pxy.rc.TCPPortManager.Acquire(pxy.name, pxy.cfg.RemotePort) pxy.realBindPort, err = pxy.rc.TCPPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
if err != nil { if err != nil {
@@ -79,7 +79,7 @@ func (pxy *TCPProxy) Run() (remoteAddr string, err error) {
return return
} }
pxy.listeners = append(pxy.listeners, listener) pxy.listeners = append(pxy.listeners, listener)
xl.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort) xl.Infof("tcp proxy listen port [%d]", pxy.cfg.RemotePort)
} }
pxy.cfg.RemotePort = pxy.realBindPort pxy.cfg.RemotePort = pxy.realBindPort

View File

@@ -65,7 +65,7 @@ func (pxy *TCPMuxProxy) httpConnectListen(
if err != nil { if err != nil {
return nil, err return nil, err
} }
pxy.xl.Info("tcpmux httpconnect multiplexer listens for host [%s], group [%s] routeByHTTPUser [%s]", pxy.xl.Infof("tcpmux httpconnect multiplexer listens for host [%s], group [%s] routeByHTTPUser [%s]",
domain, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser) domain, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser)
pxy.listeners = append(pxy.listeners, l) pxy.listeners = append(pxy.listeners, l)
return append(addrs, util.CanonicalAddr(domain, pxy.serverCfg.TCPMuxHTTPConnectPort)), nil return append(addrs, util.CanonicalAddr(domain, pxy.serverCfg.TCPMuxHTTPConnectPort)), nil

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