Compare commits

..

135 Commits

Author SHA1 Message Date
fatedier
31b44c1feb Merge pull request #4700 from fatedier/dev
bump version
2025-03-07 17:26:55 +08:00
fatedier
773169e0c4 update version (#4699) 2025-03-07 17:22:51 +08:00
fatedier
9757a351c6 fix golangci lint config (#4698) 2025-03-07 16:56:08 +08:00
fatedier
1e8db66743 update Release.md (#4668) 2025-02-12 12:30:37 +08:00
fatedier
e0dd947e6a frps: release resources in service.Close() (#4667) 2025-02-12 12:22:57 +08:00
ubergeek77
8b86e1473c Fix ports not being released on Service.Close() (#4666) 2025-02-12 11:28:30 +08:00
hansmi
b8d3ace113 Use text/template instead of html/template for config pre-processing (#4656) 2025-02-07 11:33:11 +08:00
Jeb.Wang
450b8393bc Fix goroutine leaks
* Fix goroutine leaks
2025-01-16 10:50:57 +08:00
fatedier
27db6217ec frpc: support metadatas and annotations in frpc proxy commands (#4623) 2025-01-06 14:22:57 +08:00
Andreas Deininger
6542dcd4ed Fix typos (#4615) 2025-01-02 11:33:56 +08:00
Gabriel Marin
092e5d3f94 client, pkg, server, test: replaced 'interface{}' with 'any' (#4611) 2025-01-02 11:24:08 +08:00
fatedier
01fed8d1a9 Update stale workflow (#4600) 2024-12-19 18:13:25 +08:00
fatedier
2a7aa69890 Merge pull request #4590 from fatedier/dev
bump version
2024-12-16 19:41:22 +08:00
fatedier
f47d8ab97f update Release.md (#4589) 2024-12-16 19:33:58 +08:00
Sword
bb912d6c37 enable h2c for vhost server (#4582) 2024-12-13 14:37:07 +08:00
Roy Reznik
c73096f2bf Upgrade packages to resolve CVE-2024-53259 (#4577) 2024-12-10 20:07:38 +08:00
Guiwoo Park
0358113948 samber lo version up (#4569) 2024-12-02 11:56:52 +08:00
fatedier
8593eff752 update sponsor info (#4545) 2024-11-20 15:14:51 +08:00
fatedier
dff56cb0ca update .golangci.yml (#4527) 2024-11-07 17:14:40 +08:00
fatedier
4383756fd4 frps: add support for quic-bind-port parameter in frps (#4519) 2024-10-30 15:12:31 +08:00
fatedier
6ba849fc75 readme: update sponsor (#4504) 2024-10-22 10:48:24 +08:00
fatedier
9d5638cae6 update Release.md (#4500) 2024-10-18 12:31:55 +08:00
fatedier
62352c7ba5 dockerfiles: add tzdata (#4499) 2024-10-18 12:03:17 +08:00
fatedier
4bbec09d57 Merge pull request #4496 from fatedier/dev
bump version
2024-10-17 17:28:10 +08:00
fatedier
f7a06cbe61 use go1.23 (#4495) 2024-10-17 17:22:41 +08:00
fatedier
3a08c2aeb0 conf: fix example for tls2raw (#4494) 2024-10-17 16:27:41 +08:00
0x7fff
b14192a8d3 feat: bump (#4490)
Co-authored-by: Coder123 <coder123@example.com>
2024-10-15 10:55:56 +08:00
RobKenis
2466e65f43 support multiple subjects in oidc ping (#4475)
Resolves: #4466
2024-10-12 18:52:47 +08:00
fatedier
2855ac71e3 frpc visitor: add --server-user option to specify server proxy username (#4477) 2024-10-09 14:04:30 +08:00
拾光,
fe4ca1b54e Update README_zh.md (#4421)
修复爱发电链接无法访问问题
2024-09-06 11:41:11 +08:00
crystalstall
edd7cf8967 chore: fix function name (#4416)
Signed-off-by: crystalstall <crystalruby@qq.com>
2024-09-06 11:39:22 +08:00
fatedier
ccfe8c97f4 Merge pull request #4392 from fatedier/dev
bump version
2024-08-19 13:47:36 +08:00
Wang Xiang
03c8d7bf96 bump kcp-go to add linux/loong64 support (#4384) 2024-08-16 22:24:27 +08:00
fatedier
2dcdb24cc4 replace github.com/templexxx/xorsimd to the new version (#4373) 2024-08-07 11:18:17 +08:00
Wang Xiang
d47e138bc9 bump templexxx/cpu version and add support for linux/loong64 (#4367)
* support linux/loong64

* bump cpu version
2024-08-06 17:33:14 +08:00
fatedier
f1fb2d721a update .github/FUNDING.yml (#4365) 2024-08-02 17:04:59 +08:00
fatedier
ae73ec2fed added a 30s timeout for frpc subcommands to avoid long delays (#4359) 2024-07-30 18:12:22 +08:00
Yurun
e8045194cd Fix loginFailExit = false bug (#4354)
* Fixed the issue that when loginFailExit = false, the frpc stop command cannot be stopped correctly if the server is not successfully connected after startup

* Update Release.md
2024-07-30 11:19:26 +08:00
fatedier
69cc422edf client plugin: added plugin tls2raw (#4341) 2024-07-25 14:28:17 +08:00
fatedier
243ca994e0 Merge pull request #4324 from fatedier/dev
bump version
2024-07-09 10:55:15 +08:00
fatedier
b4d5d8c756 plugin https2http&https2https: return 421 if host not match sni (#4323) 2024-07-09 10:50:16 +08:00
fatedier
c6f9d8d403 update sponsors (#4303) 2024-06-26 14:51:34 +08:00
fatedier
939c490768 Add http2http client plugin with hostHeaderRewrite and requestHeaders support (#4275) 2024-06-12 17:30:10 +08:00
fatedier
f390e4a401 add sponsor (#4265) 2024-06-05 16:53:29 +08:00
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
a5b7abfc8b Merge pull request #4060 from fatedier/dev
bump version
2024-03-12 18:11:37 +08:00
fatedier
1e650ea9a7 Merge pull request #4056 from fatedier/dev
bump version
2024-03-12 16:55:25 +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
123 changed files with 1828 additions and 792 deletions

View File

@@ -2,7 +2,7 @@ version: 2
jobs: jobs:
go-version-latest: go-version-latest:
docker: docker:
- image: cimg/go:1.22-node - image: cimg/go:1.23-node
resource_class: large resource_class: large
steps: steps:
- checkout - checkout

2
.github/FUNDING.yml vendored
View File

@@ -1,4 +1,4 @@
# These are supported funding model platforms # These are supported funding model platforms
github: [fatedier] github: [fatedier]
custom: ["https://afdian.net/a/fatedier"] custom: ["https://afdian.com/a/fatedier"]

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

@@ -17,13 +17,13 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: '1.22' go-version: '1.23'
cache: false 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.56 version: v1.61
# Optional: golangci-lint command line arguments. # Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0 # args: --issues-exit-code=0

View File

@@ -15,7 +15,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.22' go-version: '1.23'
- name: Make All - name: Make All
run: | run: |

View File

@@ -21,14 +21,14 @@ jobs:
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v9
with: with:
stale-issue-message: 'Issues go stale after 21d of inactivity. Stale issues rot after an additional 7d of inactivity and eventually close.' stale-issue-message: 'Issues go stale after 14d of inactivity. Stale issues rot after an additional 3d of inactivity and eventually close.'
stale-pr-message: "PRs go stale after 21d of inactivity. Stale PRs rot after an additional 7d of inactivity and eventually close." stale-pr-message: "PRs go stale after 14d of inactivity. Stale PRs rot after an additional 3d of inactivity and eventually close."
stale-issue-label: 'lifecycle/stale' stale-issue-label: 'lifecycle/stale'
exempt-issue-labels: 'bug,doc,enhancement,future,proposal,question,testing,todo,easy,help wanted,assigned' exempt-issue-labels: 'bug,doc,enhancement,future,proposal,question,testing,todo,easy,help wanted,assigned'
stale-pr-label: 'lifecycle/stale' stale-pr-label: 'lifecycle/stale'
exempt-pr-labels: 'bug,doc,enhancement,future,proposal,question,testing,todo,easy,help wanted,assigned' exempt-pr-labels: 'bug,doc,enhancement,future,proposal,question,testing,todo,easy,help wanted,assigned'
days-before-stale: 21 days-before-stale: 14
days-before-close: 7 days-before-close: 3
debug-only: ${{ github.event.inputs.debug-only }} debug-only: ${{ github.event.inputs.debug-only }}
exempt-all-pr-milestones: true exempt-all-pr-milestones: true
exempt-all-pr-assignees: true exempt-all-pr-assignees: true

View File

@@ -1,37 +1,20 @@
service: service:
golangci-lint-version: 1.56.x # use the fixed version to not introduce new linters unexpectedly golangci-lint-version: 1.61.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
deadline: 20m timeout: 20m
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
enable: enable:
- unused - unused
- errcheck - errcheck
- exportloopref - copyloopvar
- gocritic - gocritic
- gofumpt - gofumpt
- goimports - goimports
@@ -65,7 +48,8 @@ linters-settings:
check-blank: false check-blank: false
govet: govet:
# report about shadowed variables # report about shadowed variables
check-shadowing: false disable:
- shadow
maligned: maligned:
# print struct with more effective memory layout or not, false by default # print struct with more effective memory layout or not, false by default
suggest-new: true suggest-new: true
@@ -103,13 +87,11 @@ linters-settings:
severity: "low" severity: "low"
confidence: "low" confidence: "low"
excludes: excludes:
- G102
- G112
- G306
- G401 - G401
- G402 - G402
- G404 - G404
- G501 - G501
- G115 # integer overflow conversion
issues: issues:
# List of regexps of issue texts to exclude, empty list by default. # List of regexps of issue texts to exclude, empty list by default.
@@ -136,6 +118,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

@@ -2,22 +2,34 @@ 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 linux:loong64 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)" -tags frpc -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)" -tags frps -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

@@ -7,15 +7,30 @@
[README](README.md) | [中文文档](README_zh.md) [README](README.md) | [中文文档](README_zh.md)
## Sponsors
frp is an open source project with its ongoing development made possible entirely by the support of our awesome sponsors. If you'd like to join them, please consider [sponsoring frp's development](https://github.com/sponsors/fatedier).
<h3 align="center">Gold Sponsors</h3> <h3 align="center">Gold Sponsors</h3>
<!--gold sponsors start--> <!--gold sponsors start-->
<p align="center"> <p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank"> <a href="https://jb.gg/frp" target="_blank">
<img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png"> <img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_jetbrains.jpg">
</a> </a>
<a>&nbsp</a> </p>
<p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
</a>
</p>
<p align="center">
<a href="https://github.com/daytonaio/daytona" target="_blank"> <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"> <img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_daytona.png">
</a>
</p>
<p align="center">
<a href="https://github.com/beclab/Olares" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_olares.jpeg">
</a> </a>
</p> </p>
<!--gold sponsors end--> <!--gold sponsors end-->
@@ -78,9 +93,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)
* [Related Projects](#related-projects)
* [Contributing](#contributing) * [Contributing](#contributing)
* [Donation](#donation) * [Donation](#donation)
* [GitHub Sponsors](#github-sponsors) * [GitHub Sponsors](#github-sponsors)
@@ -350,7 +367,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"
@@ -803,7 +819,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
@@ -982,7 +998,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
@@ -994,15 +1010,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`.
@@ -1158,6 +1175,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.
@@ -1225,6 +1260,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.
## Related 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

@@ -9,15 +9,30 @@
frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。
## Sponsors
frp 是一个完全开源的项目,我们的开发工作完全依靠赞助者们的支持。如果你愿意加入他们的行列,请考虑 [赞助 frp 的开发](https://github.com/sponsors/fatedier)。
<h3 align="center">Gold Sponsors</h3> <h3 align="center">Gold Sponsors</h3>
<!--gold sponsors start--> <!--gold sponsors start-->
<p align="center"> <p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank"> <a href="https://jb.gg/frp" target="_blank">
<img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png"> <img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_jetbrains.jpg">
</a> </a>
<a>&nbsp</a> </p>
<p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
</a>
</p>
<p align="center">
<a href="https://github.com/daytonaio/daytona" target="_blank"> <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"> <img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_daytona.png">
</a>
</p>
<p align="center">
<a href="https://github.com/beclab/Olares" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_olares.jpeg">
</a> </a>
</p> </p>
<!--gold sponsors end--> <!--gold sponsors end-->
@@ -72,7 +87,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 左右),支持常用的部分功能,适用于资源有限的设备。
## 赞助 ## 赞助
@@ -84,7 +104,7 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
您可以通过 [GitHub Sponsors](https://github.com/sponsors/fatedier) 赞助我们。 您可以通过 [GitHub Sponsors](https://github.com/sponsors/fatedier) 赞助我们。
国内用户可以通过 [爱发电](https://afdian.net/a/fatedier) 赞助我们。 国内用户可以通过 [爱发电](https://afdian.com/a/fatedier) 赞助我们。
企业赞助者可以将贵公司的 Logo 以及链接放置在项目 README 文件中。 企业赞助者可以将贵公司的 Logo 以及链接放置在项目 README 文件中。
@@ -93,7 +113,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,22 +1,7 @@
### Features ### Features
* Support range ports mapping in TOML/YAML/JSON configuration file by using go template syntax. * Support metadatas and annotations in frpc proxy commands.
For example:
```
{{- range $_, $v := parseNumberRangePair "6000-6006,6007" "6000-6006,6007" }}
[[proxies]]
name = "tcp-{{ $v.First }}"
type = "tcp"
localPort = {{ $v.First }}
remotePort = {{ $v.Second }}
{{- end }}
```
This will create 8 proxies such as `tcp-6000, tcp-6001, ... tcp-6007`.
### Fixes ### Fixes
* Fix the issue of incorrect interval time for rotating the log by day. * Properly release resources in service.Close() to prevent resource leaks when used as a library.
* Disable quic-go's ECN support by default. It may cause issues on certain operating systems.

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-Q42Pu2_S.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

@@ -253,7 +253,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
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.Warnf("%s", res.Msg) log.Warnf("%s", res.Msg)

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"
@@ -169,44 +169,44 @@ func (c *defaultConnectorImpl) realConnect() (net.Conn, error) {
} }
} }
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.Errorf("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"
@@ -232,14 +230,12 @@ func (ctl *Control) registerMsgHandlers() {
ctl.msgDispatcher.RegisterHandler(&msg.Pong{}, ctl.handlePong) ctl.msgDispatcher.RegisterHandler(&msg.Pong{}, ctl.handlePong)
} }
// headerWorker sends heartbeat to server and check heartbeat timeout. // heartbeatWorker sends heartbeat to server and check heartbeat timeout.
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.Debugf("send heartbeat to server") xl.Debugf("send heartbeat to server")
pingMsg := &msg.Ping{} pingMsg := &msg.Ping{}
@@ -263,10 +259,8 @@ 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.Warnf("heartbeat timeout") xl.Warnf("heartbeat timeout")

View File

@@ -8,7 +8,7 @@ import (
var ErrPayloadType = errors.New("error payload type") var ErrPayloadType = errors.New("error payload type")
type Handler func(payload interface{}) error type Handler func(payload any) error
type StartProxyPayload struct { type StartProxyPayload struct {
NewProxyMsg *msg.NewProxy NewProxyMsg *msg.NewProxy

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,
@@ -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"
@@ -158,46 +158,48 @@ 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.Debugf("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(pxy.ctx, remote, workConn, &extraInfo)
xl.Debugf("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()

View File

@@ -96,7 +96,7 @@ func (pm *Manager) HandleWorkConn(name string, workConn net.Conn, m *msg.StartWo
} }
} }
func (pm *Manager) HandleEvent(payload interface{}) error { func (pm *Manager) HandleEvent(payload any) error {
var m msg.Message var m msg.Message
switch e := payload.(type) { switch e := payload.(type) {
case *event.StartProxyPayload: case *event.StartProxyPayload:

View File

@@ -137,7 +137,7 @@ func (pw *Wrapper) SetRunningStatus(remoteAddr string, respErr string) error {
pw.Phase = ProxyPhaseStartErr pw.Phase = ProxyPhaseStartErr
pw.Err = respErr pw.Err = respErr
pw.lastStartErr = time.Now() pw.lastStartErr = time.Now()
return fmt.Errorf(pw.Err) return fmt.Errorf("%s", pw.Err)
} }
if err := pw.pxy.Run(); err != nil { if err := pw.pxy.Run(); err != nil {

View File

@@ -169,6 +169,15 @@ func (svr *Service) Run(ctx context.Context) error {
netpkg.SetDefaultDNSAddress(svr.common.DNSServer) netpkg.SetDefaultDNSAddress(svr.common.DNSServer)
} }
if svr.webServer != nil {
go func() {
log.Infof("admin server listen on %s", svr.webServer.Address())
if err := svr.webServer.Run(); err != nil {
log.Warnf("admin server exit with error: %v", err)
}
}()
}
// first login to frps // first login to frps
svr.loopLoginUntilSuccess(10*time.Second, lo.FromPtr(svr.common.LoginFailExit)) svr.loopLoginUntilSuccess(10*time.Second, lo.FromPtr(svr.common.LoginFailExit))
if svr.ctl == nil { if svr.ctl == nil {
@@ -179,14 +188,6 @@ func (svr *Service) Run(ctx context.Context) error {
go svr.keepControllerWorking() go svr.keepControllerWorking()
if svr.webServer != nil {
go func() {
log.Infof("admin server listen on %s", svr.webServer.Address())
if err := svr.webServer.Run(); err != nil {
log.Warnf("admin server exit with error: %v", err)
}
}()
}
<-svr.ctx.Done() <-svr.ctx.Done()
svr.stop() svr.stop()
return nil return nil
@@ -380,18 +381,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

@@ -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

@@ -15,9 +15,11 @@
package sub package sub
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"strings" "strings"
"time"
"github.com/rodaine/table" "github.com/rodaine/table"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -27,24 +29,24 @@ import (
clientsdk "github.com/fatedier/frp/pkg/sdk/client" clientsdk "github.com/fatedier/frp/pkg/sdk/client"
) )
var adminAPITimeout = 30 * time.Second
func init() { func init() {
rootCmd.AddCommand(NewAdminCommand( commands := []struct {
"reload", name string
"Hot-Reload frpc configuration", description string
ReloadHandler, handler func(*v1.ClientCommonConfig) error
)) }{
{"reload", "Hot-Reload frpc configuration", ReloadHandler},
{"status", "Overview of all proxies status", StatusHandler},
{"stop", "Stop the running frpc", StopHandler},
}
rootCmd.AddCommand(NewAdminCommand( for _, cmdConfig := range commands {
"status", cmd := NewAdminCommand(cmdConfig.name, cmdConfig.description, cmdConfig.handler)
"Overview of all proxies status", cmd.Flags().DurationVar(&adminAPITimeout, "api-timeout", adminAPITimeout, "Timeout for admin API calls")
StatusHandler, rootCmd.AddCommand(cmd)
)) }
rootCmd.AddCommand(NewAdminCommand(
"stop",
"Stop the running frpc",
StopHandler,
))
} }
func NewAdminCommand(name, short string, handler func(*v1.ClientCommonConfig) error) *cobra.Command { func NewAdminCommand(name, short string, handler func(*v1.ClientCommonConfig) error) *cobra.Command {
@@ -73,7 +75,9 @@ func NewAdminCommand(name, short string, handler func(*v1.ClientCommonConfig) er
func ReloadHandler(clientCfg *v1.ClientCommonConfig) error { func ReloadHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port) client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password) client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
if err := client.Reload(strictConfigMode); err != nil { ctx, cancel := context.WithTimeout(context.Background(), adminAPITimeout)
defer cancel()
if err := client.Reload(ctx, strictConfigMode); err != nil {
return err return err
} }
fmt.Println("reload success") fmt.Println("reload success")
@@ -83,7 +87,9 @@ func ReloadHandler(clientCfg *v1.ClientCommonConfig) error {
func StatusHandler(clientCfg *v1.ClientCommonConfig) error { func StatusHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port) client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password) client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
res, err := client.GetAllProxyStatus() ctx, cancel := context.WithTimeout(context.Background(), adminAPITimeout)
defer cancel()
res, err := client.GetAllProxyStatus(ctx)
if err != nil { if err != nil {
return err return err
} }
@@ -109,7 +115,9 @@ func StatusHandler(clientCfg *v1.ClientCommonConfig) error {
func StopHandler(clientCfg *v1.ClientCommonConfig) error { func StopHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port) client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password) client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
if err := client.Stop(); err != nil { ctx, cancel := context.WithTimeout(context.Background(), adminAPITimeout)
defer cancel()
if err := client.Stop(ctx); err != nil {
return err return err
} }
fmt.Println("stop success") fmt.Println("stop success")

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

@@ -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"
@@ -310,6 +315,26 @@ localAddr = "127.0.0.1:443"
hostHeaderRewrite = "127.0.0.1" hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp" requestHeaders.set.x-from-where = "frp"
[[proxies]]
name = "plugin_http2http"
type = "tcp"
remotePort = 6007
[proxies.plugin]
type = "http2http"
localAddr = "127.0.0.1:80"
hostHeaderRewrite = "127.0.0.1"
requestHeaders.set.x-from-where = "frp"
[[proxies]]
name = "plugin_tls2raw"
type = "tcp"
remotePort = 6008
[proxies.plugin]
type = "tls2raw"
localAddr = "127.0.0.1:80"
crtPath = "./server.crt"
keyPath = "./server.key"
[[proxies]] [[proxies]]
name = "secret_tcp" name = "secret_tcp"
# If the type is secret tcp, remotePort is useless # If the type is secret tcp, remotePort is useless

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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
doc/pic/sponsor_lokal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

BIN
doc/pic/sponsor_olares.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,4 +1,4 @@
FROM golang:1.22 AS building FROM golang:1.23 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building
@@ -7,6 +7,8 @@ RUN make frpc
FROM alpine:3 FROM alpine:3
RUN apk add --no-cache tzdata
COPY --from=building /building/bin/frpc /usr/bin/frpc COPY --from=building /building/bin/frpc /usr/bin/frpc
ENTRYPOINT ["/usr/bin/frpc"] ENTRYPOINT ["/usr/bin/frpc"]

View File

@@ -1,4 +1,4 @@
FROM golang:1.22 AS building FROM golang:1.23 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building
@@ -7,6 +7,8 @@ RUN make frps
FROM alpine:3 FROM alpine:3
RUN apk add --no-cache tzdata
COPY --from=building /building/bin/frps /usr/bin/frps COPY --from=building /building/bin/frps /usr/bin/frps
ENTRYPOINT ["/usr/bin/frps"] ENTRYPOINT ["/usr/bin/frps"]

86
go.mod
View File

@@ -1,82 +1,80 @@
module github.com/fatedier/frp module github.com/fatedier/frp
go 1.22 go 1.23.0
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/golib v0.4.1 github.com/fatedier/golib v0.5.1
github.com/google/uuid v1.3.0 github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.1
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.22.0
github.com/onsi/gomega v1.27.8 github.com/onsi/gomega v1.34.2
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.1
github.com/quic-go/quic-go v0.41.0 github.com/quic-go/quic-go v0.48.2
github.com/rodaine/table v1.1.0 github.com/rodaine/table v1.2.0
github.com/samber/lo v1.39.0 github.com/samber/lo v1.47.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
github.com/xtaci/kcp-go/v5 v5.6.7 github.com/xtaci/kcp-go/v5 v5.6.13
golang.org/x/crypto v0.18.0 golang.org/x/crypto v0.30.0
golang.org/x/net v0.19.0 golang.org/x/net v0.32.0
golang.org/x/oauth2 v0.10.0 golang.org/x/oauth2 v0.16.0
golang.org/x/sync v0.3.0 golang.org/x/sync v0.10.0
golang.org/x/time v0.3.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.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // 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-20241206021119-61a79c692802 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/klauspost/reedsolomon v1.12.0 // 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/templexxx/cpu v0.1.1 // indirect
github.com/templexxx/cpu v0.1.0 // indirect github.com/templexxx/xorsimd v0.4.3 // 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.5.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect
golang.org/x/mod v0.11.0 // indirect golang.org/x/mod v0.22.0 // indirect
golang.org/x/sys v0.16.0 // indirect golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.9.3 // indirect golang.org/x/tools v0.28.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.34.1 // 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
) )

195
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=
@@ -9,13 +9,10 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/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,23 +21,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/golib v0.4.1 h1:C37VN3M+F3nUdh13laZsiyb5EXNe3tZnUdoHi+7rx+Q= github.com/fatedier/golib v0.5.1 h1:hcKAnaw5mdI/1KWRGejxR+i1Hn/NvbY5UsMKDr7o13M=
github.com/fatedier/golib v0.4.1/go.mod h1:gpu+1vXxtJ072NYaNsn/YWgojDL8Ap2kFZQtbzT2qkg= github.com/fatedier/golib v0.5.1/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ=
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.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
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=
@@ -48,27 +43,26 @@ 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-20241206021119-61a79c692802 h1:US08AXzP0bLurpzFUV3Poa9ZijrRdd1zAIOVtoHEiS8=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20241206021119-61a79c692802/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
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/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.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
@@ -79,16 +73,14 @@ 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.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
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=
@@ -105,24 +97,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.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
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.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
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/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rodaine/table v1.2.0 h1:38HEnwK4mKSHQJIkavVj+bst1TEY7j9zhLMWu4QJrMA=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rodaine/table v1.2.0/go.mod h1:wejb/q/Yd4T/SVmBSRMr7GCq3KlcZp3gyNYdLSBhkaE=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
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.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
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=
@@ -130,16 +124,17 @@ 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/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI= github.com/templexxx/cpu v0.1.1 h1:isxHaxBXpYFWnk2DReuKkigaZyrjs2+9ypIdGP4h+HI=
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI= github.com/templexxx/cpu v0.1.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
github.com/templexxx/xorsimd v0.4.3 h1:9AQTFHd7Bhk3dIT7Al2XeBX5DWOvsUPZCuhyAtNbHjU=
github.com/templexxx/xorsimd v0.4.3/go.mod h1:oZQcD6RFDisW2Am58dSAGwwL6rHjbzrlu25VDqfWkQg=
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=
@@ -148,38 +143,36 @@ 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.7 h1:7+rnxNFIsjEwTXQk4cSZpXM4pO0hqtpwE1UFFoJBffA= github.com/xtaci/kcp-go/v5 v5.6.13 h1:FEjtz9+D4p8t2x4WjciGt/jsIuhlWjjgPCCWjrVR4Hk=
github.com/xtaci/kcp-go/v5 v5.6.7/go.mod h1:oE9j2NVqAkuKO5o8ByKGch3vgVX3BNf8zqP8JiGq0bM= github.com/xtaci/kcp-go/v5 v5.6.13/go.mod h1:75S1AKYYzNUSXIv30h+jPKJYZUwqpfvLshu63nCNSOM=
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.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
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.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
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-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
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.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
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=
@@ -188,23 +181,21 @@ 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.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.10.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=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -214,27 +205,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.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.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.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
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=
@@ -243,14 +234,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.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
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=
@@ -265,8 +256,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.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.34.1/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=
@@ -279,12 +270,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

@@ -17,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 loong64'
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

@@ -50,7 +50,8 @@ func NewAuthVerifier(cfg v1.AuthServerConfig) (authVerifier Verifier) {
case v1.AuthMethodToken: case v1.AuthMethodToken:
authVerifier = NewTokenAuth(cfg.AdditionalScopes, cfg.Token) authVerifier = NewTokenAuth(cfg.AdditionalScopes, cfg.Token)
case v1.AuthMethodOIDC: case v1.AuthMethodOIDC:
authVerifier = NewOidcAuthVerifier(cfg.AdditionalScopes, cfg.OIDC) tokenVerifier := NewTokenVerifier(cfg.OIDC)
authVerifier = NewOidcAuthVerifier(cfg.AdditionalScopes, tokenVerifier)
} }
return authVerifier return authVerifier
} }

View File

@@ -87,14 +87,18 @@ func (auth *OidcAuthProvider) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (e
return err return err
} }
type TokenVerifier interface {
Verify(context.Context, string) (*oidc.IDToken, error)
}
type OidcAuthConsumer struct { type OidcAuthConsumer struct {
additionalAuthScopes []v1.AuthScope additionalAuthScopes []v1.AuthScope
verifier *oidc.IDTokenVerifier verifier TokenVerifier
subjectFromLogin string subjectsFromLogin []string
} }
func NewOidcAuthVerifier(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCServerConfig) *OidcAuthConsumer { func NewTokenVerifier(cfg v1.AuthOIDCServerConfig) TokenVerifier {
provider, err := oidc.NewProvider(context.Background(), cfg.Issuer) provider, err := oidc.NewProvider(context.Background(), cfg.Issuer)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -105,9 +109,14 @@ func NewOidcAuthVerifier(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCSer
SkipExpiryCheck: cfg.SkipExpiryCheck, SkipExpiryCheck: cfg.SkipExpiryCheck,
SkipIssuerCheck: cfg.SkipIssuerCheck, SkipIssuerCheck: cfg.SkipIssuerCheck,
} }
return provider.Verifier(&verifierConf)
}
func NewOidcAuthVerifier(additionalAuthScopes []v1.AuthScope, verifier TokenVerifier) *OidcAuthConsumer {
return &OidcAuthConsumer{ return &OidcAuthConsumer{
additionalAuthScopes: additionalAuthScopes, additionalAuthScopes: additionalAuthScopes,
verifier: provider.Verifier(&verifierConf), verifier: verifier,
subjectsFromLogin: []string{},
} }
} }
@@ -116,7 +125,9 @@ func (auth *OidcAuthConsumer) VerifyLogin(loginMsg *msg.Login) (err error) {
if err != nil { if err != nil {
return fmt.Errorf("invalid OIDC token in login: %v", err) return fmt.Errorf("invalid OIDC token in login: %v", err)
} }
auth.subjectFromLogin = token.Subject if !slices.Contains(auth.subjectsFromLogin, token.Subject) {
auth.subjectsFromLogin = append(auth.subjectsFromLogin, token.Subject)
}
return nil return nil
} }
@@ -125,11 +136,11 @@ func (auth *OidcAuthConsumer) verifyPostLoginToken(privilegeKey string) (err err
if err != nil { if err != nil {
return fmt.Errorf("invalid OIDC token in ping: %v", err) return fmt.Errorf("invalid OIDC token in ping: %v", err)
} }
if token.Subject != auth.subjectFromLogin { if !slices.Contains(auth.subjectsFromLogin, token.Subject) {
return fmt.Errorf("received different OIDC subject in login and ping. "+ return fmt.Errorf("received different OIDC subject in login and ping. "+
"original subject: %s, "+ "original subjects: %s, "+
"new subject: %s", "new subject: %s",
auth.subjectFromLogin, token.Subject) auth.subjectsFromLogin, token.Subject)
} }
return nil return nil
} }

64
pkg/auth/oidc_test.go Normal file
View File

@@ -0,0 +1,64 @@
package auth_test
import (
"context"
"testing"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/stretchr/testify/require"
"github.com/fatedier/frp/pkg/auth"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/msg"
)
type mockTokenVerifier struct{}
func (m *mockTokenVerifier) Verify(ctx context.Context, subject string) (*oidc.IDToken, error) {
return &oidc.IDToken{
Subject: subject,
}, nil
}
func TestPingWithEmptySubjectFromLoginFails(t *testing.T) {
r := require.New(t)
consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{})
err := consumer.VerifyPing(&msg.Ping{
PrivilegeKey: "ping-without-login",
Timestamp: time.Now().UnixMilli(),
})
r.Error(err)
r.Contains(err.Error(), "received different OIDC subject in login and ping")
}
func TestPingAfterLoginWithNewSubjectSucceeds(t *testing.T) {
r := require.New(t)
consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{})
err := consumer.VerifyLogin(&msg.Login{
PrivilegeKey: "ping-after-login",
})
r.NoError(err)
err = consumer.VerifyPing(&msg.Ping{
PrivilegeKey: "ping-after-login",
Timestamp: time.Now().UnixMilli(),
})
r.NoError(err)
}
func TestPingAfterLoginWithDifferentSubjectFails(t *testing.T) {
r := require.New(t)
consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{})
err := consumer.VerifyLogin(&msg.Login{
PrivilegeKey: "login-with-first-subject",
})
r.NoError(err)
err = consumer.VerifyPing(&msg.Ping{
PrivilegeKey: "ping-with-different-subject",
Timestamp: time.Now().UnixMilli(),
})
r.Error(err)
r.Contains(err.Error(), "received different OIDC subject in login and ping")
}

View File

@@ -106,6 +106,8 @@ func registerProxyBaseConfigFlags(cmd *cobra.Command, c *v1.ProxyBaseConfig, opt
} }
cmd.Flags().StringVarP(&c.Name, "proxy_name", "n", "", "proxy name") cmd.Flags().StringVarP(&c.Name, "proxy_name", "n", "", "proxy name")
cmd.Flags().StringToStringVarP(&c.Metadatas, "metadatas", "", nil, "metadata key-value pairs (e.g., key1=value1,key2=value2)")
cmd.Flags().StringToStringVarP(&c.Annotations, "annotations", "", nil, "annotation key-value pairs (e.g., key1=value1,key2=value2)")
if !options.sshMode { if !options.sshMode {
cmd.Flags().StringVarP(&c.LocalIP, "local_ip", "i", "127.0.0.1", "local ip") cmd.Flags().StringVarP(&c.LocalIP, "local_ip", "i", "127.0.0.1", "local ip")
@@ -140,6 +142,7 @@ func registerVisitorBaseConfigFlags(cmd *cobra.Command, c *v1.VisitorBaseConfig,
cmd.Flags().BoolVarP(&c.Transport.UseCompression, "uc", "", false, "use compression") cmd.Flags().BoolVarP(&c.Transport.UseCompression, "uc", "", false, "use compression")
cmd.Flags().StringVarP(&c.SecretKey, "sk", "", "", "secret key") cmd.Flags().StringVarP(&c.SecretKey, "sk", "", "", "secret key")
cmd.Flags().StringVarP(&c.ServerName, "server_name", "", "", "server name") cmd.Flags().StringVarP(&c.ServerName, "server_name", "", "", "server name")
cmd.Flags().StringVarP(&c.ServerUser, "server-user", "", "", "server user")
cmd.Flags().StringVarP(&c.BindAddr, "bind_addr", "", "", "bind addr") cmd.Flags().StringVarP(&c.BindAddr, "bind_addr", "", "", "bind addr")
cmd.Flags().IntVarP(&c.BindPort, "bind_port", "", 0, "bind port") cmd.Flags().IntVarP(&c.BindPort, "bind_port", "", 0, "bind port")
} }
@@ -226,6 +229,7 @@ func RegisterServerConfigFlags(cmd *cobra.Command, c *v1.ServerConfig, opts ...R
cmd.PersistentFlags().StringVarP(&c.BindAddr, "bind_addr", "", "0.0.0.0", "bind address") cmd.PersistentFlags().StringVarP(&c.BindAddr, "bind_addr", "", "0.0.0.0", "bind address")
cmd.PersistentFlags().IntVarP(&c.BindPort, "bind_port", "p", 7000, "bind port") cmd.PersistentFlags().IntVarP(&c.BindPort, "bind_port", "p", 7000, "bind port")
cmd.PersistentFlags().IntVarP(&c.KCPBindPort, "kcp_bind_port", "", 0, "kcp bind udp port") cmd.PersistentFlags().IntVarP(&c.KCPBindPort, "kcp_bind_port", "", 0, "kcp bind udp port")
cmd.PersistentFlags().IntVarP(&c.QUICBindPort, "quic_bind_port", "", 0, "quic bind udp port")
cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address") cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port") cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port") cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port")

View File

@@ -170,7 +170,7 @@ type ClientCommonConf struct {
} }
// Supported sources including: string(file path), []byte, Reader interface. // Supported sources including: string(file path), []byte, Reader interface.
func UnmarshalClientConfFromIni(source interface{}) (ClientCommonConf, error) { func UnmarshalClientConfFromIni(source any) (ClientCommonConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
Insensitive: false, Insensitive: false,
InsensitiveSections: false, InsensitiveSections: false,
@@ -203,7 +203,7 @@ func UnmarshalClientConfFromIni(source interface{}) (ClientCommonConf, error) {
// otherwise just start proxies in startProxy map // otherwise just start proxies in startProxy map
func LoadAllProxyConfsFromIni( func LoadAllProxyConfsFromIni(
prefix string, prefix string,
source interface{}, source any,
start []string, start []string,
) (map[string]ProxyConf, map[string]VisitorConf, error) { ) (map[string]ProxyConf, map[string]VisitorConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
@@ -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),
} }
} }

View File

@@ -200,38 +200,24 @@ 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,
} }
} }
func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) { func UnmarshalServerConfFromIni(source any) (ServerCommonConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
Insensitive: false, Insensitive: false,
InsensitiveSections: false, InsensitiveSections: false,

View File

@@ -18,10 +18,10 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"text/template"
toml "github.com/pelletier/go-toml/v2" toml "github.com/pelletier/go-toml/v2"
"github.com/samber/lo" "github.com/samber/lo"
@@ -118,7 +118,7 @@ func LoadConfigure(b []byte, c any, strict bool) error {
defer v1.DisallowUnknownFieldsMu.Unlock() defer v1.DisallowUnknownFieldsMu.Unlock()
v1.DisallowUnknownFields = strict v1.DisallowUnknownFields = strict
var tomlObj interface{} var tomlObj any
// Try to unmarshal as TOML first; swallow errors from that (assume it's not valid TOML). // Try to unmarshal as TOML first; swallow errors from that (assume it's not valid TOML).
if err := toml.Unmarshal(b, &tomlObj); err == nil { if err := toml.Unmarshal(b, &tomlObj); err == nil {
b, err = json.Marshal(&tomlObj) b, err = json.Marshal(&tomlObj)

View File

@@ -112,6 +112,29 @@ func TestLoadServerConfigStrictMode(t *testing.T) {
} }
} }
func TestRenderWithTemplate(t *testing.T) {
tests := []struct {
name string
content string
want string
}{
{"toml", tomlServerContent, tomlServerContent},
{"yaml", yamlServerContent, yamlServerContent},
{"json", jsonServerContent, jsonServerContent},
{"template numeric", `key = {{ 123 }}`, "key = 123"},
{"template string", `key = {{ "xyz" }}`, "key = xyz"},
{"template quote", `key = {{ printf "%q" "with space" }}`, `key = "with space"`},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)
got, err := RenderWithTemplate([]byte(test.content), nil)
require.NoError(err)
require.EqualValues(test.want, string(got))
})
}
}
func TestCustomStructStrictMode(t *testing.T) { func TestCustomStructStrictMode(t *testing.T) {
require := require.New(t) require := require.New(t)

View File

@@ -159,18 +159,18 @@ func NewPortsRangeSliceFromString(str string) ([]PortsRange, error) {
out = append(out, PortsRange{Single: int(singleNum)}) out = append(out, PortsRange{Single: int(singleNum)})
case 2: case 2:
// range numbers // range numbers
min, err := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64) minNum, err := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf("range number is invalid, %v", err) return nil, fmt.Errorf("range number is invalid, %v", err)
} }
max, err := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64) maxNum, err := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf("range number is invalid, %v", err) return nil, fmt.Errorf("range number is invalid, %v", err)
} }
if max < min { if maxNum < minNum {
return nil, fmt.Errorf("range number is invalid") return nil, fmt.Errorf("range number is invalid")
} }
out = append(out, PortsRange{Start: int(min), End: int(max)}) out = append(out, PortsRange{Start: int(minNum), End: int(maxNum)})
default: default:
return nil, fmt.Errorf("range number is invalid") return nil, fmt.Errorf("range number is invalid")
} }

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,11 +17,18 @@ package v1
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"github.com/samber/lo"
"github.com/fatedier/frp/pkg/util/util"
) )
type ClientPluginOptions interface{} type ClientPluginOptions interface {
Complete()
}
type TypedClientPluginOptions struct { type TypedClientPluginOptions struct {
Type string `json:"type"` Type string `json:"type"`
@@ -42,7 +49,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]
@@ -63,14 +70,20 @@ func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
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"
PluginHTTPS2HTTP = "https2http" PluginHTTPS2HTTP = "https2http"
PluginHTTPS2HTTPS = "https2https" PluginHTTPS2HTTPS = "https2https"
PluginHTTP2HTTP = "http2http"
PluginSocks5 = "socks5" PluginSocks5 = "socks5"
PluginStaticFile = "static_file" PluginStaticFile = "static_file"
PluginUnixDomainSocket = "unix_domain_socket" PluginUnixDomainSocket = "unix_domain_socket"
PluginTLS2Raw = "tls2raw"
) )
var clientPluginOptionsTypeMap = map[string]reflect.Type{ var clientPluginOptionsTypeMap = map[string]reflect.Type{
@@ -78,9 +91,11 @@ var clientPluginOptionsTypeMap = map[string]reflect.Type{
PluginHTTPProxy: reflect.TypeOf(HTTPProxyPluginOptions{}), PluginHTTPProxy: reflect.TypeOf(HTTPProxyPluginOptions{}),
PluginHTTPS2HTTP: reflect.TypeOf(HTTPS2HTTPPluginOptions{}), PluginHTTPS2HTTP: reflect.TypeOf(HTTPS2HTTPPluginOptions{}),
PluginHTTPS2HTTPS: reflect.TypeOf(HTTPS2HTTPSPluginOptions{}), PluginHTTPS2HTTPS: reflect.TypeOf(HTTPS2HTTPSPluginOptions{}),
PluginHTTP2HTTP: reflect.TypeOf(HTTP2HTTPPluginOptions{}),
PluginSocks5: reflect.TypeOf(Socks5PluginOptions{}), PluginSocks5: reflect.TypeOf(Socks5PluginOptions{}),
PluginStaticFile: reflect.TypeOf(StaticFilePluginOptions{}), PluginStaticFile: reflect.TypeOf(StaticFilePluginOptions{}),
PluginUnixDomainSocket: reflect.TypeOf(UnixDomainSocketPluginOptions{}), PluginUnixDomainSocket: reflect.TypeOf(UnixDomainSocketPluginOptions{}),
PluginTLS2Raw: reflect.TypeOf(TLS2RawPluginOptions{}),
} }
type HTTP2HTTPSPluginOptions struct { type HTTP2HTTPSPluginOptions struct {
@@ -90,36 +105,61 @@ type HTTP2HTTPSPluginOptions struct {
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
} }
func (o *HTTP2HTTPSPluginOptions) Complete() {}
type HTTPProxyPluginOptions struct { type HTTPProxyPluginOptions struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
HTTPUser string `json:"httpUser,omitempty"` HTTPUser string `json:"httpUser,omitempty"`
HTTPPassword string `json:"httpPassword,omitempty"` HTTPPassword string `json:"httpPassword,omitempty"`
} }
func (o *HTTPProxyPluginOptions) Complete() {}
type HTTPS2HTTPPluginOptions struct { type HTTPS2HTTPPluginOptions struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
LocalAddr string `json:"localAddr,omitempty"` LocalAddr string `json:"localAddr,omitempty"`
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
EnableHTTP2 *bool `json:"enableHTTP2,omitempty"`
CrtPath string `json:"crtPath,omitempty"` CrtPath string `json:"crtPath,omitempty"`
KeyPath string `json:"keyPath,omitempty"` KeyPath string `json:"keyPath,omitempty"`
} }
func (o *HTTPS2HTTPPluginOptions) Complete() {
o.EnableHTTP2 = util.EmptyOr(o.EnableHTTP2, lo.ToPtr(true))
}
type HTTPS2HTTPSPluginOptions struct { type HTTPS2HTTPSPluginOptions struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
LocalAddr string `json:"localAddr,omitempty"` LocalAddr string `json:"localAddr,omitempty"`
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"` HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"` RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
EnableHTTP2 *bool `json:"enableHTTP2,omitempty"`
CrtPath string `json:"crtPath,omitempty"` CrtPath string `json:"crtPath,omitempty"`
KeyPath string `json:"keyPath,omitempty"` KeyPath string `json:"keyPath,omitempty"`
} }
func (o *HTTPS2HTTPSPluginOptions) Complete() {
o.EnableHTTP2 = util.EmptyOr(o.EnableHTTP2, lo.ToPtr(true))
}
type HTTP2HTTPPluginOptions struct {
Type string `json:"type,omitempty"`
LocalAddr string `json:"localAddr,omitempty"`
HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
}
func (o *HTTP2HTTPPluginOptions) Complete() {}
type Socks5PluginOptions struct { type Socks5PluginOptions struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
} }
func (o *Socks5PluginOptions) Complete() {}
type StaticFilePluginOptions struct { type StaticFilePluginOptions struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
LocalPath string `json:"localPath,omitempty"` LocalPath string `json:"localPath,omitempty"`
@@ -128,7 +168,20 @@ type StaticFilePluginOptions struct {
HTTPPassword string `json:"httpPassword,omitempty"` HTTPPassword string `json:"httpPassword,omitempty"`
} }
func (o *StaticFilePluginOptions) Complete() {}
type UnixDomainSocketPluginOptions struct { type UnixDomainSocketPluginOptions struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
UnixPath string `json:"unixPath,omitempty"` UnixPath string `json:"unixPath,omitempty"`
} }
func (o *UnixDomainSocketPluginOptions) Complete() {}
type TLS2RawPluginOptions struct {
Type string `json:"type,omitempty"`
LocalAddr string `json:"localAddr,omitempty"`
CrtPath string `json:"crtPath,omitempty"`
KeyPath string `json:"keyPath,omitempty"`
}
func (o *TLS2RawPluginOptions) Complete() {}

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 {
@@ -124,6 +127,10 @@ func (c *ProxyBaseConfig) Complete(namePrefix string) {
c.Name = lo.Ternary(namePrefix == "", "", namePrefix+".") + c.Name c.Name = lo.Ternary(namePrefix == "", "", namePrefix+".") + c.Name
c.LocalIP = util.EmptyOr(c.LocalIP, "127.0.0.1") c.LocalIP = util.EmptyOr(c.LocalIP, "127.0.0.1")
c.Transport.BandwidthLimitMode = util.EmptyOr(c.Transport.BandwidthLimitMode, types.BandwidthLimitModeClient) c.Transport.BandwidthLimitMode = util.EmptyOr(c.Transport.BandwidthLimitMode, types.BandwidthLimitModeClient)
if c.Plugin.ClientPluginOptions != nil {
c.Plugin.ClientPluginOptions.Complete()
}
} }
func (c *ProxyBaseConfig) MarshalToMsg(m *msg.NewProxy) { func (c *ProxyBaseConfig) MarshalToMsg(m *msg.NewProxy) {
@@ -192,6 +199,10 @@ func (c *TypedProxyConfig) UnmarshalJSON(b []byte) error {
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 +299,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 +313,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 +327,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

@@ -32,6 +32,8 @@ func ValidateClientPluginOptions(c v1.ClientPluginOptions) error {
return validateStaticFilePluginOptions(v) return validateStaticFilePluginOptions(v)
case *v1.UnixDomainSocketPluginOptions: case *v1.UnixDomainSocketPluginOptions:
return validateUnixDomainSocketPluginOptions(v) return validateUnixDomainSocketPluginOptions(v)
case *v1.TLS2RawPluginOptions:
return validateTLS2RawPluginOptions(v)
} }
return nil return nil
} }
@@ -70,3 +72,10 @@ func validateUnixDomainSocketPluginOptions(c *v1.UnixDomainSocketPluginOptions)
} }
return nil return nil
} }
func validateTLS2RawPluginOptions(c *v1.TLS2RawPluginOptions) error {
if c.LocalAddr == "" {
return errors.New("localAddr is required")
}
return nil
}

View File

@@ -120,6 +120,10 @@ func (c *TypedVisitorConfig) UnmarshalJSON(b []byte) error {
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

@@ -39,6 +39,6 @@ func ReadMsgInto(c io.Reader, msg Message) (err error) {
return msgCtl.ReadMsgInto(c, msg) return msgCtl.ReadMsgInto(c, msg)
} }
func WriteMsg(c io.Writer, msg interface{}) (err error) { func WriteMsg(c io.Writer, msg any) (err error) {
return msgCtl.WriteMsg(c, msg) return msgCtl.WriteMsg(c, msg)
} }

View File

@@ -40,7 +40,7 @@ const (
TypeNatHoleReport = '6' TypeNatHoleReport = '6'
) )
var msgTypeMap = map[byte]interface{}{ var msgTypeMap = map[byte]any{
TypeLogin: Login{}, TypeLogin: Login{},
TypeLoginResp: LoginResp{}, TypeLoginResp: LoginResp{},
TypeNewProxy: NewProxy{}, TypeNewProxy: NewProxy{},
@@ -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

@@ -371,8 +371,8 @@ func getRangePorts(addrs []string, difference, maxNumber int) []msg.PortsRange {
return nil return nil
} }
addr, err := lo.Last(addrs) addr, isLast := lo.Last(addrs)
if err != nil { if !isLast {
return nil return nil
} }
var ports []msg.PortsRange var ports []msg.PortsRange

View File

@@ -17,7 +17,7 @@ package nathole
import ( import (
"context" "context"
"fmt" "fmt"
"math/rand" "math/rand/v2"
"net" "net"
"slices" "slices"
"strconv" "strconv"
@@ -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 {
@@ -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

View File

@@ -78,9 +78,9 @@ func ListAllLocalIPs() ([]net.IP, error) {
return ips, nil return ips, nil
} }
func ListLocalIPsForNatHole(max int) ([]string, error) { func ListLocalIPsForNatHole(maxItems int) ([]string, error) {
if max <= 0 { if maxItems <= 0 {
return nil, fmt.Errorf("max must be greater than 0") return nil, fmt.Errorf("maxItems must be greater than 0")
} }
ips, err := ListAllLocalIPs() ips, err := ListAllLocalIPs()
@@ -88,9 +88,9 @@ func ListLocalIPsForNatHole(max int) ([]string, error) {
return nil, err return nil, err
} }
filtered := make([]string, 0, max) filtered := make([]string, 0, maxItems)
for _, ip := range ips { for _, ip := range ips {
if len(filtered) >= max { if len(filtered) >= maxItems {
break break
} }

View File

@@ -0,0 +1,94 @@
// 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 !frps
package plugin
import (
"context"
"io"
stdlog "log"
"net"
"net/http"
"net/http/httputil"
"github.com/fatedier/golib/pool"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/util/log"
netpkg "github.com/fatedier/frp/pkg/util/net"
)
func init() {
Register(v1.PluginHTTP2HTTP, NewHTTP2HTTPPlugin)
}
type HTTP2HTTPPlugin struct {
opts *v1.HTTP2HTTPPluginOptions
l *Listener
s *http.Server
}
func NewHTTP2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
opts := options.(*v1.HTTP2HTTPPluginOptions)
listener := NewProxyListener()
p := &HTTP2HTTPPlugin{
opts: opts,
l: listener,
}
rp := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) {
req := r.Out
req.URL.Scheme = "http"
req.URL.Host = p.opts.LocalAddr
if p.opts.HostHeaderRewrite != "" {
req.Host = p.opts.HostHeaderRewrite
}
for k, v := range p.opts.RequestHeaders.Set {
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,
ReadHeaderTimeout: 0,
}
go func() {
_ = p.s.Serve(listener)
}()
return p, nil
}
func (p *HTTP2HTTPPlugin) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
_ = p.l.PutConn(wrapConn)
}
func (p *HTTP2HTTPPlugin) Name() string {
return v1.PluginHTTP2HTTP
}
func (p *HTTP2HTTPPlugin) Close() error {
return p.s.Close()
}

View File

@@ -17,13 +17,18 @@
package plugin package plugin
import ( import (
"context"
"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 +59,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 +72,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{
@@ -79,7 +89,7 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
return p, nil return p, nil
} }
func (p *HTTP2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { func (p *HTTP2HTTPSPlugin) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
_ = p.l.PutConn(wrapConn) _ = p.l.PutConn(wrapConn)
} }

View File

@@ -18,6 +18,7 @@ package plugin
import ( import (
"bufio" "bufio"
"context"
"encoding/base64" "encoding/base64"
"io" "io"
"net" "net"
@@ -54,7 +55,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() {
@@ -67,7 +69,7 @@ func (hp *HTTPProxy) Name() string {
return v1.PluginHTTPProxy return v1.PluginHTTPProxy
} }
func (hp *HTTPProxy) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { func (hp *HTTPProxy) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
sc, rd := libnet.NewSharedConn(wrapConn) sc, rd := libnet.NewSharedConn(wrapConn)

View File

@@ -17,15 +17,23 @@
package plugin package plugin
import ( import (
"context"
"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"
"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/transport" "github.com/fatedier/frp/pkg/transport"
httppkg "github.com/fatedier/frp/pkg/util/http"
"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 +59,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,45 +71,46 @@ 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),
} }
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.TLS != nil {
tlsServerName, _ := httppkg.CanonicalHost(r.TLS.ServerName)
host, _ := httppkg.CanonicalHost(r.Host)
if tlsServerName != "" && tlsServerName != host {
w.WriteHeader(http.StatusMisdirectedRequest)
return
}
}
rp.ServeHTTP(w, r)
})
p.s = &http.Server{ tlsConfig, err := transport.NewServerTLSConfig(p.opts.CrtPath, p.opts.KeyPath, "")
Handler: rp,
}
var (
tlsConfig *tls.Config
err error
)
if opts.CrtPath != "" || opts.KeyPath != "" {
tlsConfig, err = p.genTLSConfig()
} else {
tlsConfig, err = transport.NewServerTLSConfig("", "", "")
tlsConfig.InsecureSkipVerify = true
}
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: handler,
ReadHeaderTimeout: 60 * time.Second,
TLSConfig: tlsConfig,
}
if !lo.FromPtr(opts.EnableHTTP2) {
p.s.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
}
go func() { go func() {
_ = p.s.Serve(ln) _ = p.s.ServeTLS(listener, "", "")
}() }()
return p, nil return p, nil
} }
func (p *HTTPS2HTTPPlugin) genTLSConfig() (*tls.Config, error) { func (p *HTTPS2HTTPPlugin) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) {
cert, err := tls.LoadX509KeyPair(p.opts.CrtPath, p.opts.KeyPath)
if err != nil {
return nil, err
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
return config, nil
}
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *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

@@ -17,15 +17,23 @@
package plugin package plugin
import ( import (
"context"
"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"
"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/transport" "github.com/fatedier/frp/pkg/transport"
httppkg "github.com/fatedier/frp/pkg/util/http"
"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 +64,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,46 +76,47 @@ 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),
} }
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.TLS != nil {
tlsServerName, _ := httppkg.CanonicalHost(r.TLS.ServerName)
host, _ := httppkg.CanonicalHost(r.Host)
if tlsServerName != "" && tlsServerName != host {
w.WriteHeader(http.StatusMisdirectedRequest)
return
}
}
rp.ServeHTTP(w, r)
})
p.s = &http.Server{ tlsConfig, err := transport.NewServerTLSConfig(p.opts.CrtPath, p.opts.KeyPath, "")
Handler: rp,
}
var (
tlsConfig *tls.Config
err error
)
if opts.CrtPath != "" || opts.KeyPath != "" {
tlsConfig, err = p.genTLSConfig()
} else {
tlsConfig, err = transport.NewServerTLSConfig("", "", "")
tlsConfig.InsecureSkipVerify = true
}
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: handler,
ReadHeaderTimeout: 60 * time.Second,
TLSConfig: tlsConfig,
}
if !lo.FromPtr(opts.EnableHTTP2) {
p.s.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
}
go func() { go func() {
_ = p.s.Serve(ln) _ = p.s.ServeTLS(listener, "", "")
}() }()
return p, nil return p, nil
} }
func (p *HTTPS2HTTPSPlugin) genTLSConfig() (*tls.Config, error) { func (p *HTTPS2HTTPSPlugin) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) {
cert, err := tls.LoadX509KeyPair(p.opts.CrtPath, p.opts.KeyPath)
if err != nil {
return nil, err
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
return config, nil
}
func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *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

@@ -15,6 +15,7 @@
package plugin package plugin
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net" "net"
@@ -50,12 +51,14 @@ 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 {
Name() string Name() string
Handle(conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) Handle(ctx context.Context, conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo)
Close() error Close() error
} }

View File

@@ -17,6 +17,7 @@
package plugin package plugin
import ( import (
"context"
"io" "io"
"log" "log"
"net" "net"
@@ -50,7 +51,7 @@ func NewSocks5Plugin(options v1.ClientPluginOptions) (p Plugin, err error) {
return return
} }
func (sp *Socks5Plugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { func (sp *Socks5Plugin) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
defer conn.Close() defer conn.Close()
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
_ = sp.Server.ServeConn(wrapConn) _ = sp.Server.ServeConn(wrapConn)

View File

@@ -17,6 +17,7 @@
package plugin package plugin
import ( import (
"context"
"io" "io"
"net" "net"
"net/http" "net/http"
@@ -60,7 +61,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)
@@ -68,7 +70,7 @@ func NewStaticFilePlugin(options v1.ClientPluginOptions) (Plugin, error) {
return sp, nil return sp, nil
} }
func (sp *StaticFilePlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) { func (sp *StaticFilePlugin) Handle(_ context.Context, conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn) wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
_ = sp.l.PutConn(wrapConn) _ = sp.l.PutConn(wrapConn)
} }

View File

@@ -0,0 +1,83 @@
// 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 !frps
package plugin
import (
"context"
"crypto/tls"
"io"
"net"
libio "github.com/fatedier/golib/io"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/transport"
netpkg "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog"
)
func init() {
Register(v1.PluginTLS2Raw, NewTLS2RawPlugin)
}
type TLS2RawPlugin struct {
opts *v1.TLS2RawPluginOptions
tlsConfig *tls.Config
}
func NewTLS2RawPlugin(options v1.ClientPluginOptions) (Plugin, error) {
opts := options.(*v1.TLS2RawPluginOptions)
p := &TLS2RawPlugin{
opts: opts,
}
tlsConfig, err := transport.NewServerTLSConfig(p.opts.CrtPath, p.opts.KeyPath, "")
if err != nil {
return nil, err
}
p.tlsConfig = tlsConfig
return p, nil
}
func (p *TLS2RawPlugin) Handle(ctx context.Context, conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
xl := xlog.FromContextSafe(ctx)
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
tlsConn := tls.Server(wrapConn, p.tlsConfig)
if err := tlsConn.Handshake(); err != nil {
xl.Warnf("tls handshake error: %v", err)
return
}
rawConn, err := net.Dial("tcp", p.opts.LocalAddr)
if err != nil {
xl.Warnf("dial to local addr error: %v", err)
return
}
libio.Join(tlsConn, rawConn)
}
func (p *TLS2RawPlugin) Name() string {
return v1.PluginTLS2Raw
}
func (p *TLS2RawPlugin) Close() error {
return nil
}

View File

@@ -17,12 +17,14 @@
package plugin package plugin
import ( import (
"context"
"io" "io"
"net" "net"
libio "github.com/fatedier/golib/io" libio "github.com/fatedier/golib/io"
v1 "github.com/fatedier/frp/pkg/config/v1" v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/util/xlog"
) )
func init() { func init() {
@@ -48,9 +50,11 @@ func NewUnixDomainSocketPlugin(options v1.ClientPluginOptions) (p Plugin, err er
return return
} }
func (uds *UnixDomainSocketPlugin) Handle(conn io.ReadWriteCloser, _ net.Conn, extra *ExtraInfo) { func (uds *UnixDomainSocketPlugin) Handle(ctx context.Context, conn io.ReadWriteCloser, _ net.Conn, extra *ExtraInfo) {
xl := xlog.FromContextSafe(ctx)
localConn, err := net.DialUnix("unix", nil, uds.UnixAddr) localConn, err := net.DialUnix("unix", nil, uds.UnixAddr)
if err != nil { if err != nil {
xl.Warnf("dial to uds %s error: %v", uds.UnixAddr, err)
return return
} }
if extra.ProxyProtocolHeader != nil { if extra.ProxyProtocolHeader != nil {

View File

@@ -72,7 +72,7 @@ func (p *httpPlugin) IsSupport(op string) bool {
return false return false
} }
func (p *httpPlugin) Handle(ctx context.Context, op string, content interface{}) (*Response, interface{}, error) { func (p *httpPlugin) Handle(ctx context.Context, op string, content any) (*Response, any, error) {
r := &Request{ r := &Request{
Version: APIVersion, Version: APIVersion,
Op: op, Op: op,

View File

@@ -75,7 +75,7 @@ func (m *Manager) Login(content *LoginContent) (*LoginContent, error) {
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent interface{} retContent any
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@@ -109,7 +109,7 @@ func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) {
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent interface{} retContent any
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@@ -168,7 +168,7 @@ func (m *Manager) Ping(content *PingContent) (*PingContent, error) {
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent interface{} retContent any
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@@ -202,7 +202,7 @@ func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent,
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent interface{} retContent any
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()
@@ -236,7 +236,7 @@ func (m *Manager) NewUserConn(content *NewUserConnContent) (*NewUserConnContent,
Reject: false, Reject: false,
Unchange: true, Unchange: true,
} }
retContent interface{} retContent any
err error err error
) )
reqid, _ := util.RandID() reqid, _ := util.RandID()

View File

@@ -32,5 +32,5 @@ const (
type Plugin interface { type Plugin interface {
Name() string Name() string
IsSupport(op string) bool IsSupport(op string) bool
Handle(ctx context.Context, op string, content interface{}) (res *Response, retContent interface{}, err error) Handle(ctx context.Context, op string, content any) (res *Response, retContent any, err error)
} }

View File

@@ -19,16 +19,16 @@ import (
) )
type Request struct { type Request struct {
Version string `json:"version"` Version string `json:"version"`
Op string `json:"op"` Op string `json:"op"`
Content interface{} `json:"content"` Content any `json:"content"`
} }
type Response struct { type Response struct {
Reject bool `json:"reject"` Reject bool `json:"reject"`
RejectReason string `json:"reject_reason"` RejectReason string `json:"reject_reason"`
Unchange bool `json:"unchange"` Unchange bool `json:"unchange"`
Content interface{} `json:"content"` Content any `json:"content"`
} }
type LoginContent struct { type LoginContent struct {

View File

@@ -1,6 +1,7 @@
package client package client
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@@ -31,8 +32,8 @@ func (c *Client) SetAuth(user, pwd string) {
c.authPwd = pwd c.authPwd = pwd
} }
func (c *Client) GetProxyStatus(name string) (*client.ProxyStatusResp, error) { func (c *Client) GetProxyStatus(ctx context.Context, name string) (*client.ProxyStatusResp, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/status", nil) req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/status", nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -54,8 +55,8 @@ func (c *Client) GetProxyStatus(name string) (*client.ProxyStatusResp, error) {
return nil, fmt.Errorf("no proxy status found") return nil, fmt.Errorf("no proxy status found")
} }
func (c *Client) GetAllProxyStatus() (client.StatusResp, error) { func (c *Client) GetAllProxyStatus(ctx context.Context) (client.StatusResp, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/status", nil) req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/status", nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -70,7 +71,7 @@ func (c *Client) GetAllProxyStatus() (client.StatusResp, error) {
return allStatus, nil return allStatus, nil
} }
func (c *Client) Reload(strictMode bool) error { func (c *Client) Reload(ctx context.Context, strictMode bool) error {
v := url.Values{} v := url.Values{}
if strictMode { if strictMode {
v.Set("strictConfig", "true") v.Set("strictConfig", "true")
@@ -79,7 +80,7 @@ func (c *Client) Reload(strictMode bool) error {
if len(v) > 0 { if len(v) > 0 {
queryStr = "?" + v.Encode() queryStr = "?" + v.Encode()
} }
req, err := http.NewRequest("GET", "http://"+c.address+"/api/reload"+queryStr, nil) req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/reload"+queryStr, nil)
if err != nil { if err != nil {
return err return err
} }
@@ -87,8 +88,8 @@ func (c *Client) Reload(strictMode bool) error {
return err return err
} }
func (c *Client) Stop() error { func (c *Client) Stop(ctx context.Context) error {
req, err := http.NewRequest("POST", "http://"+c.address+"/api/stop", nil) req, err := http.NewRequestWithContext(ctx, "POST", "http://"+c.address+"/api/stop", nil)
if err != nil { if err != nil {
return err return err
} }
@@ -96,16 +97,16 @@ func (c *Client) Stop() error {
return err return err
} }
func (c *Client) GetConfig() (string, error) { func (c *Client) GetConfig(ctx context.Context) (string, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/config", nil) req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/config", nil)
if err != nil { if err != nil {
return "", err return "", err
} }
return c.do(req) return c.do(req)
} }
func (c *Client) UpdateConfig(content string) error { func (c *Client) UpdateConfig(ctx context.Context, content string) error {
req, err := http.NewRequest("PUT", "http://"+c.address+"/api/config", strings.NewReader(content)) req, err := http.NewRequestWithContext(ctx, "PUT", "http://"+c.address+"/api/config", strings.NewReader(content))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -112,6 +112,10 @@ func (g *Gateway) Run() {
} }
} }
func (g *Gateway) Close() error {
return g.ln.Close()
}
func (g *Gateway) handleConn(conn net.Conn) { func (g *Gateway) handleConn(conn net.Conn) {
defer conn.Close() defer conn.Close()

View File

@@ -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,11 +15,20 @@
package log package log
import ( import (
"bytes"
"os" "os"
"github.com/fatedier/golib/log" "github.com/fatedier/golib/log"
) )
var (
TraceLevel = log.TraceLevel
DebugLevel = log.DebugLevel
InfoLevel = log.InfoLevel
WarnLevel = log.WarnLevel
ErrorLevel = log.ErrorLevel
)
var Logger *log.Logger var Logger *log.Logger
func init() { func init() {
@@ -58,22 +67,43 @@ func InitLogger(logPath string, levelStr string, maxDays int, disableLogColor bo
Logger = Logger.WithOptions(options...) Logger = Logger.WithOptions(options...)
} }
func Errorf(format string, v ...interface{}) { func Errorf(format string, v ...any) {
Logger.Errorf(format, v...) Logger.Errorf(format, v...)
} }
func Warnf(format string, v ...interface{}) { func Warnf(format string, v ...any) {
Logger.Warnf(format, v...) Logger.Warnf(format, v...)
} }
func Infof(format string, v ...interface{}) { func Infof(format string, v ...any) {
Logger.Infof(format, v...) Logger.Infof(format, v...)
} }
func Debugf(format string, v ...interface{}) { func Debugf(format string, v ...any) {
Logger.Debugf(format, v...) Logger.Debugf(format, v...)
} }
func Tracef(format string, v ...interface{}) { func Tracef(format string, v ...any) {
Logger.Tracef(format, v...) Logger.Tracef(format, v...)
} }
func Logf(level log.Level, offset int, format string, v ...any) {
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,
}
}
func (w *WriteLogger) Write(p []byte) (n int, err error) {
Logger.Log(w.level, w.offset, string(bytes.TrimRight(p, "\n")))
return len(p), nil
}

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

@@ -4,6 +4,7 @@ import (
"errors" "errors"
"net" "net"
"net/http" "net/http"
"time"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
@@ -39,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() {

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"
@@ -85,21 +85,21 @@ func ParseRangeNumbers(rangeStr string) (numbers []int64, err error) {
numbers = append(numbers, singleNum) numbers = append(numbers, singleNum)
case 2: case 2:
// range numbers // range numbers
min, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64) minValue, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
if errRet != nil { if errRet != nil {
err = fmt.Errorf("range number is invalid, %v", errRet) err = fmt.Errorf("range number is invalid, %v", errRet)
return return
} }
max, errRet := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64) maxValue, errRet := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
if errRet != nil { if errRet != nil {
err = fmt.Errorf("range number is invalid, %v", errRet) err = fmt.Errorf("range number is invalid, %v", errRet)
return return
} }
if max < min { if maxValue < minValue {
err = fmt.Errorf("range number is invalid") err = fmt.Errorf("range number is invalid")
return return
} }
for i := min; i <= max; i++ { for i := minValue; i <= maxValue; i++ {
numbers = append(numbers, i) numbers = append(numbers, i)
} }
default: default:
@@ -118,13 +118,13 @@ func GenerateResponseErrorString(summary string, err error, detailed bool) strin
} }
func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Duration { func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Duration {
min := int64(minRatio * 1000.0) minValue := int64(minRatio * 1000.0)
max := int64(maxRatio * 1000.0) maxValue := int64(maxRatio * 1000.0)
var n int64 var n int64
if max <= min { if maxValue <= minValue {
n = min n = minValue
} else { } else {
n = mathrand.Int63n(max-min) + min n = mathrand.Int64N(maxValue-minValue) + minValue
} }
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,7 +14,7 @@
package version package version
var version = "0.56.0" var version = "0.61.2"
func Full() string { func Full() string {
return version return version

View File

@@ -15,7 +15,6 @@
package vhost package vhost
import ( import (
"bytes"
"context" "context"
"encoding/base64" "encoding/base64"
"errors" "errors"
@@ -30,6 +29,8 @@ import (
libio "github.com/fatedier/golib/io" libio "github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool" "github.com/fatedier/golib/pool"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
httppkg "github.com/fatedier/frp/pkg/util/http" httppkg "github.com/fatedier/frp/pkg/util/http"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
@@ -42,7 +43,7 @@ type HTTPReverseProxyOptions struct {
} }
type HTTPReverseProxy struct { type HTTPReverseProxy struct {
proxy *httputil.ReverseProxy proxy http.Handler
vhostRouter *Routers vhostRouter *Routers
responseHeaderTimeout time.Duration responseHeaderTimeout time.Duration
@@ -59,13 +60,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
@@ -77,7 +79,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
endpoint, _ = rc.ChooseEndpointFn() endpoint, _ = rc.ChooseEndpointFn()
reqRouteInfo.Endpoint = endpoint reqRouteInfo.Endpoint = endpoint
log.Tracef("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 +94,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,15 +126,21 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
return nil, nil return nil, nil
}, },
}, },
BufferPool: newWrapPool(), BufferPool: pool.NewBuffer(32 * 1024),
ErrorLog: stdlog.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) {
log.Warnf("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())
}, },
} }
rp.proxy = proxy rp.proxy = h2c.NewHandler(proxy, &http2.Server{})
return rp return rp
} }
@@ -151,14 +168,6 @@ func (rp *HTTPReverseProxy) GetRouteConfig(domain, location, routeByHTTPUser str
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 +308,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 +335,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) {
log.Warnf("%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

@@ -24,7 +24,7 @@ type Router struct {
httpUser string httpUser string
// store any object here // store any object here
payload interface{} payload any
} }
func NewRouters() *Routers { func NewRouters() *Routers {
@@ -33,7 +33,7 @@ func NewRouters() *Routers {
} }
} }
func (r *Routers) Add(domain, location, httpUser string, payload interface{}) error { func (r *Routers) Add(domain, location, httpUser string, payload any) error {
domain = strings.ToLower(domain) domain = strings.ToLower(domain)
r.mutex.Lock() r.mutex.Lock()

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 {
@@ -99,6 +100,10 @@ func (v *Muxer) SetRewriteHostFunc(f hostRewriteFunc) *Muxer {
return v return v
} }
func (v *Muxer) Close() error {
return v.listener.Close()
}
type ChooseEndpointFunc func() (string, error) type ChooseEndpointFunc func() (string, error)
type CreateConnFunc func(remoteAddr string) (net.Conn, error) type CreateConnFunc func(remoteAddr string) (net.Conn, error)
@@ -113,6 +118,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

View File

@@ -15,7 +15,7 @@
package wait package wait
import ( import (
"math/rand" "math/rand/v2"
"time" "time"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"

View File

@@ -94,22 +94,22 @@ func (l *Logger) Spawn() *Logger {
return nl return nl
} }
func (l *Logger) Errorf(format string, v ...interface{}) { func (l *Logger) Errorf(format string, v ...any) {
log.Logger.Errorf(l.prefixString+format, v...) log.Logger.Errorf(l.prefixString+format, v...)
} }
func (l *Logger) Warnf(format string, v ...interface{}) { func (l *Logger) Warnf(format string, v ...any) {
log.Logger.Warnf(l.prefixString+format, v...) log.Logger.Warnf(l.prefixString+format, v...)
} }
func (l *Logger) Infof(format string, v ...interface{}) { func (l *Logger) Infof(format string, v ...any) {
log.Logger.Infof(l.prefixString+format, v...) log.Logger.Infof(l.prefixString+format, v...)
} }
func (l *Logger) Debugf(format string, v ...interface{}) { func (l *Logger) Debugf(format string, v ...any) {
log.Logger.Debugf(l.prefixString+format, v...) log.Logger.Debugf(l.prefixString+format, v...)
} }
func (l *Logger) Tracef(format string, v ...interface{}) { func (l *Logger) Tracef(format string, v ...any) {
log.Logger.Tracef(l.prefixString+format, v...) log.Logger.Tracef(l.prefixString+format, v...)
} }

View File

@@ -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.Warnf("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

View File

@@ -59,3 +59,13 @@ type ResourceController struct {
// All server manager plugin // All server manager plugin
PluginManager *plugin.Manager PluginManager *plugin.Manager
} }
func (rc *ResourceController) Close() error {
if rc.VhostHTTPSMuxer != nil {
rc.VhostHTTPSMuxer.Close()
}
if rc.TCPMuxHTTPConnectMuxer != nil {
rc.TCPMuxHTTPConnectMuxer.Close()
}
return nil
}

View File

@@ -32,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
@@ -146,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 {
@@ -197,15 +196,15 @@ func getConfByType(proxyType string) any {
// Get proxy info. // Get proxy info.
type ProxyStatsInfo struct { type ProxyStatsInfo struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf any `json:"conf"`
ClientVersion string `json:"clientVersion,omitempty"` ClientVersion string `json:"clientVersion,omitempty"`
TodayTrafficIn int64 `json:"todayTrafficIn"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"todayTrafficOut"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"curConns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"lastStartTime"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"lastCloseTime"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
type GetProxyInfoResp struct { type GetProxyInfoResp struct {
@@ -273,14 +272,14 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt
// Get proxy info by name. // Get proxy info by name.
type GetProxyStatsResp struct { type GetProxyStatsResp struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf any `json:"conf"`
TodayTrafficIn int64 `json:"todayTrafficIn"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"todayTrafficOut"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"curConns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"lastStartTime"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"lastCloseTime"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
// /api/proxy/:type/:name // /api/proxy/:type/:name

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,

View File

@@ -137,17 +137,17 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
dstAddr string dstAddr string
srcPortStr string srcPortStr string
dstPortStr string dstPortStr string
srcPort int srcPort uint64
dstPort int dstPort uint64
) )
if src != nil { if src != nil {
srcAddr, srcPortStr, _ = net.SplitHostPort(src.String()) srcAddr, srcPortStr, _ = net.SplitHostPort(src.String())
srcPort, _ = strconv.Atoi(srcPortStr) srcPort, _ = strconv.ParseUint(srcPortStr, 10, 16)
} }
if dst != nil { if dst != nil {
dstAddr, dstPortStr, _ = net.SplitHostPort(dst.String()) dstAddr, dstPortStr, _ = net.SplitHostPort(dst.String())
dstPort, _ = strconv.Atoi(dstPortStr) dstPort, _ = strconv.ParseUint(dstPortStr, 10, 16)
} }
err := msg.WriteMsg(workConn, &msg.StartWorkConn{ err := msg.WriteMsg(workConn, &msg.StartWorkConn{
ProxyName: pxy.GetName(), ProxyName: pxy.GetName(),
@@ -190,8 +190,8 @@ func (pxy *BaseProxy) startCommonTCPListenersHandler() {
} else { } else {
tempDelay *= 2 tempDelay *= 2
} }
if max := 1 * time.Second; tempDelay > max { if maxTime := 1 * time.Second; tempDelay > maxTime {
tempDelay = max tempDelay = maxTime
} }
xl.Infof("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)

View File

@@ -17,8 +17,7 @@ package proxy
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"sync"
"github.com/fatedier/golib/errors"
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"
@@ -32,7 +31,8 @@ type XTCPProxy struct {
*BaseProxy *BaseProxy
cfg *v1.XTCPProxyConfig cfg *v1.XTCPProxyConfig
closeCh chan struct{} closeCh chan struct{}
closeOnce sync.Once
} }
func NewXTCPProxy(baseProxy *BaseProxy) Proxy { func NewXTCPProxy(baseProxy *BaseProxy) Proxy {
@@ -43,6 +43,7 @@ func NewXTCPProxy(baseProxy *BaseProxy) Proxy {
return &XTCPProxy{ return &XTCPProxy{
BaseProxy: baseProxy, BaseProxy: baseProxy,
cfg: unwrapped, cfg: unwrapped,
closeCh: make(chan struct{}),
} }
} }
@@ -87,9 +88,9 @@ func (pxy *XTCPProxy) Run() (remoteAddr string, err error) {
} }
func (pxy *XTCPProxy) Close() { func (pxy *XTCPProxy) Close() {
pxy.BaseProxy.Close() pxy.closeOnce.Do(func() {
pxy.rc.NatHoleController.CloseClient(pxy.GetName()) pxy.BaseProxy.Close()
_ = errors.PanicToError(func() { pxy.rc.NatHoleController.CloseClient(pxy.GetName())
close(pxy.closeCh) close(pxy.closeCh)
}) })
} }

View File

@@ -26,6 +26,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/fatedier/golib/crypto"
"github.com/fatedier/golib/net/mux" "github.com/fatedier/golib/net/mux"
fmux "github.com/hashicorp/yamux" fmux "github.com/hashicorp/yamux"
quic "github.com/quic-go/quic-go" quic "github.com/quic-go/quic-go"
@@ -61,6 +62,7 @@ const (
) )
func init() { func init() {
crypto.DefaultSalt = "frp"
// Disable quic-go's receive buffer warning. // Disable quic-go's receive buffer warning.
os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true") 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. // Disable quic-go's ECN support by default. It may cause issues on certain operating systems.
@@ -284,12 +286,13 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPPort)) address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPPort))
server := &http.Server{ server := &http.Server{
Addr: address, Addr: address,
Handler: rp, Handler: rp,
ReadHeaderTimeout: 60 * time.Second,
} }
var l net.Listener var l net.Listener
if httpMuxOn { if httpMuxOn {
l = svr.muxer.ListenHttp(1) l = svr.muxer.ListenHTTP(1)
} else { } else {
l, err = net.Listen("tcp", address) l, err = net.Listen("tcp", address)
if err != nil { if err != nil {
@@ -306,7 +309,7 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
if cfg.VhostHTTPSPort > 0 { if cfg.VhostHTTPSPort > 0 {
var l net.Listener var l net.Listener
if httpsMuxOn { if httpsMuxOn {
l = svr.muxer.ListenHttps(1) l = svr.muxer.ListenHTTPS(1)
} else { } else {
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPSPort)) address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPSPort))
l, err = net.Listen("tcp", address) l, err = net.Listen("tcp", address)
@@ -383,24 +386,30 @@ func (svr *Service) Run(ctx context.Context) {
func (svr *Service) Close() error { func (svr *Service) Close() error {
if svr.kcpListener != nil { if svr.kcpListener != nil {
svr.kcpListener.Close() svr.kcpListener.Close()
svr.kcpListener = nil
} }
if svr.quicListener != nil { if svr.quicListener != nil {
svr.quicListener.Close() svr.quicListener.Close()
svr.quicListener = nil
} }
if svr.websocketListener != nil { if svr.websocketListener != nil {
svr.websocketListener.Close() svr.websocketListener.Close()
svr.websocketListener = nil
} }
if svr.tlsListener != nil { if svr.tlsListener != nil {
svr.tlsListener.Close() svr.tlsListener.Close()
svr.tlsConfig = nil }
if svr.sshTunnelListener != nil {
svr.sshTunnelListener.Close()
} }
if svr.listener != nil { if svr.listener != nil {
svr.listener.Close() svr.listener.Close()
svr.listener = nil
} }
if svr.webServer != nil {
svr.webServer.Close()
}
if svr.sshTunnelGateway != nil {
svr.sshTunnelGateway.Close()
}
svr.rc.Close()
svr.muxer.Close()
svr.ctlManager.Close() svr.ctlManager.Close()
if svr.cancel != nil { if svr.cancel != nil {
svr.cancel() svr.cancel()

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