mirror of
https://github.com/fatedier/frp.git
synced 2025-08-03 20:26:50 +00:00
Compare commits
57 Commits
8115f7b410
...
v0.54.0
Author | SHA1 | Date | |
---|---|---|---|
|
d689f0fc53 | ||
|
d505ecb473 | ||
|
2b83436a97 | ||
|
051299ec25 | ||
|
44985f574d | ||
|
c9ca9353cf | ||
|
31fa3f021a | ||
|
2d3af8a108 | ||
|
466d69eae0 | ||
|
7c8cbeb250 | ||
|
4fd6301577 | ||
|
53626b370c | ||
|
4fd800bc48 | ||
|
0d6d968fe8 | ||
|
8fb99ef7a9 | ||
|
88e74ff24d | ||
|
534dc99d55 | ||
|
595aba5a9b | ||
|
a4189ba474 | ||
|
9ec84f8143 | ||
|
8ab474cc97 | ||
|
a301046f3d | ||
|
8888610d83 | ||
|
fe5fb0326b | ||
|
eb1e19a821 | ||
|
10f2620131 | ||
|
ce677820c6 | ||
|
88fcc079e8 | ||
|
2dab5d0bca | ||
|
143750901e | ||
|
997d406ec2 | ||
|
cfd1a3128a | ||
|
57577ea044 | ||
|
c5c79e4148 | ||
|
55da58eca4 | ||
|
76a1efccd9 | ||
|
980f084ad1 | ||
|
3bf1eb8565 | ||
|
b2ae433e18 | ||
|
aa0a41ee4e | ||
|
1ea1530b36 | ||
|
e0c45a1aca | ||
|
813c45f5c2 | ||
|
aa74dc4646 | ||
|
2406ecdfea | ||
|
8668fef136 | ||
|
ea62bc5a34 | ||
|
23bb76397a | ||
|
487c8d7c29 | ||
|
f480160e2d | ||
|
30c246c488 | ||
|
75f3bce04d | ||
|
adc3adc13b | ||
|
e62d9a5242 | ||
|
134a46c00b | ||
|
ae08811636 | ||
|
6451583e60 |
@@ -2,15 +2,24 @@ version: 2
|
||||
jobs:
|
||||
go-version-latest:
|
||||
docker:
|
||||
- image: cimg/go:1.22-node
|
||||
- image: cimg/go:1.21-node
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout
|
||||
- run: make
|
||||
- run: make alltest
|
||||
- checkout
|
||||
- run: make
|
||||
- run: make alltest
|
||||
go-version-last:
|
||||
docker:
|
||||
- image: cimg/go:1.20-node
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout
|
||||
- run: make
|
||||
- run: make alltest
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- go-version-latest
|
||||
- go-version-latest
|
||||
- go-version-last
|
||||
|
12
.github/workflows/build-and-push-image.yml
vendored
12
.github/workflows/build-and-push-image.yml
vendored
@@ -19,15 +19,15 @@ jobs:
|
||||
steps:
|
||||
# environment
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# get image tag name
|
||||
- name: Get Image Tag Name
|
||||
@@ -38,13 +38,13 @@ jobs:
|
||||
echo "TAG_NAME=${{ github.event.inputs.tag }}" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to the GPR
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
${{ env.TAG_FRPC_GPR }}
|
||||
|
||||
- name: Build and push frps
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./dockerfiles/Dockerfile-for-frps
|
||||
|
41
.github/workflows/golangci-lint.yml
vendored
41
.github/workflows/golangci-lint.yml
vendored
@@ -14,29 +14,28 @@ jobs:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: false
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v4
|
||||
with:
|
||||
# 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.57
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.21'
|
||||
- uses: actions/checkout@v3
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||
version: v1.55
|
||||
|
||||
# Optional: golangci-lint command line arguments.
|
||||
# args: --issues-exit-code=0
|
||||
# Optional: golangci-lint command line arguments.
|
||||
# args: --issues-exit-code=0
|
||||
|
||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||
# only-new-issues: true
|
||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||
# only-new-issues: true
|
||||
|
||||
# Optional: if set to true then the all caching functionality will be complete disabled,
|
||||
# takes precedence over all other caching options.
|
||||
# skip-cache: true
|
||||
# Optional: if set to true then the all caching functionality will be complete disabled,
|
||||
# takes precedence over all other caching options.
|
||||
# skip-cache: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||
# skip-pkg-cache: true
|
||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||
# skip-pkg-cache: true
|
||||
|
||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
||||
# skip-build-cache: true
|
||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
||||
# skip-build-cache: true
|
||||
|
8
.github/workflows/goreleaser.yml
vendored
8
.github/workflows/goreleaser.yml
vendored
@@ -8,21 +8,21 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22'
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Make All
|
||||
run: |
|
||||
./package.sh
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
version: latest
|
||||
args: release --clean --release-notes=./Release.md
|
||||
|
@@ -1,6 +1,6 @@
|
||||
service:
|
||||
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
|
||||
|
||||
golangci-lint-version: 1.55.x # use the fixed version to not introduce new linters unexpectedly
|
||||
|
||||
run:
|
||||
concurrency: 4
|
||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||
@@ -8,6 +8,23 @@ run:
|
||||
build-tags:
|
||||
- integ
|
||||
- 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:
|
||||
disable-all: true
|
||||
@@ -86,8 +103,12 @@ linters-settings:
|
||||
severity: "low"
|
||||
confidence: "low"
|
||||
excludes:
|
||||
- G102
|
||||
- G112
|
||||
- G306
|
||||
- G401
|
||||
- G402
|
||||
- G404
|
||||
- G501
|
||||
|
||||
issues:
|
||||
@@ -115,14 +136,6 @@ issues:
|
||||
- unparam
|
||||
text: "is always false"
|
||||
|
||||
exclude-dirs:
|
||||
- genfiles$
|
||||
- vendor$
|
||||
- bin$
|
||||
exclude-files:
|
||||
- ".*\\.pb\\.go"
|
||||
- ".*\\.gen\\.go"
|
||||
|
||||
# Independently from option `exclude` we use default exclude patterns,
|
||||
# it can be disabled by this option. To list all
|
||||
# excluded by default patterns execute `golangci-lint run --help`.
|
||||
|
7
Makefile
7
Makefile
@@ -1,14 +1,11 @@
|
||||
export PATH := $(PATH):`go env GOPATH`/bin
|
||||
export PATH := $(GOPATH)/bin:$(PATH)
|
||||
export GO111MODULE=on
|
||||
LDFLAGS := -s -w
|
||||
|
||||
all: env fmt build
|
||||
all: fmt build
|
||||
|
||||
build: frps frpc
|
||||
|
||||
env:
|
||||
@go version
|
||||
|
||||
# compile assets into binary file
|
||||
file:
|
||||
rm -rf ./assets/frps/static/*
|
||||
|
@@ -1,35 +1,23 @@
|
||||
export PATH := $(PATH):`go env GOPATH`/bin
|
||||
export PATH := $(GOPATH)/bin:$(PATH)
|
||||
export GO111MODULE=on
|
||||
LDFLAGS := -s -w
|
||||
|
||||
os-archs=darwin:amd64 darwin:arm64 freebsd:amd64 linux:amd64 linux:arm:7 linux:arm:5 linux:arm64 windows:amd64 windows:arm64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat linux:riscv64 android:arm64
|
||||
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
|
||||
|
||||
all: build
|
||||
|
||||
build: app
|
||||
|
||||
app:
|
||||
@$(foreach n, $(os-archs), \
|
||||
os=$(shell echo "$(n)" | cut -d : -f 1); \
|
||||
arch=$(shell echo "$(n)" | cut -d : -f 2); \
|
||||
extra=$(shell echo "$(n)" | cut -d : -f 3); \
|
||||
flags=''; \
|
||||
target_suffix=$${os}_$${arch}; \
|
||||
if [ "$${os}" = "linux" ] && [ "$${arch}" = "arm" ] && [ "$${extra}" != "" ] ; then \
|
||||
if [ "$${extra}" = "7" ]; then \
|
||||
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"; \
|
||||
@$(foreach n, $(os-archs),\
|
||||
os=$(shell echo "$(n)" | cut -d : -f 1);\
|
||||
arch=$(shell echo "$(n)" | cut -d : -f 2);\
|
||||
gomips=$(shell echo "$(n)" | cut -d : -f 3);\
|
||||
target_suffix=$${os}_$${arch};\
|
||||
echo "Build $${os}-$${arch}...";\
|
||||
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} GOMIPS=$${gomips} go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_$${target_suffix} ./cmd/frpc;\
|
||||
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} GOMIPS=$${gomips} go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_$${target_suffix} ./cmd/frps;\
|
||||
echo "Build $${os}-$${arch} done";\
|
||||
)
|
||||
@mv ./release/frpc_windows_amd64 ./release/frpc_windows_amd64.exe
|
||||
@mv ./release/frps_windows_amd64 ./release/frps_windows_amd64.exe
|
||||
|
40
README.md
40
README.md
@@ -2,8 +2,6 @@
|
||||
|
||||
[](https://circleci.com/gh/fatedier/frp)
|
||||
[](https://github.com/fatedier/frp/releases)
|
||||
[](https://goreportcard.com/report/github.com/fatedier/frp)
|
||||
[](https://somsubhra.github.io/github-release-stats/?username=fatedier&repository=frp)
|
||||
|
||||
[README](README.md) | [中文文档](README_zh.md)
|
||||
|
||||
@@ -14,8 +12,8 @@
|
||||
<img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
|
||||
</a>
|
||||
<a> </a>
|
||||
<a href="https://github.com/daytonaio/daytona" target="_blank">
|
||||
<img width="360px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_daytona.png">
|
||||
<a href="https://www.nango.dev?utm_source=github&utm_medium=oss-banner&utm_campaign=fatedier-frp" target="_blank">
|
||||
<img width="400px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_nango.png">
|
||||
</a>
|
||||
</p>
|
||||
<!--gold sponsors end-->
|
||||
@@ -78,11 +76,9 @@ frp also offers a P2P connect mode.
|
||||
* [URL Routing](#url-routing)
|
||||
* [TCP Port Multiplexing](#tcp-port-multiplexing)
|
||||
* [Connecting to frps via PROXY](#connecting-to-frps-via-proxy)
|
||||
* [Port range mapping](#port-range-mapping)
|
||||
* [Client Plugins](#client-plugins)
|
||||
* [Server Manage Plugins](#server-manage-plugins)
|
||||
* [SSH Tunnel Gateway](#ssh-tunnel-gateway)
|
||||
* [Releated Projects](#releated-projects)
|
||||
* [Contributing](#contributing)
|
||||
* [Donation](#donation)
|
||||
* [GitHub Sponsors](#github-sponsors)
|
||||
@@ -205,11 +201,11 @@ This example implements multiple SSH services exposed through the same port usin
|
||||
|
||||
4. To access internal machine A using SSH ProxyCommand, assuming the username is "test":
|
||||
|
||||
`ssh -o 'proxycommand socat - PROXY:x.x.x.x:%h:%p,proxyport=5002' test@machine-a.example.com`
|
||||
`ssh -o 'proxycommand socat - PROXY:x.x.x.x:machine-a.example.com:22,proxyport=5002' test@machine-a`
|
||||
|
||||
5. To access internal machine B, the only difference is the domain name, assuming the username is "test":
|
||||
|
||||
`ssh -o 'proxycommand socat - PROXY:x.x.x.x:%h:%p,proxyport=5002' test@machine-b.example.com`
|
||||
`ssh -o 'proxycommand socat - PROXY:x.x.x.x:machine-b.example.com:22,proxyport=5002' test@machine-b`
|
||||
|
||||
### Accessing Internal Web Services with Custom Domains in LAN
|
||||
|
||||
@@ -352,6 +348,7 @@ You may substitute `https2https` for the plugin, and point the `localAddr` to a
|
||||
# frpc.toml
|
||||
serverAddr = "x.x.x.x"
|
||||
serverPort = 7000
|
||||
vhostHTTPSPort = 443
|
||||
|
||||
[[proxies]]
|
||||
name = "test_https2http"
|
||||
@@ -529,8 +526,6 @@ Check frp's status and proxies' statistics information by Dashboard.
|
||||
Configure a port for dashboard to enable this feature:
|
||||
|
||||
```toml
|
||||
# The default value is 127.0.0.1. Change it to 0.0.0.0 when you want to access it from a public network.
|
||||
webServer.addr = "0.0.0.0"
|
||||
webServer.port = 7500
|
||||
# dashboard's username and password are both optional
|
||||
webServer.user = "admin"
|
||||
@@ -1003,7 +998,7 @@ In this example, it will set header `x-from-where: frp` in the HTTP request.
|
||||
|
||||
#### HTTP X-Forwarded-For
|
||||
|
||||
This feature is for `http` proxies or proxies with the `https2http` and `https2https` plugins enabled.
|
||||
This feature is for http proxy only.
|
||||
|
||||
You can get user's real IP from HTTP request headers `X-Forwarded-For`.
|
||||
|
||||
@@ -1159,24 +1154,6 @@ serverPort = 7000
|
||||
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
|
||||
|
||||
frpc only forwards requests to local TCP or UDP ports by default.
|
||||
@@ -1244,11 +1221,6 @@ 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.
|
||||
|
||||
## Releated Projects
|
||||
|
||||
* [gofrp/plugin](https://github.com/gofrp/plugin) - A repository for frp plugins that contains a variety of plugins implemented based on the frp extension mechanism, meeting the customization needs of different scenarios.
|
||||
* [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - A lightweight version of the frp client (around 3.5MB at minimum) implemented using the ssh protocol, supporting some of the most commonly used features, suitable for devices with limited resources.
|
||||
|
||||
## Contributing
|
||||
|
||||
Interested in getting involved? We would like to help you!
|
||||
|
17
README_zh.md
17
README_zh.md
@@ -2,8 +2,6 @@
|
||||
|
||||
[](https://circleci.com/gh/fatedier/frp)
|
||||
[](https://github.com/fatedier/frp/releases)
|
||||
[](https://goreportcard.com/report/github.com/fatedier/frp)
|
||||
[](https://somsubhra.github.io/github-release-stats/?username=fatedier&repository=frp)
|
||||
|
||||
[README](README.md) | [中文文档](README_zh.md)
|
||||
|
||||
@@ -16,8 +14,8 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP
|
||||
<img width="350px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
|
||||
</a>
|
||||
<a> </a>
|
||||
<a href="https://github.com/daytonaio/daytona" target="_blank">
|
||||
<img width="360px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_daytona.png">
|
||||
<a href="https://www.nango.dev?utm_source=github&utm_medium=oss-banner&utm_campaign=fatedier-frp" target="_blank">
|
||||
<img width="400px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_nango.png">
|
||||
</a>
|
||||
</p>
|
||||
<!--gold sponsors end-->
|
||||
@@ -72,12 +70,7 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
|
||||
* 贡献代码请提交 PR 至 dev 分支,master 分支仅用于发布稳定可用版本。
|
||||
* 如果你有任何其他方面的问题或合作,欢迎发送邮件至 fatedier@gmail.com 。
|
||||
|
||||
**提醒:和项目相关的问题请在 [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 左右),支持常用的部分功能,适用于资源有限的设备。
|
||||
**提醒:和项目相关的问题最好在 [issues](https://github.com/fatedier/frp/issues) 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。**
|
||||
|
||||
## 赞助
|
||||
|
||||
@@ -98,3 +91,7 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
|
||||
如果您想了解更多 frp 相关技术以及更新详解,或者寻求任何 frp 使用方面的帮助,都可以通过微信扫描下方的二维码付费加入知识星球的官方社群:
|
||||
|
||||

|
||||
|
||||
### 微信支付捐赠
|
||||
|
||||

|
||||
|
10
Release.md
10
Release.md
@@ -1,13 +1,11 @@
|
||||
### Notable Changes
|
||||
### Deprecation Notices
|
||||
|
||||
We have optimized the heartbeat mechanism when tcpmux is enabled (enabled by default). The default value of `heartbeatInterval` has been adjusted to -1. This update ensures that when tcpmux is active, the client does not send additional heartbeats to the server. Since tcpmux incorporates its own heartbeat system, this change effectively reduces unnecessary data consumption, streamlining communication efficiency between client and server.
|
||||
|
||||
When connecting to frps versions older than v0.39.0 might encounter compatibility issues due to changes in the heartbeat mechanism. As a temporary workaround, setting the `heartbeatInterval` to 30 can help maintain stable connectivity with these older versions. We recommend updating to the latest frps version to leverage full functionality and improvements.
|
||||
* Using an underscore in a flag name is deprecated and has been replaced by a hyphen. The underscore format will remain compatible for some time, until it is completely removed in a future version. For example, `--remote_port` is replaced with `--remote-port`.
|
||||
|
||||
### Features
|
||||
|
||||
* Show tcpmux proxies on the frps dashboard.
|
||||
* The `Refresh` and `ClearOfflineProxies` buttons have been added to the Dashboard of frps.
|
||||
|
||||
### Fixes
|
||||
|
||||
* When an HTTP proxy request times out, it returns 504 instead of 404 now.
|
||||
* The host/domain matching in the routing rules has been changed to be case-insensitive.
|
||||
|
84
assets/frps/static/index-1gecbKzv.js
Normal file
84
assets/frps/static/index-1gecbKzv.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
assets/frps/static/index-Lf6B06jY.css
Normal file
1
assets/frps/static/index-Lf6B06jY.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -4,8 +4,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>frps dashboard</title>
|
||||
<script type="module" crossorigin src="./index-82-40HIG.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./index-rzPDshRD.css">
|
||||
<script type="module" crossorigin src="./index-1gecbKzv.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./index-Lf6B06jY.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@@ -15,17 +15,19 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/fatedier/frp/client/proxy"
|
||||
"github.com/fatedier/frp/pkg/config"
|
||||
"github.com/fatedier/frp/pkg/config/v1/validation"
|
||||
@@ -76,9 +78,9 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
|
||||
strictConfigMode, _ = strconv.ParseBool(strictStr)
|
||||
}
|
||||
|
||||
log.Infof("api request [/api/reload]")
|
||||
log.Info("api request [/api/reload]")
|
||||
defer func() {
|
||||
log.Infof("api response [/api/reload], code [%d]", res.Code)
|
||||
log.Info("api response [/api/reload], code [%d]", res.Code)
|
||||
w.WriteHeader(res.Code)
|
||||
if len(res.Msg) > 0 {
|
||||
_, _ = w.Write([]byte(res.Msg))
|
||||
@@ -89,32 +91,32 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
res.Code = 400
|
||||
res.Msg = err.Error()
|
||||
log.Warnf("reload frpc proxy config error: %s", res.Msg)
|
||||
log.Warn("reload frpc proxy config error: %s", res.Msg)
|
||||
return
|
||||
}
|
||||
if _, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs); err != nil {
|
||||
res.Code = 400
|
||||
res.Msg = err.Error()
|
||||
log.Warnf("reload frpc proxy config error: %s", res.Msg)
|
||||
log.Warn("reload frpc proxy config error: %s", res.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
if err := svr.UpdateAllConfigurer(proxyCfgs, visitorCfgs); err != nil {
|
||||
res.Code = 500
|
||||
res.Msg = err.Error()
|
||||
log.Warnf("reload frpc proxy config error: %s", res.Msg)
|
||||
log.Warn("reload frpc proxy config error: %s", res.Msg)
|
||||
return
|
||||
}
|
||||
log.Infof("success reload conf")
|
||||
log.Info("success reload conf")
|
||||
}
|
||||
|
||||
// POST /api/stop
|
||||
func (svr *Service) apiStop(w http.ResponseWriter, _ *http.Request) {
|
||||
res := GeneralResponse{Code: 200}
|
||||
|
||||
log.Infof("api request [/api/stop]")
|
||||
log.Info("api request [/api/stop]")
|
||||
defer func() {
|
||||
log.Infof("api response [/api/stop], code [%d]", res.Code)
|
||||
log.Info("api response [/api/stop], code [%d]", res.Code)
|
||||
w.WriteHeader(res.Code)
|
||||
if len(res.Msg) > 0 {
|
||||
_, _ = w.Write([]byte(res.Msg))
|
||||
@@ -151,7 +153,7 @@ func NewProxyStatusResp(status *proxy.WorkingStatus, serverAddr string) ProxySta
|
||||
|
||||
if status.Err == "" {
|
||||
psr.RemoteAddr = status.RemoteAddr
|
||||
if slices.Contains([]string{"tcp", "udp"}, status.Type) {
|
||||
if lo.Contains([]string{"tcp", "udp"}, status.Type) {
|
||||
psr.RemoteAddr = serverAddr + psr.RemoteAddr
|
||||
}
|
||||
}
|
||||
@@ -165,9 +167,9 @@ func (svr *Service) apiStatus(w http.ResponseWriter, _ *http.Request) {
|
||||
res StatusResp = make(map[string][]ProxyStatusResp)
|
||||
)
|
||||
|
||||
log.Infof("Http request [/api/status]")
|
||||
log.Info("Http request [/api/status]")
|
||||
defer func() {
|
||||
log.Infof("Http response [/api/status]")
|
||||
log.Info("Http response [/api/status]")
|
||||
buf, _ = json.Marshal(&res)
|
||||
_, _ = w.Write(buf)
|
||||
}()
|
||||
@@ -188,8 +190,8 @@ func (svr *Service) apiStatus(w http.ResponseWriter, _ *http.Request) {
|
||||
if len(arrs) <= 1 {
|
||||
continue
|
||||
}
|
||||
slices.SortFunc(arrs, func(a, b ProxyStatusResp) int {
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
sort.Slice(arrs, func(i, j int) bool {
|
||||
return strings.Compare(arrs[i].Name, arrs[j].Name) < 0
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -198,9 +200,9 @@ func (svr *Service) apiStatus(w http.ResponseWriter, _ *http.Request) {
|
||||
func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
|
||||
res := GeneralResponse{Code: 200}
|
||||
|
||||
log.Infof("Http get request [/api/config]")
|
||||
log.Info("Http get request [/api/config]")
|
||||
defer func() {
|
||||
log.Infof("Http get response [/api/config], code [%d]", res.Code)
|
||||
log.Info("Http get response [/api/config], code [%d]", res.Code)
|
||||
w.WriteHeader(res.Code)
|
||||
if len(res.Msg) > 0 {
|
||||
_, _ = w.Write([]byte(res.Msg))
|
||||
@@ -210,7 +212,7 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
|
||||
if svr.configFilePath == "" {
|
||||
res.Code = 400
|
||||
res.Msg = "frpc has no config file path"
|
||||
log.Warnf("%s", res.Msg)
|
||||
log.Warn("%s", res.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -218,7 +220,7 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
|
||||
if err != nil {
|
||||
res.Code = 400
|
||||
res.Msg = err.Error()
|
||||
log.Warnf("load frpc config file error: %s", res.Msg)
|
||||
log.Warn("load frpc config file error: %s", res.Msg)
|
||||
return
|
||||
}
|
||||
res.Msg = string(content)
|
||||
@@ -228,9 +230,9 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, _ *http.Request) {
|
||||
func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
|
||||
res := GeneralResponse{Code: 200}
|
||||
|
||||
log.Infof("Http put request [/api/config]")
|
||||
log.Info("Http put request [/api/config]")
|
||||
defer func() {
|
||||
log.Infof("Http put response [/api/config], code [%d]", res.Code)
|
||||
log.Info("Http put response [/api/config], code [%d]", res.Code)
|
||||
w.WriteHeader(res.Code)
|
||||
if len(res.Msg) > 0 {
|
||||
_, _ = w.Write([]byte(res.Msg))
|
||||
@@ -242,21 +244,21 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
res.Code = 400
|
||||
res.Msg = fmt.Sprintf("read request body error: %v", err)
|
||||
log.Warnf("%s", res.Msg)
|
||||
log.Warn("%s", res.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
if len(body) == 0 {
|
||||
res.Code = 400
|
||||
res.Msg = "body can't be empty"
|
||||
log.Warnf("%s", res.Msg)
|
||||
log.Warn("%s", res.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.WriteFile(svr.configFilePath, body, 0o600); err != nil {
|
||||
if err := os.WriteFile(svr.configFilePath, body, 0o644); err != nil {
|
||||
res.Code = 500
|
||||
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
|
||||
log.Warnf("%s", res.Msg)
|
||||
log.Warn("%s", res.Msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
libnet "github.com/fatedier/golib/net"
|
||||
libdial "github.com/fatedier/golib/net/dial"
|
||||
fmux "github.com/hashicorp/yamux"
|
||||
quic "github.com/quic-go/quic-go"
|
||||
"github.com/samber/lo"
|
||||
@@ -84,7 +84,7 @@ func (c *defaultConnectorImpl) Open() error {
|
||||
tlsConfig, err = transport.NewClientTLSConfig("", "", "", sn)
|
||||
}
|
||||
if err != nil {
|
||||
xl.Warnf("fail to build tls configuration, err: %v", err)
|
||||
xl.Warn("fail to build tls configuration, err: %v", err)
|
||||
return err
|
||||
}
|
||||
tlsConfig.NextProtos = []string{"frp"}
|
||||
@@ -164,49 +164,49 @@ func (c *defaultConnectorImpl) realConnect() (net.Conn, error) {
|
||||
c.cfg.Transport.TLS.TrustedCaFile,
|
||||
sn)
|
||||
if err != nil {
|
||||
xl.Warnf("fail to build tls configuration, err: %v", err)
|
||||
xl.Warn("fail to build tls configuration, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
proxyType, addr, auth, err := libnet.ParseProxyURL(c.cfg.Transport.ProxyURL)
|
||||
proxyType, addr, auth, err := libdial.ParseProxyURL(c.cfg.Transport.ProxyURL)
|
||||
if err != nil {
|
||||
xl.Errorf("fail to parse proxy url")
|
||||
xl.Error("fail to parse proxy url")
|
||||
return nil, err
|
||||
}
|
||||
dialOptions := []libnet.DialOption{}
|
||||
dialOptions := []libdial.DialOption{}
|
||||
protocol := c.cfg.Transport.Protocol
|
||||
switch protocol {
|
||||
case "websocket":
|
||||
protocol = "tcp"
|
||||
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
|
||||
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
|
||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
|
||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
|
||||
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
|
||||
}))
|
||||
dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
|
||||
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
|
||||
case "wss":
|
||||
protocol = "tcp"
|
||||
dialOptions = append(dialOptions, libnet.WithTLSConfigAndPriority(100, tlsConfig))
|
||||
dialOptions = append(dialOptions, libdial.WithTLSConfigAndPriority(100, tlsConfig))
|
||||
// Make sure that if it is wss, the websocket hook is executed after the tls hook.
|
||||
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
|
||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
|
||||
default:
|
||||
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
|
||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
|
||||
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
|
||||
}))
|
||||
dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
|
||||
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
|
||||
}
|
||||
|
||||
if c.cfg.Transport.ConnectServerLocalIP != "" {
|
||||
dialOptions = append(dialOptions, libnet.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
|
||||
dialOptions = append(dialOptions, libdial.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
|
||||
}
|
||||
dialOptions = append(dialOptions,
|
||||
libnet.WithProtocol(protocol),
|
||||
libnet.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
|
||||
libnet.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
|
||||
libnet.WithProxy(proxyType, addr),
|
||||
libnet.WithProxyAuth(auth),
|
||||
libdial.WithProtocol(protocol),
|
||||
libdial.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
|
||||
libdial.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
|
||||
libdial.WithProxy(proxyType, addr),
|
||||
libdial.WithProxyAuth(auth),
|
||||
)
|
||||
conn, err := libnet.DialContext(
|
||||
conn, err := libdial.DialContext(
|
||||
c.ctx,
|
||||
net.JoinHostPort(c.cfg.ServerAddr, strconv.Itoa(c.cfg.ServerPort)),
|
||||
dialOptions...,
|
||||
|
@@ -20,6 +20,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/fatedier/frp/client/proxy"
|
||||
"github.com/fatedier/frp/client/visitor"
|
||||
"github.com/fatedier/frp/pkg/auth"
|
||||
@@ -122,7 +124,7 @@ func (ctl *Control) handleReqWorkConn(_ msg.Message) {
|
||||
xl := ctl.xl
|
||||
workConn, err := ctl.connectServer()
|
||||
if err != nil {
|
||||
xl.Warnf("start new connection to server error: %v", err)
|
||||
xl.Warn("start new connection to server error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -130,24 +132,24 @@ func (ctl *Control) handleReqWorkConn(_ msg.Message) {
|
||||
RunID: ctl.sessionCtx.RunID,
|
||||
}
|
||||
if err = ctl.sessionCtx.AuthSetter.SetNewWorkConn(m); err != nil {
|
||||
xl.Warnf("error during NewWorkConn authentication: %v", err)
|
||||
xl.Warn("error during NewWorkConn authentication: %v", err)
|
||||
workConn.Close()
|
||||
return
|
||||
}
|
||||
if err = msg.WriteMsg(workConn, m); err != nil {
|
||||
xl.Warnf("work connection write to server error: %v", err)
|
||||
xl.Warn("work connection write to server error: %v", err)
|
||||
workConn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
var startMsg msg.StartWorkConn
|
||||
if err = msg.ReadMsgInto(workConn, &startMsg); err != nil {
|
||||
xl.Tracef("work connection closed before response StartWorkConn message: %v", err)
|
||||
xl.Trace("work connection closed before response StartWorkConn message: %v", err)
|
||||
workConn.Close()
|
||||
return
|
||||
}
|
||||
if startMsg.Error != "" {
|
||||
xl.Errorf("StartWorkConn contains error: %s", startMsg.Error)
|
||||
xl.Error("StartWorkConn contains error: %s", startMsg.Error)
|
||||
workConn.Close()
|
||||
return
|
||||
}
|
||||
@@ -163,9 +165,9 @@ func (ctl *Control) handleNewProxyResp(m msg.Message) {
|
||||
// Start a new proxy handler if no error got
|
||||
err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error)
|
||||
if err != nil {
|
||||
xl.Warnf("[%s] start error: %v", inMsg.ProxyName, err)
|
||||
xl.Warn("[%s] start error: %v", inMsg.ProxyName, err)
|
||||
} else {
|
||||
xl.Infof("[%s] start proxy success", inMsg.ProxyName)
|
||||
xl.Info("[%s] start proxy success", inMsg.ProxyName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +178,7 @@ func (ctl *Control) handleNatHoleResp(m msg.Message) {
|
||||
// Dispatch the NatHoleResp message to the related proxy.
|
||||
ok := ctl.msgTransporter.DispatchWithType(inMsg, msg.TypeNameNatHoleResp, inMsg.TransactionID)
|
||||
if !ok {
|
||||
xl.Tracef("dispatch NatHoleResp message to related proxy error")
|
||||
xl.Trace("dispatch NatHoleResp message to related proxy error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,12 +187,12 @@ func (ctl *Control) handlePong(m msg.Message) {
|
||||
inMsg := m.(*msg.Pong)
|
||||
|
||||
if inMsg.Error != "" {
|
||||
xl.Errorf("Pong message contains error: %s", inMsg.Error)
|
||||
xl.Error("Pong message contains error: %s", inMsg.Error)
|
||||
ctl.closeSession()
|
||||
return
|
||||
}
|
||||
ctl.lastPong.Store(time.Now())
|
||||
xl.Debugf("receive heartbeat from server")
|
||||
xl.Debug("receive heartbeat from server")
|
||||
}
|
||||
|
||||
// closeSession closes the control connection.
|
||||
@@ -234,13 +236,15 @@ func (ctl *Control) registerMsgHandlers() {
|
||||
func (ctl *Control) heartbeatWorker() {
|
||||
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 {
|
||||
// Send heartbeat to server.
|
||||
// send heartbeat to server
|
||||
sendHeartBeat := func() (bool, error) {
|
||||
xl.Debugf("send heartbeat to server")
|
||||
xl.Debug("send heartbeat to server")
|
||||
pingMsg := &msg.Ping{}
|
||||
if err := ctl.sessionCtx.AuthSetter.SetPing(pingMsg); err != nil {
|
||||
xl.Warnf("error during ping authentication: %v, skip sending ping message", err)
|
||||
xl.Warn("error during ping authentication: %v, skip sending ping message", err)
|
||||
return false, err
|
||||
}
|
||||
_ = ctl.msgDispatcher.Send(pingMsg)
|
||||
@@ -259,11 +263,13 @@ func (ctl *Control) heartbeatWorker() {
|
||||
)
|
||||
}
|
||||
|
||||
// Check heartbeat timeout.
|
||||
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 {
|
||||
// Check heartbeat timeout only if TCPMux is not enabled and users don't disable heartbeat feature.
|
||||
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 &&
|
||||
!lo.FromPtr(ctl.sessionCtx.Common.Transport.TCPMux) {
|
||||
|
||||
go wait.Until(func() {
|
||||
if time.Since(ctl.lastPong.Load().(time.Time)) > time.Duration(ctl.sessionCtx.Common.Transport.HeartbeatTimeout)*time.Second {
|
||||
xl.Warnf("heartbeat timeout")
|
||||
xl.Warn("heartbeat timeout")
|
||||
ctl.closeSession()
|
||||
return
|
||||
}
|
||||
|
@@ -40,8 +40,8 @@ type Monitor struct {
|
||||
addr string
|
||||
|
||||
// For http
|
||||
url string
|
||||
header http.Header
|
||||
url string
|
||||
|
||||
failedTimes uint64
|
||||
statusOK bool
|
||||
statusNormalFn func()
|
||||
@@ -73,11 +73,6 @@ func NewMonitor(ctx context.Context, cfg v1.HealthCheckConfig, addr string,
|
||||
}
|
||||
url = s + cfg.Path
|
||||
}
|
||||
header := make(http.Header)
|
||||
for _, h := range cfg.HTTPHeaders {
|
||||
header.Set(h.Name, h.Value)
|
||||
}
|
||||
|
||||
return &Monitor{
|
||||
checkType: cfg.Type,
|
||||
interval: time.Duration(cfg.IntervalSeconds) * time.Second,
|
||||
@@ -85,7 +80,6 @@ func NewMonitor(ctx context.Context, cfg v1.HealthCheckConfig, addr string,
|
||||
maxFailedTimes: cfg.MaxFailed,
|
||||
addr: addr,
|
||||
url: url,
|
||||
header: header,
|
||||
statusOK: false,
|
||||
statusNormalFn: statusNormalFn,
|
||||
statusFailedFn: statusFailedFn,
|
||||
@@ -118,17 +112,17 @@ func (monitor *Monitor) checkWorker() {
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
xl.Tracef("do one health check success")
|
||||
xl.Trace("do one health check success")
|
||||
if !monitor.statusOK && monitor.statusNormalFn != nil {
|
||||
xl.Infof("health check status change to success")
|
||||
xl.Info("health check status change to success")
|
||||
monitor.statusOK = true
|
||||
monitor.statusNormalFn()
|
||||
}
|
||||
} else {
|
||||
xl.Warnf("do one health check failed: %v", err)
|
||||
xl.Warn("do one health check failed: %v", err)
|
||||
monitor.failedTimes++
|
||||
if monitor.statusOK && int(monitor.failedTimes) >= monitor.maxFailedTimes && monitor.statusFailedFn != nil {
|
||||
xl.Warnf("health check status change to failed")
|
||||
xl.Warn("health check status change to failed")
|
||||
monitor.statusOK = false
|
||||
monitor.statusFailedFn()
|
||||
}
|
||||
@@ -169,8 +163,6 @@ func (monitor *Monitor) doHTTPCheck(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header = monitor.header
|
||||
req.Host = monitor.header.Get("Host")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -25,7 +25,7 @@ import (
|
||||
"time"
|
||||
|
||||
libio "github.com/fatedier/golib/io"
|
||||
libnet "github.com/fatedier/golib/net"
|
||||
libdial "github.com/fatedier/golib/net/dial"
|
||||
pp "github.com/pires/go-proxyproto"
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
@@ -141,13 +141,13 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
|
||||
})
|
||||
}
|
||||
|
||||
xl.Tracef("handle tcp work connection, useEncryption: %t, useCompression: %t",
|
||||
xl.Trace("handle tcp work connection, useEncryption: %t, useCompression: %t",
|
||||
baseCfg.Transport.UseEncryption, baseCfg.Transport.UseCompression)
|
||||
if baseCfg.Transport.UseEncryption {
|
||||
remote, err = libio.WithEncryption(remote, encKey)
|
||||
if err != nil {
|
||||
workConn.Close()
|
||||
xl.Errorf("create encryption stream error: %v", err)
|
||||
xl.Error("create encryption stream error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -158,70 +158,68 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
|
||||
|
||||
// check if we need to send proxy protocol info
|
||||
var extraInfo plugin.ExtraInfo
|
||||
if m.SrcAddr != "" && m.SrcPort != 0 {
|
||||
if m.DstAddr == "" {
|
||||
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))))
|
||||
extraInfo.SrcAddr = srcAddr
|
||||
extraInfo.DstAddr = dstAddr
|
||||
}
|
||||
if baseCfg.Transport.ProxyProtocolVersion != "" {
|
||||
if m.SrcAddr != "" && m.SrcPort != 0 {
|
||||
if m.DstAddr == "" {
|
||||
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 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 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
|
||||
}
|
||||
|
||||
if baseCfg.Transport.ProxyProtocolVersion == "v1" {
|
||||
h.Version = 1
|
||||
} else if baseCfg.Transport.ProxyProtocolVersion == "v2" {
|
||||
h.Version = 2
|
||||
extraInfo.ProxyProtocolHeader = h
|
||||
}
|
||||
extraInfo.ProxyProtocolHeader = h
|
||||
}
|
||||
|
||||
if pxy.proxyPlugin != nil {
|
||||
// if plugin is set, let plugin handle connection first
|
||||
xl.Debugf("handle by plugin: %s", pxy.proxyPlugin.Name())
|
||||
xl.Debug("handle by plugin: %s", pxy.proxyPlugin.Name())
|
||||
pxy.proxyPlugin.Handle(remote, workConn, &extraInfo)
|
||||
xl.Debugf("handle by plugin finished")
|
||||
xl.Debug("handle by plugin finished")
|
||||
return
|
||||
}
|
||||
|
||||
localConn, err := libnet.Dial(
|
||||
localConn, err := libdial.Dial(
|
||||
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
|
||||
libnet.WithTimeout(10*time.Second),
|
||||
libdial.WithTimeout(10*time.Second),
|
||||
)
|
||||
if err != nil {
|
||||
workConn.Close()
|
||||
xl.Errorf("connect to local service [%s:%d] error: %v", baseCfg.LocalIP, baseCfg.LocalPort, err)
|
||||
xl.Error("connect to local service [%s:%d] error: %v", baseCfg.LocalIP, baseCfg.LocalPort, err)
|
||||
return
|
||||
}
|
||||
|
||||
xl.Debugf("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
|
||||
xl.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
|
||||
localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
||||
|
||||
if extraInfo.ProxyProtocolHeader != nil {
|
||||
if _, err := extraInfo.ProxyProtocolHeader.WriteTo(localConn); err != nil {
|
||||
workConn.Close()
|
||||
xl.Errorf("write proxy protocol header to local conn error: %v", err)
|
||||
xl.Error("write proxy protocol header to local conn error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, _, errs := libio.Join(localConn, remote)
|
||||
xl.Debugf("join connections closed")
|
||||
xl.Debug("join connections closed")
|
||||
if len(errs) > 0 {
|
||||
xl.Tracef("join connections errors: %v", errs)
|
||||
xl.Trace("join connections errors: %v", errs)
|
||||
}
|
||||
if compressionResourceRecycleFn != nil {
|
||||
compressionResourceRecycleFn()
|
||||
|
@@ -152,7 +152,7 @@ func (pm *Manager) UpdateAll(proxyCfgs []v1.ProxyConfigurer) {
|
||||
}
|
||||
}
|
||||
if len(delPxyNames) > 0 {
|
||||
xl.Infof("proxy removed: %s", delPxyNames)
|
||||
xl.Info("proxy removed: %s", delPxyNames)
|
||||
}
|
||||
|
||||
addPxyNames := make([]string, 0)
|
||||
@@ -170,6 +170,6 @@ func (pm *Manager) UpdateAll(proxyCfgs []v1.ProxyConfigurer) {
|
||||
}
|
||||
}
|
||||
if len(addPxyNames) > 0 {
|
||||
xl.Infof("proxy added: %s", addPxyNames)
|
||||
xl.Info("proxy added: %s", addPxyNames)
|
||||
}
|
||||
}
|
||||
|
@@ -114,7 +114,7 @@ func NewWrapper(
|
||||
addr := net.JoinHostPort(baseInfo.LocalIP, strconv.Itoa(baseInfo.LocalPort))
|
||||
pw.monitor = health.NewMonitor(pw.ctx, baseInfo.HealthCheck, addr,
|
||||
pw.statusNormalCallback, pw.statusFailedCallback)
|
||||
xl.Tracef("enable health check monitor")
|
||||
xl.Trace("enable health check monitor")
|
||||
}
|
||||
|
||||
pw.pxy = NewProxy(pw.ctx, pw.Cfg, clientCfg, pw.msgTransporter)
|
||||
@@ -197,7 +197,7 @@ func (pw *Wrapper) checkWorker() {
|
||||
(pw.Phase == ProxyPhaseWaitStart && now.After(pw.lastSendStartMsg.Add(waitResponseTimeout))) ||
|
||||
(pw.Phase == ProxyPhaseStartErr && now.After(pw.lastStartErr.Add(startErrTimeout))) {
|
||||
|
||||
xl.Tracef("change status from [%s] to [%s]", pw.Phase, ProxyPhaseWaitStart)
|
||||
xl.Trace("change status from [%s] to [%s]", pw.Phase, ProxyPhaseWaitStart)
|
||||
pw.Phase = ProxyPhaseWaitStart
|
||||
|
||||
var newProxyMsg msg.NewProxy
|
||||
@@ -212,7 +212,7 @@ func (pw *Wrapper) checkWorker() {
|
||||
pw.mu.Lock()
|
||||
if pw.Phase == ProxyPhaseRunning || pw.Phase == ProxyPhaseWaitStart {
|
||||
pw.close()
|
||||
xl.Tracef("change status from [%s] to [%s]", pw.Phase, ProxyPhaseCheckFailed)
|
||||
xl.Trace("change status from [%s] to [%s]", pw.Phase, ProxyPhaseCheckFailed)
|
||||
pw.Phase = ProxyPhaseCheckFailed
|
||||
}
|
||||
pw.mu.Unlock()
|
||||
@@ -236,7 +236,7 @@ func (pw *Wrapper) statusNormalCallback() {
|
||||
default:
|
||||
}
|
||||
})
|
||||
xl.Infof("health check success")
|
||||
xl.Info("health check success")
|
||||
}
|
||||
|
||||
func (pw *Wrapper) statusFailedCallback() {
|
||||
@@ -248,7 +248,7 @@ func (pw *Wrapper) statusFailedCallback() {
|
||||
default:
|
||||
}
|
||||
})
|
||||
xl.Infof("health check failed")
|
||||
xl.Info("health check failed")
|
||||
}
|
||||
|
||||
func (pw *Wrapper) InWorkConn(workConn net.Conn, m *msg.StartWorkConn) {
|
||||
@@ -257,7 +257,7 @@ func (pw *Wrapper) InWorkConn(workConn net.Conn, m *msg.StartWorkConn) {
|
||||
pxy := pw.pxy
|
||||
pw.mu.RUnlock()
|
||||
if pxy != nil && pw.Phase == ProxyPhaseRunning {
|
||||
xl.Debugf("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
||||
xl.Debug("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
||||
go pxy.InWorkConn(workConn, m)
|
||||
} else {
|
||||
workConn.Close()
|
||||
|
@@ -81,7 +81,7 @@ func (pxy *SUDPProxy) Close() {
|
||||
|
||||
func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
xl := pxy.xl
|
||||
xl.Infof("incoming a new work connection for sudp proxy, %s", conn.RemoteAddr().String())
|
||||
xl.Info("incoming a new work connection for sudp proxy, %s", conn.RemoteAddr().String())
|
||||
|
||||
var rwc io.ReadWriteCloser = conn
|
||||
var err error
|
||||
@@ -94,7 +94,7 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
rwc, err = libio.WithEncryption(rwc, []byte(pxy.clientCfg.Auth.Token))
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
xl.Errorf("create encryption stream error: %v", err)
|
||||
xl.Error("create encryption stream error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -133,21 +133,21 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
// first to check sudp proxy is closed or not
|
||||
select {
|
||||
case <-pxy.closeCh:
|
||||
xl.Tracef("frpc sudp proxy is closed")
|
||||
xl.Trace("frpc sudp proxy is closed")
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
var udpMsg msg.UDPPacket
|
||||
if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
|
||||
xl.Warnf("read from workConn for sudp error: %v", errRet)
|
||||
xl.Warn("read from workConn for sudp error: %v", errRet)
|
||||
return
|
||||
}
|
||||
|
||||
if errRet := errors.PanicToError(func() {
|
||||
readCh <- &udpMsg
|
||||
}); errRet != nil {
|
||||
xl.Warnf("reader goroutine for sudp work connection closed: %v", errRet)
|
||||
xl.Warn("reader goroutine for sudp work connection closed: %v", errRet)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -157,21 +157,21 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
|
||||
defer func() {
|
||||
closeFn()
|
||||
xl.Infof("writer goroutine for sudp work connection closed")
|
||||
xl.Info("writer goroutine for sudp work connection closed")
|
||||
}()
|
||||
|
||||
var errRet error
|
||||
for rawMsg := range sendCh {
|
||||
switch m := rawMsg.(type) {
|
||||
case *msg.UDPPacket:
|
||||
xl.Tracef("frpc send udp package to frpc visitor, [udp local: %v, remote: %v], [tcp work conn local: %v, remote: %v]",
|
||||
xl.Trace("frpc send udp package to frpc visitor, [udp local: %v, remote: %v], [tcp work conn local: %v, remote: %v]",
|
||||
m.LocalAddr.String(), m.RemoteAddr.String(), conn.LocalAddr().String(), conn.RemoteAddr().String())
|
||||
case *msg.Ping:
|
||||
xl.Tracef("frpc send ping message to frpc visitor")
|
||||
xl.Trace("frpc send ping message to frpc visitor")
|
||||
}
|
||||
|
||||
if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
|
||||
xl.Errorf("sudp work write error: %v", errRet)
|
||||
xl.Error("sudp work write error: %v", errRet)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -191,11 +191,11 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
if errRet = errors.PanicToError(func() {
|
||||
sendCh <- &msg.Ping{}
|
||||
}); errRet != nil {
|
||||
xl.Warnf("heartbeat goroutine for sudp work connection closed")
|
||||
xl.Warn("heartbeat goroutine for sudp work connection closed")
|
||||
return
|
||||
}
|
||||
case <-pxy.closeCh:
|
||||
xl.Tracef("frpc sudp proxy is closed")
|
||||
xl.Trace("frpc sudp proxy is closed")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ func (pxy *UDPProxy) Close() {
|
||||
|
||||
func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
xl := pxy.xl
|
||||
xl.Infof("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
|
||||
xl.Info("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
|
||||
// close resources related with old workConn
|
||||
pxy.Close()
|
||||
|
||||
@@ -105,7 +105,7 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
rwc, err = libio.WithEncryption(rwc, []byte(pxy.clientCfg.Auth.Token))
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
xl.Errorf("create encryption stream error: %v", err)
|
||||
xl.Error("create encryption stream error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -125,32 +125,32 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
for {
|
||||
var udpMsg msg.UDPPacket
|
||||
if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
|
||||
xl.Warnf("read from workConn for udp error: %v", errRet)
|
||||
xl.Warn("read from workConn for udp error: %v", errRet)
|
||||
return
|
||||
}
|
||||
if errRet := errors.PanicToError(func() {
|
||||
xl.Tracef("get udp package from workConn: %s", udpMsg.Content)
|
||||
xl.Trace("get udp package from workConn: %s", udpMsg.Content)
|
||||
readCh <- &udpMsg
|
||||
}); errRet != nil {
|
||||
xl.Infof("reader goroutine for udp work connection closed: %v", errRet)
|
||||
xl.Info("reader goroutine for udp work connection closed: %v", errRet)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
|
||||
defer func() {
|
||||
xl.Infof("writer goroutine for udp work connection closed")
|
||||
xl.Info("writer goroutine for udp work connection closed")
|
||||
}()
|
||||
var errRet error
|
||||
for rawMsg := range sendCh {
|
||||
switch m := rawMsg.(type) {
|
||||
case *msg.UDPPacket:
|
||||
xl.Tracef("send udp package to workConn: %s", m.Content)
|
||||
xl.Trace("send udp package to workConn: %s", m.Content)
|
||||
case *msg.Ping:
|
||||
xl.Tracef("send ping message to udp workConn")
|
||||
xl.Trace("send ping message to udp workConn")
|
||||
}
|
||||
if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
|
||||
xl.Errorf("udp work write error: %v", errRet)
|
||||
xl.Error("udp work write error: %v", errRet)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
||||
if errRet = errors.PanicToError(func() {
|
||||
sendCh <- &msg.Ping{}
|
||||
}); errRet != nil {
|
||||
xl.Tracef("heartbeat goroutine for udp work connection closed")
|
||||
xl.Trace("heartbeat goroutine for udp work connection closed")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@@ -59,17 +59,17 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
|
||||
var natHoleSidMsg msg.NatHoleSid
|
||||
err := msg.ReadMsgInto(conn, &natHoleSidMsg)
|
||||
if err != nil {
|
||||
xl.Errorf("xtcp read from workConn error: %v", err)
|
||||
xl.Error("xtcp read from workConn error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
xl.Tracef("nathole prepare start")
|
||||
xl.Trace("nathole prepare start")
|
||||
prepareResult, err := nathole.Prepare([]string{pxy.clientCfg.NatHoleSTUNServer})
|
||||
if err != nil {
|
||||
xl.Warnf("nathole prepare error: %v", err)
|
||||
xl.Warn("nathole prepare error: %v", err)
|
||||
return
|
||||
}
|
||||
xl.Infof("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v",
|
||||
xl.Info("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v",
|
||||
prepareResult.NatType, prepareResult.Behavior, prepareResult.Addrs, prepareResult.AssistedAddrs)
|
||||
defer prepareResult.ListenConn.Close()
|
||||
|
||||
@@ -83,14 +83,14 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
|
||||
AssistedAddrs: prepareResult.AssistedAddrs,
|
||||
}
|
||||
|
||||
xl.Tracef("nathole exchange info start")
|
||||
xl.Trace("nathole exchange info start")
|
||||
natHoleRespMsg, err := nathole.ExchangeInfo(pxy.ctx, pxy.msgTransporter, transactionID, natHoleClientMsg, 5*time.Second)
|
||||
if err != nil {
|
||||
xl.Warnf("nathole exchange info error: %v", err)
|
||||
xl.Warn("nathole exchange info error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
xl.Infof("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v",
|
||||
xl.Info("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v",
|
||||
natHoleRespMsg.Sid, natHoleRespMsg.Protocol, natHoleRespMsg.CandidateAddrs,
|
||||
natHoleRespMsg.AssistedAddrs, natHoleRespMsg.DetectBehavior)
|
||||
|
||||
@@ -98,7 +98,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
|
||||
newListenConn, raddr, err := nathole.MakeHole(pxy.ctx, listenConn, natHoleRespMsg, []byte(pxy.cfg.Secretkey))
|
||||
if err != nil {
|
||||
listenConn.Close()
|
||||
xl.Warnf("make hole error: %v", err)
|
||||
xl.Warn("make hole error: %v", err)
|
||||
_ = pxy.msgTransporter.Send(&msg.NatHoleReport{
|
||||
Sid: natHoleRespMsg.Sid,
|
||||
Success: false,
|
||||
@@ -106,7 +106,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
|
||||
return
|
||||
}
|
||||
listenConn = newListenConn
|
||||
xl.Infof("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr)
|
||||
xl.Info("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr)
|
||||
|
||||
_ = pxy.msgTransporter.Send(&msg.NatHoleReport{
|
||||
Sid: natHoleRespMsg.Sid,
|
||||
@@ -128,14 +128,14 @@ func (pxy *XTCPProxy) listenByKCP(listenConn *net.UDPConn, raddr *net.UDPAddr, s
|
||||
laddr, _ := net.ResolveUDPAddr("udp", listenConn.LocalAddr().String())
|
||||
lConn, err := net.DialUDP("udp", laddr, raddr)
|
||||
if err != nil {
|
||||
xl.Warnf("dial udp error: %v", err)
|
||||
xl.Warn("dial udp error: %v", err)
|
||||
return
|
||||
}
|
||||
defer lConn.Close()
|
||||
|
||||
remote, err := netpkg.NewKCPConnFromUDP(lConn, true, raddr.String())
|
||||
if err != nil {
|
||||
xl.Warnf("create kcp connection from udp connection error: %v", err)
|
||||
xl.Warn("create kcp connection from udp connection error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (pxy *XTCPProxy) listenByKCP(listenConn *net.UDPConn, raddr *net.UDPAddr, s
|
||||
fmuxCfg.LogOutput = io.Discard
|
||||
session, err := fmux.Server(remote, fmuxCfg)
|
||||
if err != nil {
|
||||
xl.Errorf("create mux session error: %v", err)
|
||||
xl.Error("create mux session error: %v", err)
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
@@ -153,7 +153,7 @@ func (pxy *XTCPProxy) listenByKCP(listenConn *net.UDPConn, raddr *net.UDPAddr, s
|
||||
for {
|
||||
muxConn, err := session.Accept()
|
||||
if err != nil {
|
||||
xl.Errorf("accept connection error: %v", err)
|
||||
xl.Error("accept connection error: %v", err)
|
||||
return
|
||||
}
|
||||
go pxy.HandleTCPWorkConnection(muxConn, startWorkConnMsg, []byte(pxy.cfg.Secretkey))
|
||||
@@ -166,7 +166,7 @@ func (pxy *XTCPProxy) listenByQUIC(listenConn *net.UDPConn, _ *net.UDPAddr, star
|
||||
|
||||
tlsConfig, err := transport.NewServerTLSConfig("", "", "")
|
||||
if err != nil {
|
||||
xl.Warnf("create tls config error: %v", err)
|
||||
xl.Warn("create tls config error: %v", err)
|
||||
return
|
||||
}
|
||||
tlsConfig.NextProtos = []string{"frp"}
|
||||
@@ -178,19 +178,19 @@ func (pxy *XTCPProxy) listenByQUIC(listenConn *net.UDPConn, _ *net.UDPAddr, star
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
xl.Warnf("dial quic error: %v", err)
|
||||
xl.Warn("dial quic error: %v", err)
|
||||
return
|
||||
}
|
||||
// only accept one connection from raddr
|
||||
c, err := quicListener.Accept(pxy.ctx)
|
||||
if err != nil {
|
||||
xl.Errorf("quic accept connection error: %v", err)
|
||||
xl.Error("quic accept connection error: %v", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
stream, err := c.AcceptStream(pxy.ctx)
|
||||
if err != nil {
|
||||
xl.Debugf("quic accept stream error: %v", err)
|
||||
xl.Debug("quic accept stream error: %v", err)
|
||||
_ = c.CloseWithError(0, "")
|
||||
return
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -41,12 +40,6 @@ import (
|
||||
|
||||
func init() {
|
||||
crypto.DefaultSalt = "frp"
|
||||
// Disable quic-go's receive buffer warning.
|
||||
os.Setenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING", "true")
|
||||
// Disable quic-go's ECN support by default. It may cause issues on certain operating systems.
|
||||
if os.Getenv("QUIC_GO_DISABLE_ECN") == "" {
|
||||
os.Setenv("QUIC_GO_DISABLE_ECN", "true")
|
||||
}
|
||||
}
|
||||
|
||||
type cancelErr struct {
|
||||
@@ -181,9 +174,9 @@ func (svr *Service) Run(ctx context.Context) error {
|
||||
|
||||
if svr.webServer != nil {
|
||||
go func() {
|
||||
log.Infof("admin server listen on %s", svr.webServer.Address())
|
||||
log.Info("admin server listen on %s", svr.webServer.Address())
|
||||
if err := svr.webServer.Run(); err != nil {
|
||||
log.Warnf("admin server exit with error: %v", err)
|
||||
log.Warn("admin server exit with error: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -276,14 +269,14 @@ func (svr *Service) login() (conn net.Conn, connector Connector, err error) {
|
||||
|
||||
if loginRespMsg.Error != "" {
|
||||
err = fmt.Errorf("%s", loginRespMsg.Error)
|
||||
xl.Errorf("%s", loginRespMsg.Error)
|
||||
xl.Error("%s", loginRespMsg.Error)
|
||||
return
|
||||
}
|
||||
|
||||
svr.runID = loginRespMsg.RunID
|
||||
xl.AddPrefix(xlog.LogPrefix{Name: "runID", Value: svr.runID})
|
||||
|
||||
xl.Infof("login to server success, get run id [%s]", loginRespMsg.RunID)
|
||||
xl.Info("login to server success, get run id [%s]", loginRespMsg.RunID)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -291,10 +284,10 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE
|
||||
xl := xlog.FromContextSafe(svr.ctx)
|
||||
|
||||
loginFunc := func() (bool, error) {
|
||||
xl.Infof("try to connect to server...")
|
||||
xl.Info("try to connect to server...")
|
||||
conn, connector, err := svr.login()
|
||||
if err != nil {
|
||||
xl.Warnf("connect to server error: %v", err)
|
||||
xl.Warn("connect to server error: %v", err)
|
||||
if firstLoginExit {
|
||||
svr.cancel(cancelErr{Err: err})
|
||||
}
|
||||
@@ -320,7 +313,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE
|
||||
ctl, err := NewControl(svr.ctx, sessionCtx)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
xl.Errorf("NewControl error: %v", err)
|
||||
xl.Error("NewControl error: %v", err)
|
||||
return false, err
|
||||
}
|
||||
ctl.SetInWorkConnCallback(svr.handleWorkConnCb)
|
||||
@@ -380,31 +373,18 @@ func (svr *Service) stop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (svr *Service) getProxyStatus(name string) (*proxy.WorkingStatus, bool) {
|
||||
// TODO(fatedier): Use StatusExporter to provide query interfaces instead of directly using methods from the Service.
|
||||
func (svr *Service) GetProxyStatus(name string) (*proxy.WorkingStatus, error) {
|
||||
svr.ctlMu.RLock()
|
||||
ctl := svr.ctl
|
||||
svr.ctlMu.RUnlock()
|
||||
|
||||
if ctl == nil {
|
||||
return nil, false
|
||||
return nil, fmt.Errorf("control is not running")
|
||||
}
|
||||
return ctl.pm.GetProxyStatus(name)
|
||||
}
|
||||
|
||||
func (svr *Service) StatusExporter() StatusExporter {
|
||||
return &statusExporterImpl{
|
||||
getProxyStatusFunc: svr.getProxyStatus,
|
||||
ws, ok := ctl.pm.GetProxyStatus(name)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("proxy [%s] is not found", name)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
return ws, nil
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ func (sv *STCPVisitor) worker() {
|
||||
for {
|
||||
conn, err := sv.l.Accept()
|
||||
if err != nil {
|
||||
xl.Warnf("stcp local listener closed")
|
||||
xl.Warn("stcp local listener closed")
|
||||
return
|
||||
}
|
||||
go sv.handleConn(conn)
|
||||
@@ -68,7 +68,7 @@ func (sv *STCPVisitor) internalConnWorker() {
|
||||
for {
|
||||
conn, err := sv.internalLn.Accept()
|
||||
if err != nil {
|
||||
xl.Warnf("stcp internal listener closed")
|
||||
xl.Warn("stcp internal listener closed")
|
||||
return
|
||||
}
|
||||
go sv.handleConn(conn)
|
||||
@@ -79,7 +79,7 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
|
||||
xl := xlog.FromContextSafe(sv.ctx)
|
||||
defer userConn.Close()
|
||||
|
||||
xl.Debugf("get a new stcp user connection")
|
||||
xl.Debug("get a new stcp user connection")
|
||||
visitorConn, err := sv.helper.ConnectServer()
|
||||
if err != nil {
|
||||
return
|
||||
@@ -97,7 +97,7 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
|
||||
}
|
||||
err = msg.WriteMsg(visitorConn, newVisitorConnMsg)
|
||||
if err != nil {
|
||||
xl.Warnf("send newVisitorConnMsg to server error: %v", err)
|
||||
xl.Warn("send newVisitorConnMsg to server error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,13 +105,13 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
|
||||
_ = visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
||||
err = msg.ReadMsgInto(visitorConn, &newVisitorConnRespMsg)
|
||||
if err != nil {
|
||||
xl.Warnf("get newVisitorConnRespMsg error: %v", err)
|
||||
xl.Warn("get newVisitorConnRespMsg error: %v", err)
|
||||
return
|
||||
}
|
||||
_ = visitorConn.SetReadDeadline(time.Time{})
|
||||
|
||||
if newVisitorConnRespMsg.Error != "" {
|
||||
xl.Warnf("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
|
||||
xl.Warn("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
|
||||
if sv.cfg.Transport.UseEncryption {
|
||||
remote, err = libio.WithEncryption(remote, []byte(sv.cfg.SecretKey))
|
||||
if err != nil {
|
||||
xl.Errorf("create encryption stream error: %v", err)
|
||||
xl.Error("create encryption stream error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ func (sv *SUDPVisitor) Run() (err error) {
|
||||
sv.sendCh = make(chan *msg.UDPPacket, 1024)
|
||||
sv.readCh = make(chan *msg.UDPPacket, 1024)
|
||||
|
||||
xl.Infof("sudp start to work, listen on %s", addr)
|
||||
xl.Info("sudp start to work, listen on %s", addr)
|
||||
|
||||
go sv.dispatcher()
|
||||
go udp.ForwardUserConn(sv.udpConn, sv.readCh, sv.sendCh, int(sv.clientCfg.UDPPacketSize))
|
||||
@@ -84,17 +84,17 @@ func (sv *SUDPVisitor) dispatcher() {
|
||||
select {
|
||||
case firstPacket = <-sv.sendCh:
|
||||
if firstPacket == nil {
|
||||
xl.Infof("frpc sudp visitor proxy is closed")
|
||||
xl.Info("frpc sudp visitor proxy is closed")
|
||||
return
|
||||
}
|
||||
case <-sv.checkCloseCh:
|
||||
xl.Infof("frpc sudp visitor proxy is closed")
|
||||
xl.Info("frpc sudp visitor proxy is closed")
|
||||
return
|
||||
}
|
||||
|
||||
visitorConn, err = sv.getNewVisitorConn()
|
||||
if err != nil {
|
||||
xl.Warnf("newVisitorConn to frps error: %v, try to reconnect", err)
|
||||
xl.Warn("newVisitorConn to frps error: %v, try to reconnect", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ func (sv *SUDPVisitor) dispatcher() {
|
||||
|
||||
func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
|
||||
xl := xlog.FromContextSafe(sv.ctx)
|
||||
xl.Debugf("starting sudp proxy worker")
|
||||
xl.Debug("starting sudp proxy worker")
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
@@ -134,21 +134,21 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
|
||||
// frpc will send heartbeat in workConn to frpc visitor for keeping alive
|
||||
_ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
||||
if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil {
|
||||
xl.Warnf("read from workconn for user udp conn error: %v", errRet)
|
||||
xl.Warn("read from workconn for user udp conn error: %v", errRet)
|
||||
return
|
||||
}
|
||||
|
||||
_ = conn.SetReadDeadline(time.Time{})
|
||||
switch m := rawMsg.(type) {
|
||||
case *msg.Ping:
|
||||
xl.Debugf("frpc visitor get ping message from frpc")
|
||||
xl.Debug("frpc visitor get ping message from frpc")
|
||||
continue
|
||||
case *msg.UDPPacket:
|
||||
if errRet := errors.PanicToError(func() {
|
||||
sv.readCh <- m
|
||||
xl.Tracef("frpc visitor get udp packet from workConn: %s", m.Content)
|
||||
xl.Trace("frpc visitor get udp packet from workConn: %s", m.Content)
|
||||
}); errRet != nil {
|
||||
xl.Infof("reader goroutine for udp work connection closed")
|
||||
xl.Info("reader goroutine for udp work connection closed")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -165,25 +165,25 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
|
||||
var errRet error
|
||||
if firstPacket != nil {
|
||||
if errRet = msg.WriteMsg(conn, firstPacket); errRet != nil {
|
||||
xl.Warnf("sender goroutine for udp work connection closed: %v", errRet)
|
||||
xl.Warn("sender goroutine for udp work connection closed: %v", errRet)
|
||||
return
|
||||
}
|
||||
xl.Tracef("send udp package to workConn: %s", firstPacket.Content)
|
||||
xl.Trace("send udp package to workConn: %s", firstPacket.Content)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case udpMsg, ok := <-sv.sendCh:
|
||||
if !ok {
|
||||
xl.Infof("sender goroutine for udp work connection closed")
|
||||
xl.Info("sender goroutine for udp work connection closed")
|
||||
return
|
||||
}
|
||||
|
||||
if errRet = msg.WriteMsg(conn, udpMsg); errRet != nil {
|
||||
xl.Warnf("sender goroutine for udp work connection closed: %v", errRet)
|
||||
xl.Warn("sender goroutine for udp work connection closed: %v", errRet)
|
||||
return
|
||||
}
|
||||
xl.Tracef("send udp package to workConn: %s", udpMsg.Content)
|
||||
xl.Trace("send udp package to workConn: %s", udpMsg.Content)
|
||||
case <-closeCh:
|
||||
return
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
|
||||
go workConnSenderFn(workConn)
|
||||
|
||||
wg.Wait()
|
||||
xl.Infof("sudp worker is closed")
|
||||
xl.Info("sudp worker is closed")
|
||||
}
|
||||
|
||||
func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) {
|
||||
@@ -235,7 +235,7 @@ func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) {
|
||||
if sv.cfg.Transport.UseEncryption {
|
||||
remote, err = libio.WithEncryption(remote, []byte(sv.cfg.SecretKey))
|
||||
if err != nil {
|
||||
xl.Errorf("create encryption stream error: %v", err)
|
||||
xl.Error("create encryption stream error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@@ -79,14 +79,14 @@ func (vm *Manager) keepVisitorsRunning() {
|
||||
for {
|
||||
select {
|
||||
case <-vm.stopCh:
|
||||
xl.Tracef("gracefully shutdown visitor manager")
|
||||
xl.Trace("gracefully shutdown visitor manager")
|
||||
return
|
||||
case <-ticker.C:
|
||||
vm.mu.Lock()
|
||||
for _, cfg := range vm.cfgs {
|
||||
name := cfg.GetBaseConfig().Name
|
||||
if _, exist := vm.visitors[name]; !exist {
|
||||
xl.Infof("try to start visitor [%s]", name)
|
||||
xl.Info("try to start visitor [%s]", name)
|
||||
_ = vm.startVisitor(cfg)
|
||||
}
|
||||
}
|
||||
@@ -115,10 +115,10 @@ func (vm *Manager) startVisitor(cfg v1.VisitorConfigurer) (err error) {
|
||||
visitor := NewVisitor(vm.ctx, cfg, vm.clientCfg, vm.helper)
|
||||
err = visitor.Run()
|
||||
if err != nil {
|
||||
xl.Warnf("start error: %v", err)
|
||||
xl.Warn("start error: %v", err)
|
||||
} else {
|
||||
vm.visitors[name] = visitor
|
||||
xl.Infof("start visitor success")
|
||||
xl.Info("start visitor success")
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func (vm *Manager) UpdateAll(cfgs []v1.VisitorConfigurer) {
|
||||
}
|
||||
}
|
||||
if len(delNames) > 0 {
|
||||
xl.Infof("visitor removed: %v", delNames)
|
||||
xl.Info("visitor removed: %v", delNames)
|
||||
}
|
||||
|
||||
addNames := make([]string, 0)
|
||||
@@ -169,7 +169,7 @@ func (vm *Manager) UpdateAll(cfgs []v1.VisitorConfigurer) {
|
||||
}
|
||||
}
|
||||
if len(addNames) > 0 {
|
||||
xl.Infof("visitor added: %v", addNames)
|
||||
xl.Info("visitor added: %v", addNames)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -93,7 +93,7 @@ func (sv *XTCPVisitor) worker() {
|
||||
for {
|
||||
conn, err := sv.l.Accept()
|
||||
if err != nil {
|
||||
xl.Warnf("xtcp local listener closed")
|
||||
xl.Warn("xtcp local listener closed")
|
||||
return
|
||||
}
|
||||
go sv.handleConn(conn)
|
||||
@@ -105,7 +105,7 @@ func (sv *XTCPVisitor) internalConnWorker() {
|
||||
for {
|
||||
conn, err := sv.internalLn.Accept()
|
||||
if err != nil {
|
||||
xl.Warnf("xtcp internal listener closed")
|
||||
xl.Warn("xtcp internal listener closed")
|
||||
return
|
||||
}
|
||||
go sv.handleConn(conn)
|
||||
@@ -140,14 +140,14 @@ func (sv *XTCPVisitor) keepTunnelOpenWorker() {
|
||||
case <-sv.ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
xl.Debugf("keepTunnelOpenWorker try to check tunnel...")
|
||||
xl.Debug("keepTunnelOpenWorker try to check tunnel...")
|
||||
conn, err := sv.getTunnelConn()
|
||||
if err != nil {
|
||||
xl.Warnf("keepTunnelOpenWorker get tunnel connection error: %v", err)
|
||||
xl.Warn("keepTunnelOpenWorker get tunnel connection error: %v", err)
|
||||
_ = sv.retryLimiter.Wait(sv.ctx)
|
||||
continue
|
||||
}
|
||||
xl.Debugf("keepTunnelOpenWorker check success")
|
||||
xl.Debug("keepTunnelOpenWorker check success")
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
||||
}
|
||||
}()
|
||||
|
||||
xl.Debugf("get a new xtcp user connection")
|
||||
xl.Debug("get a new xtcp user connection")
|
||||
|
||||
// Open a tunnel connection to the server. If there is already a successful hole-punching connection,
|
||||
// it will be reused. Otherwise, it will block and wait for a successful hole-punching connection until timeout.
|
||||
@@ -176,15 +176,15 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
||||
}
|
||||
tunnelConn, err := sv.openTunnel(ctx)
|
||||
if err != nil {
|
||||
xl.Errorf("open tunnel error: %v", err)
|
||||
xl.Error("open tunnel error: %v", err)
|
||||
// no fallback, just return
|
||||
if sv.cfg.FallbackTo == "" {
|
||||
return
|
||||
}
|
||||
|
||||
xl.Debugf("try to transfer connection to visitor: %s", sv.cfg.FallbackTo)
|
||||
xl.Debug("try to transfer connection to visitor: %s", sv.cfg.FallbackTo)
|
||||
if err := sv.helper.TransferConn(sv.cfg.FallbackTo, userConn); err != nil {
|
||||
xl.Errorf("transfer connection to visitor %s error: %v", sv.cfg.FallbackTo, err)
|
||||
xl.Error("transfer connection to visitor %s error: %v", sv.cfg.FallbackTo, err)
|
||||
return
|
||||
}
|
||||
isConnTrasfered = true
|
||||
@@ -195,7 +195,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
||||
if sv.cfg.Transport.UseEncryption {
|
||||
muxConnRWCloser, err = libio.WithEncryption(muxConnRWCloser, []byte(sv.cfg.SecretKey))
|
||||
if err != nil {
|
||||
xl.Errorf("create encryption stream error: %v", err)
|
||||
xl.Error("create encryption stream error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -206,9 +206,9 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
||||
}
|
||||
|
||||
_, _, errs := libio.Join(userConn, muxConnRWCloser)
|
||||
xl.Debugf("join connections closed")
|
||||
xl.Debug("join connections closed")
|
||||
if len(errs) > 0 {
|
||||
xl.Tracef("join connections errors: %v", errs)
|
||||
xl.Trace("join connections errors: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ func (sv *XTCPVisitor) openTunnel(ctx context.Context) (conn net.Conn, err error
|
||||
|
||||
if err != nil {
|
||||
if err != ErrNoTunnelSession {
|
||||
xl.Warnf("get tunnel connection error: %v", err)
|
||||
xl.Warn("get tunnel connection error: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -268,19 +268,19 @@ func (sv *XTCPVisitor) getTunnelConn() (net.Conn, error) {
|
||||
// 4. Create a tunnel session using an underlying UDP connection.
|
||||
func (sv *XTCPVisitor) makeNatHole() {
|
||||
xl := xlog.FromContextSafe(sv.ctx)
|
||||
xl.Tracef("makeNatHole start")
|
||||
xl.Trace("makeNatHole start")
|
||||
if err := nathole.PreCheck(sv.ctx, sv.helper.MsgTransporter(), sv.cfg.ServerName, 5*time.Second); err != nil {
|
||||
xl.Warnf("nathole precheck error: %v", err)
|
||||
xl.Warn("nathole precheck error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
xl.Tracef("nathole prepare start")
|
||||
xl.Trace("nathole prepare start")
|
||||
prepareResult, err := nathole.Prepare([]string{sv.clientCfg.NatHoleSTUNServer})
|
||||
if err != nil {
|
||||
xl.Warnf("nathole prepare error: %v", err)
|
||||
xl.Warn("nathole prepare error: %v", err)
|
||||
return
|
||||
}
|
||||
xl.Infof("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v",
|
||||
xl.Info("nathole prepare success, nat type: %s, behavior: %s, addresses: %v, assistedAddresses: %v",
|
||||
prepareResult.NatType, prepareResult.Behavior, prepareResult.Addrs, prepareResult.AssistedAddrs)
|
||||
|
||||
listenConn := prepareResult.ListenConn
|
||||
@@ -298,30 +298,30 @@ func (sv *XTCPVisitor) makeNatHole() {
|
||||
AssistedAddrs: prepareResult.AssistedAddrs,
|
||||
}
|
||||
|
||||
xl.Tracef("nathole exchange info start")
|
||||
xl.Trace("nathole exchange info start")
|
||||
natHoleRespMsg, err := nathole.ExchangeInfo(sv.ctx, sv.helper.MsgTransporter(), transactionID, natHoleVisitorMsg, 5*time.Second)
|
||||
if err != nil {
|
||||
listenConn.Close()
|
||||
xl.Warnf("nathole exchange info error: %v", err)
|
||||
xl.Warn("nathole exchange info error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
xl.Infof("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v",
|
||||
xl.Info("get natHoleRespMsg, sid [%s], protocol [%s], candidate address %v, assisted address %v, detectBehavior: %+v",
|
||||
natHoleRespMsg.Sid, natHoleRespMsg.Protocol, natHoleRespMsg.CandidateAddrs,
|
||||
natHoleRespMsg.AssistedAddrs, natHoleRespMsg.DetectBehavior)
|
||||
|
||||
newListenConn, raddr, err := nathole.MakeHole(sv.ctx, listenConn, natHoleRespMsg, []byte(sv.cfg.SecretKey))
|
||||
if err != nil {
|
||||
listenConn.Close()
|
||||
xl.Warnf("make hole error: %v", err)
|
||||
xl.Warn("make hole error: %v", err)
|
||||
return
|
||||
}
|
||||
listenConn = newListenConn
|
||||
xl.Infof("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr)
|
||||
xl.Info("establishing nat hole connection successful, sid [%s], remoteAddr [%s]", natHoleRespMsg.Sid, raddr)
|
||||
|
||||
if err := sv.session.Init(listenConn, raddr); err != nil {
|
||||
listenConn.Close()
|
||||
xl.Warnf("init tunnel session error: %v", err)
|
||||
xl.Warn("init tunnel session error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -17,10 +17,8 @@ package main
|
||||
import (
|
||||
_ "github.com/fatedier/frp/assets/frpc"
|
||||
"github.com/fatedier/frp/cmd/frpc/sub"
|
||||
"github.com/fatedier/frp/pkg/util/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
system.EnableCompatibilityMode()
|
||||
sub.Execute()
|
||||
}
|
||||
|
@@ -17,8 +17,8 @@ package sub
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/fatedier/frp/pkg/config"
|
||||
@@ -55,7 +55,7 @@ func init() {
|
||||
config.RegisterProxyFlags(cmd, c)
|
||||
|
||||
// add sub command for visitor
|
||||
if slices.Contains(visitorTypes, v1.VisitorType(typ)) {
|
||||
if lo.Contains(visitorTypes, v1.VisitorType(typ)) {
|
||||
vc := v1.NewVisitorConfigurerByType(v1.VisitorType(typ))
|
||||
if vc == nil {
|
||||
panic("visitor type: " + typ + " not support")
|
||||
|
@@ -46,7 +46,7 @@ func init() {
|
||||
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "./frpc.ini", "config file of frpc")
|
||||
rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory")
|
||||
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
|
||||
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors")
|
||||
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", false, "strict config parsing mode, unknown fields will cause an error")
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
@@ -136,11 +136,11 @@ func startService(
|
||||
visitorCfgs []v1.VisitorConfigurer,
|
||||
cfgFile string,
|
||||
) error {
|
||||
log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
|
||||
log.InitLog(cfg.Log.To, cfg.Log.Level, cfg.Log.MaxDays, cfg.Log.DisablePrintColor)
|
||||
|
||||
if cfgFile != "" {
|
||||
log.Infof("start frpc service for config file [%s]", cfgFile)
|
||||
defer log.Infof("frpc service for config file [%s] stopped", cfgFile)
|
||||
log.Info("start frpc service for config file [%s]", cfgFile)
|
||||
defer log.Info("frpc service for config file [%s] stopped", cfgFile)
|
||||
}
|
||||
svr, err := client.NewService(client.ServiceOptions{
|
||||
Common: cfg,
|
||||
|
@@ -15,12 +15,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/fatedier/golib/crypto"
|
||||
|
||||
_ "github.com/fatedier/frp/assets/frps"
|
||||
_ "github.com/fatedier/frp/pkg/metrics"
|
||||
"github.com/fatedier/frp/pkg/util/system"
|
||||
)
|
||||
|
||||
func main() {
|
||||
system.EnableCompatibilityMode()
|
||||
crypto.DefaultSalt = "frp"
|
||||
Execute()
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ var (
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file of frps")
|
||||
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frps")
|
||||
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause errors")
|
||||
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", false, "strict config parsing mode, unknown fields will cause error")
|
||||
|
||||
config.RegisterServerConfigFlags(rootCmd, &serverCfg)
|
||||
}
|
||||
@@ -99,19 +99,19 @@ func Execute() {
|
||||
}
|
||||
|
||||
func runServer(cfg *v1.ServerConfig) (err error) {
|
||||
log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
|
||||
log.InitLog(cfg.Log.To, cfg.Log.Level, cfg.Log.MaxDays, cfg.Log.DisablePrintColor)
|
||||
|
||||
if cfgFile != "" {
|
||||
log.Infof("frps uses config file: %s", cfgFile)
|
||||
log.Info("frps uses config file: %s", cfgFile)
|
||||
} else {
|
||||
log.Infof("frps uses command line arguments for config")
|
||||
log.Info("frps uses command line arguments for config")
|
||||
}
|
||||
|
||||
svr, err := server.NewService(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("frps started successfully")
|
||||
log.Info("frps started successfully")
|
||||
svr.Run(context.Background())
|
||||
return
|
||||
}
|
||||
|
@@ -164,16 +164,11 @@ healthCheck.type = "tcp"
|
||||
healthCheck.timeoutSeconds = 3
|
||||
# If continuous failed in 3 times, the proxy will be removed from frps
|
||||
healthCheck.maxFailed = 3
|
||||
# Every 10 seconds will do a health check
|
||||
# every 10 seconds will do a health check
|
||||
healthCheck.intervalSeconds = 10
|
||||
# Additional meta info for each proxy. It will be passed to the server-side plugin for use.
|
||||
# additional meta info for each proxy
|
||||
metadatas.var1 = "abc"
|
||||
metadatas.var2 = "123"
|
||||
# You can add some extra information to the proxy through annotations.
|
||||
# These annotations will be displayed on the frps dashboard.
|
||||
[proxies.annotations]
|
||||
key1 = "value1"
|
||||
"prefix/key2" = "value2"
|
||||
|
||||
[[proxies]]
|
||||
name = "ssh_random"
|
||||
@@ -216,10 +211,6 @@ healthCheck.path = "/status"
|
||||
healthCheck.intervalSeconds = 10
|
||||
healthCheck.maxFailed = 3
|
||||
healthCheck.timeoutSeconds = 3
|
||||
# set health check headers
|
||||
healthCheck.httpHeaders=[
|
||||
{ name = "x-from-where", value = "frp" }
|
||||
]
|
||||
|
||||
[[proxies]]
|
||||
name = "web02"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 56 KiB |
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.22 AS building
|
||||
FROM golang:1.21 AS building
|
||||
|
||||
COPY . /building
|
||||
WORKDIR /building
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.22 AS building
|
||||
FROM golang:1.21 AS building
|
||||
|
||||
COPY . /building
|
||||
WORKDIR /building
|
||||
|
89
go.mod
89
go.mod
@@ -1,81 +1,80 @@
|
||||
module github.com/fatedier/frp
|
||||
|
||||
go 1.22
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||
github.com/coreos/go-oidc/v3 v3.10.0
|
||||
github.com/fatedier/golib v0.5.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb
|
||||
github.com/fatedier/golib v0.1.1-0.20230725122706-dcbaee8eef40
|
||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/hashicorp/yamux v0.1.1
|
||||
github.com/onsi/ginkgo/v2 v2.17.1
|
||||
github.com/onsi/gomega v1.32.0
|
||||
github.com/pelletier/go-toml/v2 v2.2.0
|
||||
github.com/pion/stun/v2 v2.0.0
|
||||
github.com/onsi/ginkgo/v2 v2.11.0
|
||||
github.com/onsi/gomega v1.27.8
|
||||
github.com/pelletier/go-toml/v2 v2.1.0
|
||||
github.com/pion/stun v0.6.1
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/quic-go/quic-go v0.42.0
|
||||
github.com/rodaine/table v1.2.0
|
||||
github.com/samber/lo v1.39.0
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/quic-go/quic-go v0.37.7
|
||||
github.com/rodaine/table v1.1.0
|
||||
github.com/samber/lo v1.38.1
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tidwall/gjson v1.17.1
|
||||
github.com/xtaci/kcp-go/v5 v5.6.8
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/oauth2 v0.16.0
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/time v0.5.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/oauth2 v0.10.0
|
||||
golang.org/x/sync v0.3.0
|
||||
golang.org/x/time v0.3.0
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
k8s.io/apimachinery v0.28.8
|
||||
k8s.io/client-go v0.28.8
|
||||
k8s.io/apimachinery v0.27.4
|
||||
k8s.io/client-go v0.27.4
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/klauspost/reedsolomon v1.12.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
|
||||
github.com/klauspost/reedsolomon v1.9.15 // 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/logging v0.2.2 // indirect
|
||||
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||
github.com/pion/transport/v3 v3.0.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/templexxx/cpu v0.1.0 // indirect
|
||||
github.com/templexxx/xorsimd v0.4.2 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
golang.org/x/tools v0.9.3 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
213
go.sum
213
go.sum
@@ -1,6 +1,6 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/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/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
@@ -14,8 +14,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
|
||||
github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac=
|
||||
github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o=
|
||||
github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc=
|
||||
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -24,21 +24,29 @@ 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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatedier/golib v0.5.0 h1:hNcH7hgfIFqVWbP+YojCCAj4eO94pPf4dEF8lmq2jWs=
|
||||
github.com/fatedier/golib v0.5.0/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ=
|
||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
|
||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
||||
github.com/fatedier/golib v0.1.1-0.20230725122706-dcbaee8eef40 h1:BVdpWT6viE/mpuRa6txNyRNjtHa1Efrii9Du6/gHfJ0=
|
||||
github.com/fatedier/golib v0.1.1-0.20230725122706-dcbaee8eef40/go.mod h1:Lmi9U4VfvdRvonSMh1FgXVy1hCXycVyJk4E9ktokknE=
|
||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
|
||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
|
||||
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo=
|
||||
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
|
||||
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/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.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
@@ -46,81 +54,80 @@ 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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/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/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
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/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/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/reedsolomon v1.12.0 h1:I5FEp3xSwVCcEh3F5A7dofEfhXdF/bWhQWPH+XwBFno=
|
||||
github.com/klauspost/reedsolomon v1.12.0/go.mod h1:EPLZJeh4l27pUGC3aXOjheaoh1I9yut7xTURiW3LQ9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/reedsolomon v1.9.15 h1:g2erWKD2M6rgnPf89fCji6jNlhMKMdXcuNHMW1SYCIo=
|
||||
github.com/klauspost/reedsolomon v1.9.15/go.mod h1:eqPAcE7xar5CIzcdfwydOEdcmchAKAP/qs14y4GCBOk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
|
||||
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
||||
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
|
||||
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
|
||||
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||
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/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/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
|
||||
github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
|
||||
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
|
||||
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
|
||||
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rodaine/table v1.2.0 h1:38HEnwK4mKSHQJIkavVj+bst1TEY7j9zhLMWu4QJrMA=
|
||||
github.com/rodaine/table v1.2.0/go.mod h1:wejb/q/Yd4T/SVmBSRMr7GCq3KlcZp3gyNYdLSBhkaE=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.37.7 h1:AgKsQLZ1+YCwZd2GYhBUsJDYZwEkA5gENtAjb+MxONU=
|
||||
github.com/quic-go/quic-go v0.37.7/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU=
|
||||
github.com/rodaine/table v1.1.0 h1:/fUlCSdjamMY8VifdQRIu3VWZXYLY7QHFkVorS8NTr4=
|
||||
github.com/rodaine/table v1.1.0/go.mod h1:Qu3q5wi1jTQD6B6HsP6szie/S4w1QUQ8pq22pz9iL8g=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/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.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
@@ -128,126 +135,117 @@ 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.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.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.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.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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/templexxx/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40=
|
||||
github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI=
|
||||
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI=
|
||||
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
|
||||
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
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/xtaci/kcp-go/v5 v5.6.8 h1:jlI/0jAyjoOjT/SaGB58s4bQMJiNS41A2RKzR6TMWeI=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.8/go.mod h1:oE9j2NVqAkuKO5o8ByKGch3vgVX3BNf8zqP8JiGq0bM=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-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.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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-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-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-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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
|
||||
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
|
||||
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
|
||||
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
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-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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.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-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.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
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.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
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.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.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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/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.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -262,11 +260,10 @@ 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.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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
@@ -276,12 +273,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/apimachinery v0.28.8 h1:hi/nrxHwk4QLV+W/SHve1bypTE59HCDorLY1stBIxKQ=
|
||||
k8s.io/apimachinery v0.28.8/go.mod h1:cBnwIM3fXoRo28SqbV/Ihxf/iviw85KyXOrzxvZQ83U=
|
||||
k8s.io/client-go v0.28.8 h1:TE59Tjd87WKvS2FPBTfIKLFX0nQJ4SSHsnDo5IHjgOw=
|
||||
k8s.io/client-go v0.28.8/go.mod h1:uDVQ/rPzWpWIy40c6lZ4mUwaEvRWGnpoqSO4FM65P3o=
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
|
||||
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs=
|
||||
k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||
k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
|
||||
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
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/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
|
@@ -6,7 +6,7 @@ ROOT=$(unset CDPATH && cd "$(dirname "$SCRIPT")/.." && pwd)
|
||||
ginkgo_command=$(which ginkgo 2>/dev/null)
|
||||
if [ -z "$ginkgo_command" ]; then
|
||||
echo "ginkgo not found, try to install..."
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@v2.17.1
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@v2.11.0
|
||||
fi
|
||||
|
||||
debug=false
|
||||
|
82
package.sh
82
package.sh
@@ -1,6 +1,3 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# compile for version
|
||||
make
|
||||
if [ $? -ne 0 ]; then
|
||||
@@ -17,57 +14,50 @@ make -f ./Makefile.cross-compiles
|
||||
rm -rf ./release/packages
|
||||
mkdir -p ./release/packages
|
||||
|
||||
os_all='linux windows darwin freebsd android'
|
||||
os_all='linux windows darwin freebsd'
|
||||
arch_all='386 amd64 arm arm64 mips64 mips64le mips mipsle riscv64'
|
||||
extra_all='_ hf'
|
||||
|
||||
cd ./release
|
||||
|
||||
for os in $os_all; do
|
||||
for arch in $arch_all; do
|
||||
for extra in $extra_all; do
|
||||
suffix="${os}_${arch}"
|
||||
if [ "x${extra}" != x"_" ]; then
|
||||
suffix="${os}_${arch}_${extra}"
|
||||
frp_dir_name="frp_${frp_version}_${os}_${arch}"
|
||||
frp_path="./packages/frp_${frp_version}_${os}_${arch}"
|
||||
|
||||
if [ "x${os}" = x"windows" ]; then
|
||||
if [ ! -f "./frpc_${os}_${arch}.exe" ]; then
|
||||
continue
|
||||
fi
|
||||
frp_dir_name="frp_${frp_version}_${suffix}"
|
||||
frp_path="./packages/frp_${frp_version}_${suffix}"
|
||||
if [ ! -f "./frps_${os}_${arch}.exe" ]; then
|
||||
continue
|
||||
fi
|
||||
mkdir ${frp_path}
|
||||
mv ./frpc_${os}_${arch}.exe ${frp_path}/frpc.exe
|
||||
mv ./frps_${os}_${arch}.exe ${frp_path}/frps.exe
|
||||
else
|
||||
if [ ! -f "./frpc_${os}_${arch}" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ ! -f "./frps_${os}_${arch}" ]; then
|
||||
continue
|
||||
fi
|
||||
mkdir ${frp_path}
|
||||
mv ./frpc_${os}_${arch} ${frp_path}/frpc
|
||||
mv ./frps_${os}_${arch} ${frp_path}/frps
|
||||
fi
|
||||
cp ../LICENSE ${frp_path}
|
||||
cp -f ../conf/frpc.toml ${frp_path}
|
||||
cp -f ../conf/frps.toml ${frp_path}
|
||||
|
||||
if [ "x${os}" = x"windows" ]; then
|
||||
if [ ! -f "./frpc_${os}_${arch}.exe" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ ! -f "./frps_${os}_${arch}.exe" ]; then
|
||||
continue
|
||||
fi
|
||||
mkdir ${frp_path}
|
||||
mv ./frpc_${os}_${arch}.exe ${frp_path}/frpc.exe
|
||||
mv ./frps_${os}_${arch}.exe ${frp_path}/frps.exe
|
||||
else
|
||||
if [ ! -f "./frpc_${suffix}" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ ! -f "./frps_${suffix}" ]; then
|
||||
continue
|
||||
fi
|
||||
mkdir ${frp_path}
|
||||
mv ./frpc_${suffix} ${frp_path}/frpc
|
||||
mv ./frps_${suffix} ${frp_path}/frps
|
||||
fi
|
||||
cp ../LICENSE ${frp_path}
|
||||
cp -f ../conf/frpc.toml ${frp_path}
|
||||
cp -f ../conf/frps.toml ${frp_path}
|
||||
|
||||
# packages
|
||||
cd ./packages
|
||||
if [ "x${os}" = x"windows" ]; then
|
||||
zip -rq ${frp_dir_name}.zip ${frp_dir_name}
|
||||
else
|
||||
tar -zcf ${frp_dir_name}.tar.gz ${frp_dir_name}
|
||||
fi
|
||||
cd ..
|
||||
rm -rf ${frp_path}
|
||||
done
|
||||
# packages
|
||||
cd ./packages
|
||||
if [ "x${os}" = x"windows" ]; then
|
||||
zip -rq ${frp_dir_name}.zip ${frp_dir_name}
|
||||
else
|
||||
tar -zcf ${frp_dir_name}.tar.gz ${frp_dir_name}
|
||||
fi
|
||||
cd ..
|
||||
rm -rf ${frp_path}
|
||||
done
|
||||
done
|
||||
|
||||
|
@@ -17,9 +17,9 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/oauth2/clientcredentials"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
@@ -70,7 +70,7 @@ func (auth *OidcAuthProvider) SetLogin(loginMsg *msg.Login) (err error) {
|
||||
}
|
||||
|
||||
func (auth *OidcAuthProvider) SetPing(pingMsg *msg.Ping) (err error) {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func (auth *OidcAuthProvider) SetPing(pingMsg *msg.Ping) (err error) {
|
||||
}
|
||||
|
||||
func (auth *OidcAuthProvider) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ func (auth *OidcAuthConsumer) verifyPostLoginToken(privilegeKey string) (err err
|
||||
}
|
||||
|
||||
func (auth *OidcAuthConsumer) VerifyPing(pingMsg *msg.Ping) (err error) {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (auth *OidcAuthConsumer) VerifyPing(pingMsg *msg.Ping) (err error) {
|
||||
}
|
||||
|
||||
func (auth *OidcAuthConsumer) VerifyNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -16,9 +16,10 @@ package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
@@ -42,7 +43,7 @@ func (auth *TokenAuthSetterVerifier) SetLogin(loginMsg *msg.Login) error {
|
||||
}
|
||||
|
||||
func (auth *TokenAuthSetterVerifier) SetPing(pingMsg *msg.Ping) error {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ func (auth *TokenAuthSetterVerifier) SetPing(pingMsg *msg.Ping) error {
|
||||
}
|
||||
|
||||
func (auth *TokenAuthSetterVerifier) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) error {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ func (auth *TokenAuthSetterVerifier) VerifyLogin(m *msg.Login) error {
|
||||
}
|
||||
|
||||
func (auth *TokenAuthSetterVerifier) VerifyPing(m *msg.Ping) error {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ func (auth *TokenAuthSetterVerifier) VerifyPing(m *msg.Ping) error {
|
||||
}
|
||||
|
||||
func (auth *TokenAuthSetterVerifier) VerifyNewWorkConn(m *msg.NewWorkConn) error {
|
||||
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
if !lo.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -18,9 +18,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
legacyauth "github.com/fatedier/frp/pkg/auth/legacy"
|
||||
@@ -399,7 +399,7 @@ func (cfg *ClientCommonConf) Validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
if !slices.Contains([]string{"tcp", "kcp", "quic", "websocket", "wss"}, cfg.Protocol) {
|
||||
if !lo.Contains([]string{"tcp", "kcp", "quic", "websocket", "wss"}, cfg.Protocol) {
|
||||
return fmt.Errorf("invalid protocol")
|
||||
}
|
||||
|
||||
|
@@ -175,9 +175,6 @@ func transformHeadersFromPluginParams(params map[string]string) v1.HeaderOperati
|
||||
continue
|
||||
}
|
||||
if k = strings.TrimPrefix(k, "plugin_header_"); k != "" {
|
||||
if out.Set == nil {
|
||||
out.Set = make(map[string]string)
|
||||
}
|
||||
out.Set[k] = v
|
||||
}
|
||||
}
|
||||
|
@@ -80,10 +80,7 @@ func DetectLegacyINIFormatFromFile(path string) bool {
|
||||
}
|
||||
|
||||
func RenderWithTemplate(in []byte, values *Values) ([]byte, error) {
|
||||
tmpl, err := template.New("frp").Funcs(template.FuncMap{
|
||||
"parseNumberRange": parseNumberRange,
|
||||
"parseNumberRangePair": parseNumberRangePair,
|
||||
}).Parse(string(in))
|
||||
tmpl, err := template.New("frp").Parse(string(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -1,52 +0,0 @@
|
||||
// Copyright 2024 The frp Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
)
|
||||
|
||||
type NumberPair struct {
|
||||
First int64
|
||||
Second int64
|
||||
}
|
||||
|
||||
func parseNumberRangePair(firstRangeStr, secondRangeStr string) ([]NumberPair, error) {
|
||||
firstRangeNumbers, err := util.ParseRangeNumbers(firstRangeStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secondRangeNumbers, err := util.ParseRangeNumbers(secondRangeStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(firstRangeNumbers) != len(secondRangeNumbers) {
|
||||
return nil, fmt.Errorf("first and second range numbers are not in pairs")
|
||||
}
|
||||
pairs := make([]NumberPair, 0, len(firstRangeNumbers))
|
||||
for i := 0; i < len(firstRangeNumbers); i++ {
|
||||
pairs = append(pairs, NumberPair{
|
||||
First: firstRangeNumbers[i],
|
||||
Second: secondRangeNumbers[i],
|
||||
})
|
||||
}
|
||||
return pairs, nil
|
||||
}
|
||||
|
||||
func parseNumberRange(firstRangeStr string) ([]int64, error) {
|
||||
return util.ParseRangeNumbers(firstRangeStr)
|
||||
}
|
@@ -45,6 +45,15 @@ func NewBandwidthQuantity(s string) (BandwidthQuantity, error) {
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func MustBandwidthQuantity(s string) BandwidthQuantity {
|
||||
q := BandwidthQuantity{}
|
||||
err := q.UnmarshalString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *BandwidthQuantity) Equal(u *BandwidthQuantity) bool {
|
||||
if q == nil && u == nil {
|
||||
return true
|
||||
|
@@ -136,14 +136,8 @@ func (c *ClientTransportConfig) Complete() {
|
||||
c.PoolCount = util.EmptyOr(c.PoolCount, 1)
|
||||
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))
|
||||
c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60)
|
||||
if lo.FromPtr(c.TCPMux) {
|
||||
// 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.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, 30)
|
||||
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90)
|
||||
c.QUIC.Complete()
|
||||
c.TLS.Complete()
|
||||
}
|
||||
|
@@ -129,8 +129,3 @@ type HTTPPluginOptions struct {
|
||||
type HeaderOperations struct {
|
||||
Set map[string]string `json:"set,omitempty"`
|
||||
}
|
||||
|
||||
type HTTPHeader struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
|
||||
if err := decoder.Decode(options); err != nil {
|
||||
return fmt.Errorf("unmarshal ClientPluginOptions error: %v", err)
|
||||
return err
|
||||
}
|
||||
c.ClientPluginOptions = options
|
||||
return nil
|
||||
|
@@ -97,9 +97,6 @@ type HealthCheckConfig struct {
|
||||
// Path specifies the path to send health checks to if the
|
||||
// health check type is "http".
|
||||
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 {
|
||||
@@ -108,10 +105,9 @@ type DomainConfig struct {
|
||||
}
|
||||
|
||||
type ProxyBaseConfig struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
Transport ProxyTransport `json:"transport,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Transport ProxyTransport `json:"transport,omitempty"`
|
||||
// metadata info for each proxy
|
||||
Metadatas map[string]string `json:"metadatas,omitempty"`
|
||||
LoadBalancer LoadBalancerConfig `json:"loadBalancer,omitempty"`
|
||||
@@ -142,7 +138,6 @@ func (c *ProxyBaseConfig) MarshalToMsg(m *msg.NewProxy) {
|
||||
m.Group = c.LoadBalancer.Group
|
||||
m.GroupKey = c.LoadBalancer.GroupKey
|
||||
m.Metas = c.Metadatas
|
||||
m.Annotations = c.Annotations
|
||||
}
|
||||
|
||||
func (c *ProxyBaseConfig) UnmarshalFromMsg(m *msg.NewProxy) {
|
||||
@@ -159,7 +154,6 @@ func (c *ProxyBaseConfig) UnmarshalFromMsg(m *msg.NewProxy) {
|
||||
c.LoadBalancer.Group = m.Group
|
||||
c.LoadBalancer.GroupKey = m.GroupKey
|
||||
c.Metadatas = m.Metas
|
||||
c.Annotations = m.Annotations
|
||||
}
|
||||
|
||||
type TypedProxyConfig struct {
|
||||
@@ -189,7 +183,7 @@ func (c *TypedProxyConfig) UnmarshalJSON(b []byte) error {
|
||||
decoder.DisallowUnknownFields()
|
||||
}
|
||||
if err := decoder.Decode(configurer); err != nil {
|
||||
return fmt.Errorf("unmarshal ProxyConfig error: %v", err)
|
||||
return err
|
||||
}
|
||||
c.ProxyConfigurer = configurer
|
||||
return nil
|
||||
|
@@ -179,12 +179,7 @@ func (c *ServerTransportConfig) Complete() {
|
||||
c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60)
|
||||
c.TCPKeepAlive = util.EmptyOr(c.TCPKeepAlive, 7200)
|
||||
c.MaxPoolCount = util.EmptyOr(c.MaxPoolCount, 5)
|
||||
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.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90)
|
||||
c.QUIC.Complete()
|
||||
if c.TLS.TrustedCaFile != "" {
|
||||
c.TLS.Force = true
|
||||
|
@@ -18,7 +18,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
@@ -30,7 +29,7 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
|
||||
warnings Warning
|
||||
errs error
|
||||
)
|
||||
if !slices.Contains(SupportedAuthMethods, c.Auth.Method) {
|
||||
if !lo.Contains(SupportedAuthMethods, c.Auth.Method) {
|
||||
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
|
||||
}
|
||||
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
|
||||
@@ -64,7 +63,7 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig) (Warning, error) {
|
||||
warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.Transport.TLS.TrustedCaFile))
|
||||
}
|
||||
|
||||
if !slices.Contains(SupportedTransportProtocols, c.Transport.Protocol) {
|
||||
if !lo.Contains(SupportedTransportProtocols, c.Transport.Protocol) {
|
||||
errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols))
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,8 @@ package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
)
|
||||
@@ -43,7 +44,7 @@ func ValidatePort(port int, fieldPath string) error {
|
||||
}
|
||||
|
||||
func validateLogConfig(c *v1.LogConfig) error {
|
||||
if !slices.Contains(SupportedLogLevels, c.Level) {
|
||||
if !lo.Contains(SupportedLogLevels, c.Level) {
|
||||
return fmt.Errorf("invalid log level, optional values are %v", SupportedLogLevels)
|
||||
}
|
||||
return nil
|
||||
|
@@ -17,10 +17,9 @@ package validation
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"github.com/samber/lo"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
)
|
||||
@@ -30,13 +29,11 @@ func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
|
||||
return errors.New("name should not be empty")
|
||||
}
|
||||
|
||||
if err := ValidateAnnotations(c.Annotations); err != nil {
|
||||
return err
|
||||
}
|
||||
if !slices.Contains([]string{"", "v1", "v2"}, c.Transport.ProxyProtocolVersion) {
|
||||
if !lo.Contains([]string{"", "v1", "v2"}, c.Transport.ProxyProtocolVersion) {
|
||||
return fmt.Errorf("not support proxy protocol version: %s", c.Transport.ProxyProtocolVersion)
|
||||
}
|
||||
if !slices.Contains([]string{"client", "server"}, c.Transport.BandwidthLimitMode) {
|
||||
|
||||
if !lo.Contains([]string{"client", "server"}, c.Transport.BandwidthLimitMode) {
|
||||
return fmt.Errorf("bandwidth limit mode should be client or server")
|
||||
}
|
||||
|
||||
@@ -46,7 +43,7 @@ func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
|
||||
}
|
||||
}
|
||||
|
||||
if !slices.Contains([]string{"", "tcp", "http"}, c.HealthCheck.Type) {
|
||||
if !lo.Contains([]string{"", "tcp", "http"}, c.HealthCheck.Type) {
|
||||
return fmt.Errorf("not support health check type: %s", c.HealthCheck.Type)
|
||||
}
|
||||
if c.HealthCheck.Type != "" {
|
||||
@@ -64,10 +61,7 @@ func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateProxyBaseConfigForServer(c *v1.ProxyBaseConfig) error {
|
||||
if err := ValidateAnnotations(c.Annotations); err != nil {
|
||||
return err
|
||||
}
|
||||
func validateProxyBaseConfigForServer(c *v1.ProxyBaseConfig, s *v1.ServerConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -139,7 +133,7 @@ func validateTCPMuxProxyConfigForClient(c *v1.TCPMuxProxyConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !slices.Contains([]string{string(v1.TCPMultiplexerHTTPConnect)}, c.Multiplexer) {
|
||||
if !lo.Contains([]string{string(v1.TCPMultiplexerHTTPConnect)}, c.Multiplexer) {
|
||||
return fmt.Errorf("not support multiplexer: %s", c.Multiplexer)
|
||||
}
|
||||
return nil
|
||||
@@ -167,7 +161,7 @@ func validateSUDPProxyConfigForClient(c *v1.SUDPProxyConfig) error {
|
||||
|
||||
func ValidateProxyConfigurerForServer(c v1.ProxyConfigurer, s *v1.ServerConfig) error {
|
||||
base := c.GetBaseConfig()
|
||||
if err := validateProxyBaseConfigForServer(base); err != nil {
|
||||
if err := validateProxyBaseConfigForServer(base, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -237,34 +231,3 @@ func validateXTCPProxyConfigForServer(c *v1.XTCPProxyConfig, s *v1.ServerConfig)
|
||||
func validateSUDPProxyConfigForServer(c *v1.SUDPProxyConfig, s *v1.ServerConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateAnnotations validates that a set of annotations are correctly defined.
|
||||
func ValidateAnnotations(annotations map[string]string) error {
|
||||
if len(annotations) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errs error
|
||||
for k := range annotations {
|
||||
for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
|
||||
errs = AppendError(errs, fmt.Errorf("annotation key %s is invalid: %s", k, msg))
|
||||
}
|
||||
}
|
||||
if err := ValidateAnnotationsSize(annotations); err != nil {
|
||||
errs = AppendError(errs, err)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
|
||||
|
||||
func ValidateAnnotationsSize(annotations map[string]string) error {
|
||||
var totalSize int64
|
||||
for k, v := range annotations {
|
||||
totalSize += (int64)(len(k)) + (int64)(len(v))
|
||||
}
|
||||
if totalSize > (int64)(TotalAnnotationSizeLimitB) {
|
||||
return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
@@ -28,7 +27,7 @@ func ValidateServerConfig(c *v1.ServerConfig) (Warning, error) {
|
||||
warnings Warning
|
||||
errs error
|
||||
)
|
||||
if !slices.Contains(SupportedAuthMethods, c.Auth.Method) {
|
||||
if !lo.Contains(SupportedAuthMethods, c.Auth.Method) {
|
||||
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
|
||||
}
|
||||
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
|
||||
|
@@ -17,7 +17,8 @@ package validation
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
)
|
||||
@@ -55,7 +56,7 @@ func validateVisitorBaseConfig(c *v1.VisitorBaseConfig) error {
|
||||
}
|
||||
|
||||
func validateXTCPVisitorConfig(c *v1.XTCPVisitorConfig) error {
|
||||
if !slices.Contains([]string{"kcp", "quic"}, c.Protocol) {
|
||||
if !lo.Contains([]string{"kcp", "quic"}, c.Protocol) {
|
||||
return fmt.Errorf("protocol should be kcp or quic")
|
||||
}
|
||||
return nil
|
||||
|
@@ -114,7 +114,7 @@ func (c *TypedVisitorConfig) UnmarshalJSON(b []byte) error {
|
||||
decoder.DisallowUnknownFields()
|
||||
}
|
||||
if err := decoder.Decode(configurer); err != nil {
|
||||
return fmt.Errorf("unmarshal VisitorConfig error: %v", err)
|
||||
return err
|
||||
}
|
||||
c.VisitorConfigurer = configurer
|
||||
return nil
|
||||
|
@@ -62,7 +62,7 @@ func (m *serverMetrics) run() {
|
||||
time.Sleep(12 * time.Hour)
|
||||
start := time.Now()
|
||||
count, total := m.clearUselessInfo(time.Duration(7*24) * time.Hour)
|
||||
log.Debugf("clear useless proxy statistics data count %d/%d, cost %v", count, total, time.Since(start))
|
||||
log.Debug("clear useless proxy statistics data count %d/%d, cost %v", count, total, time.Since(start))
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (m *serverMetrics) clearUselessInfo(continuousOfflineDuration time.Duration
|
||||
time.Since(data.LastCloseTime) > continuousOfflineDuration {
|
||||
delete(m.info.ProxyStatistics, name)
|
||||
count++
|
||||
log.Tracef("clear proxy [%s]'s statistics data, lastCloseTime: [%s]", name, data.LastCloseTime.String())
|
||||
log.Trace("clear proxy [%s]'s statistics data, lastCloseTime: [%s]", name, data.LastCloseTime.String())
|
||||
}
|
||||
}
|
||||
return count, total
|
||||
|
@@ -42,3 +42,7 @@ func ReadMsgInto(c io.Reader, msg Message) (err error) {
|
||||
func WriteMsg(c io.Writer, msg interface{}) (err error) {
|
||||
return msgCtl.WriteMsg(c, msg)
|
||||
}
|
||||
|
||||
func Pack(msg interface{}) (data []byte, err error) {
|
||||
return msgCtl.Pack(msg)
|
||||
}
|
||||
|
@@ -108,7 +108,6 @@ type NewProxy struct {
|
||||
Group string `json:"group,omitempty"`
|
||||
GroupKey string `json:"group_key,omitempty"`
|
||||
Metas map[string]string `json:"metas,omitempty"`
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
||||
// tcp and udp only
|
||||
RemotePort int `json:"remote_port,omitempty"`
|
||||
|
@@ -15,8 +15,6 @@
|
||||
package nathole
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -226,7 +224,7 @@ func (mhr *MakeHoleRecords) ReportSuccess(mode int, index int) {
|
||||
}
|
||||
|
||||
score.Score += 2
|
||||
score.Score = min(score.Score, 10)
|
||||
score.Score = lo.Min([]int{score.Score, 10})
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -235,12 +233,12 @@ func (mhr *MakeHoleRecords) Recommand() (mode, index int) {
|
||||
mhr.mu.Lock()
|
||||
defer mhr.mu.Unlock()
|
||||
|
||||
if len(mhr.scores) == 0 {
|
||||
maxScore := lo.MaxBy(mhr.scores, func(item, max *BehaviorScore) bool {
|
||||
return item.Score > max.Score
|
||||
})
|
||||
if maxScore == nil {
|
||||
return 0, 0
|
||||
}
|
||||
maxScore := slices.MaxFunc(mhr.scores, func(a, b *BehaviorScore) int {
|
||||
return cmp.Compare(a.Score, b.Score)
|
||||
})
|
||||
maxScore.Score--
|
||||
mhr.LastUpdateTime = time.Now()
|
||||
return maxScore.Mode, maxScore.Index
|
||||
|
@@ -17,8 +17,9 @@ package nathole
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -58,7 +59,7 @@ func ClassifyNATFeature(addresses []string, localIPs []string) (*NatFeature, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if slices.Contains(localIPs, ip) {
|
||||
if lo.Contains(localIPs, ip) {
|
||||
natFeature.PublicNetwork = true
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,6 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -73,7 +72,7 @@ type Session struct {
|
||||
|
||||
func (s *Session) genAnalysisKey() {
|
||||
hash := md5.New()
|
||||
vIPs := slices.Compact(parseIPs(s.visitorMsg.MappedAddrs))
|
||||
vIPs := lo.Uniq(parseIPs(s.visitorMsg.MappedAddrs))
|
||||
if len(vIPs) > 0 {
|
||||
hash.Write([]byte(vIPs[0]))
|
||||
}
|
||||
@@ -81,7 +80,7 @@ func (s *Session) genAnalysisKey() {
|
||||
hash.Write([]byte(s.vNatFeature.Behavior))
|
||||
hash.Write([]byte(strconv.FormatBool(s.vNatFeature.RegularPortsChange)))
|
||||
|
||||
cIPs := slices.Compact(parseIPs(s.clientMsg.MappedAddrs))
|
||||
cIPs := lo.Uniq(parseIPs(s.clientMsg.MappedAddrs))
|
||||
if len(cIPs) > 0 {
|
||||
hash.Write([]byte(cIPs[0]))
|
||||
}
|
||||
@@ -115,7 +114,7 @@ func (c *Controller) CleanWorker(ctx context.Context) {
|
||||
case <-ticker.C:
|
||||
start := time.Now()
|
||||
count, total := c.analyzer.Clean()
|
||||
log.Tracef("clean %d/%d nathole analysis data, cost %v", count, total, time.Since(start))
|
||||
log.Trace("clean %d/%d nathole analysis data, cost %v", count, total, time.Since(start))
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
@@ -157,7 +156,7 @@ func (c *Controller) HandleVisitor(m *msg.NatHoleVisitor, transporter transport.
|
||||
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, fmt.Sprintf("xtcp server for [%s] doesn't exist", m.ProxyName)))
|
||||
return
|
||||
}
|
||||
if !slices.Contains(cfg.allowUsers, visitorUser) && !slices.Contains(cfg.allowUsers, "*") {
|
||||
if !lo.Contains(cfg.allowUsers, visitorUser) && !lo.Contains(cfg.allowUsers, "*") {
|
||||
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, fmt.Sprintf("xtcp visitor user [%s] not allowed for [%s]", visitorUser, m.ProxyName)))
|
||||
return
|
||||
}
|
||||
@@ -191,11 +190,11 @@ func (c *Controller) HandleVisitor(m *msg.NatHoleVisitor, transporter transport.
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
log.Warnf("handle visitorMsg error: %v", err)
|
||||
log.Warn("handle visitorMsg error: %v", err)
|
||||
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, err.Error()))
|
||||
return
|
||||
}
|
||||
log.Tracef("handle visitor message, sid [%s], server name: %s", sid, m.ProxyName)
|
||||
log.Trace("handle visitor message, sid [%s], server name: %s", sid, m.ProxyName)
|
||||
|
||||
defer func() {
|
||||
c.mu.Lock()
|
||||
@@ -213,14 +212,14 @@ func (c *Controller) HandleVisitor(m *msg.NatHoleVisitor, transporter transport.
|
||||
select {
|
||||
case <-session.notifyCh:
|
||||
case <-time.After(time.Duration(NatHoleTimeout) * time.Second):
|
||||
log.Debugf("wait for NatHoleClient message timeout, sid [%s]", sid)
|
||||
log.Debug("wait for NatHoleClient message timeout, sid [%s]", sid)
|
||||
return
|
||||
}
|
||||
|
||||
// Make hole-punching decisions based on the NAT information of the client and visitor.
|
||||
vResp, cResp, err := c.analysis(session)
|
||||
if err != nil {
|
||||
log.Debugf("sid [%s] analysis error: %v", err)
|
||||
log.Debug("sid [%s] analysis error: %v", err)
|
||||
vResp = c.GenNatHoleResponse(session.visitorMsg.TransactionID, nil, err.Error())
|
||||
cResp = c.GenNatHoleResponse(session.clientMsg.TransactionID, nil, err.Error())
|
||||
}
|
||||
@@ -257,7 +256,7 @@ func (c *Controller) HandleClient(m *msg.NatHoleClient, transporter transport.Me
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Tracef("handle client message, sid [%s], server name: %s", session.sid, m.ProxyName)
|
||||
log.Trace("handle client message, sid [%s], server name: %s", session.sid, m.ProxyName)
|
||||
session.clientMsg = m
|
||||
session.clientTransporter = transporter
|
||||
select {
|
||||
@@ -271,13 +270,13 @@ func (c *Controller) HandleReport(m *msg.NatHoleReport) {
|
||||
session, ok := c.sessions[m.Sid]
|
||||
c.mu.RUnlock()
|
||||
if !ok {
|
||||
log.Tracef("sid [%s] report make hole success: %v, but session not found", m.Sid, m.Success)
|
||||
log.Trace("sid [%s] report make hole success: %v, but session not found", m.Sid, m.Success)
|
||||
return
|
||||
}
|
||||
if m.Success {
|
||||
c.analyzer.ReportSuccess(session.analysisKey, session.recommandMode, session.recommandIndex)
|
||||
}
|
||||
log.Infof("sid [%s] report make hole success: %v, mode %v, index %v",
|
||||
log.Info("sid [%s] report make hole success: %v, mode %v, index %v",
|
||||
m.Sid, m.Success, session.recommandMode, session.recommandIndex)
|
||||
}
|
||||
|
||||
@@ -318,7 +317,7 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
|
||||
session.cBehavior = cBehavior
|
||||
session.vBehavior = vBehavior
|
||||
|
||||
timeoutMs := max(cBehavior.SendDelayMs, vBehavior.SendDelayMs) + 5000
|
||||
timeoutMs := lo.Max([]int{cBehavior.SendDelayMs, vBehavior.SendDelayMs}) + 5000
|
||||
if cBehavior.ListenRandomPorts > 0 || vBehavior.ListenRandomPorts > 0 {
|
||||
timeoutMs += 30000
|
||||
}
|
||||
@@ -328,8 +327,8 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
|
||||
TransactionID: vm.TransactionID,
|
||||
Sid: session.sid,
|
||||
Protocol: protocol,
|
||||
CandidateAddrs: slices.Compact(cm.MappedAddrs),
|
||||
AssistedAddrs: slices.Compact(cm.AssistedAddrs),
|
||||
CandidateAddrs: lo.Uniq(cm.MappedAddrs),
|
||||
AssistedAddrs: lo.Uniq(cm.AssistedAddrs),
|
||||
DetectBehavior: msg.NatHoleDetectBehavior{
|
||||
Mode: mode,
|
||||
Role: vBehavior.Role,
|
||||
@@ -345,8 +344,8 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
|
||||
TransactionID: cm.TransactionID,
|
||||
Sid: session.sid,
|
||||
Protocol: protocol,
|
||||
CandidateAddrs: slices.Compact(vm.MappedAddrs),
|
||||
AssistedAddrs: slices.Compact(vm.AssistedAddrs),
|
||||
CandidateAddrs: lo.Uniq(vm.MappedAddrs),
|
||||
AssistedAddrs: lo.Uniq(vm.AssistedAddrs),
|
||||
DetectBehavior: msg.NatHoleDetectBehavior{
|
||||
Mode: mode,
|
||||
Role: cBehavior.Role,
|
||||
@@ -359,10 +358,10 @@ func (c *Controller) analysis(session *Session) (*msg.NatHoleResp, *msg.NatHoleR
|
||||
},
|
||||
}
|
||||
|
||||
log.Debugf("sid [%s] visitor nat: %+v, candidateAddrs: %v; client nat: %+v, candidateAddrs: %v, protocol: %s",
|
||||
log.Debug("sid [%s] visitor nat: %+v, candidateAddrs: %v; client nat: %+v, candidateAddrs: %v, protocol: %s",
|
||||
session.sid, *vNatFeature, vm.MappedAddrs, *cNatFeature, cm.MappedAddrs, protocol)
|
||||
log.Debugf("sid [%s] visitor detect behavior: %+v", session.sid, vResp.DetectBehavior)
|
||||
log.Debugf("sid [%s] client detect behavior: %+v", session.sid, cResp.DetectBehavior)
|
||||
log.Debug("sid [%s] visitor detect behavior: %+v", session.sid, vResp.DetectBehavior)
|
||||
log.Debug("sid [%s] client detect behavior: %+v", session.sid, cResp.DetectBehavior)
|
||||
return vResp, cResp, nil
|
||||
}
|
||||
|
||||
@@ -385,8 +384,8 @@ func getRangePorts(addrs []string, difference, maxNumber int) []msg.PortsRange {
|
||||
return nil
|
||||
}
|
||||
ports = append(ports, msg.PortsRange{
|
||||
From: max(port-difference-5, port-maxNumber, 1),
|
||||
To: min(port+difference+5, port+maxNumber, 65535),
|
||||
From: lo.Max([]int{port - difference - 5, port - maxNumber, 1}),
|
||||
To: lo.Min([]int{port + difference + 5, port + maxNumber, 65535}),
|
||||
})
|
||||
return ports
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pion/stun/v2"
|
||||
"github.com/pion/stun"
|
||||
)
|
||||
|
||||
var responseTimeout = 3 * time.Second
|
||||
|
@@ -17,14 +17,14 @@ package nathole
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"math/rand"
|
||||
"net"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatedier/golib/pool"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/net/ipv4"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
@@ -204,7 +204,7 @@ func MakeHole(ctx context.Context, listenConn *net.UDPConn, m *msg.NatHoleResp,
|
||||
for i := 0; i < m.DetectBehavior.ListenRandomPorts; i++ {
|
||||
tmpConn, err := net.ListenUDP("udp4", nil)
|
||||
if err != nil {
|
||||
xl.Warnf("listen random udp addr error: %v", err)
|
||||
xl.Warn("listen random udp addr error: %v", err)
|
||||
continue
|
||||
}
|
||||
listenConns = append(listenConns, tmpConn)
|
||||
@@ -212,11 +212,11 @@ func MakeHole(ctx context.Context, listenConn *net.UDPConn, m *msg.NatHoleResp,
|
||||
}
|
||||
}
|
||||
|
||||
detectAddrs = slices.Compact(detectAddrs)
|
||||
detectAddrs = lo.Uniq(detectAddrs)
|
||||
for _, detectAddr := range detectAddrs {
|
||||
for _, conn := range listenConns {
|
||||
if err := sendSidMessage(ctx, conn, m.Sid, transactionID, detectAddr, key, m.DetectBehavior.TTL); err != nil {
|
||||
xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
|
||||
xl.Trace("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,16 +289,16 @@ func waitDetectMessage(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
xl.Debugf("get udp message local %s, from %s", conn.LocalAddr(), raddr)
|
||||
xl.Debug("get udp message local %s, from %s", conn.LocalAddr(), raddr)
|
||||
var m msg.NatHoleSid
|
||||
if err := DecodeMessageInto(buf[:n], key, &m); err != nil {
|
||||
xl.Warnf("decode sid message error: %v", err)
|
||||
xl.Warn("decode sid message error: %v", err)
|
||||
continue
|
||||
}
|
||||
pool.PutBuf(buf)
|
||||
|
||||
if m.Sid != sid {
|
||||
xl.Warnf("get sid message with wrong sid: %s, expect: %s", m.Sid, sid)
|
||||
xl.Warn("get sid message with wrong sid: %s, expect: %s", m.Sid, sid)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ func waitDetectMessage(
|
||||
m.Response = true
|
||||
buf2, err := EncodeMessage(&m, key)
|
||||
if err != nil {
|
||||
xl.Warnf("encode sid message error: %v", err)
|
||||
xl.Warn("encode sid message error: %v", err)
|
||||
continue
|
||||
}
|
||||
_, _ = conn.WriteToUDP(buf2, raddr)
|
||||
@@ -329,7 +329,7 @@ func sendSidMessage(
|
||||
if ttl > 0 {
|
||||
ttlStr = fmt.Sprintf(" with ttl %d", ttl)
|
||||
}
|
||||
xl.Tracef("send sid message from %s to %s%s", conn.LocalAddr(), addr, ttlStr)
|
||||
xl.Trace("send sid message from %s to %s%s", conn.LocalAddr(), addr, ttlStr)
|
||||
raddr, err := net.ResolveUDPAddr("udp4", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -341,7 +341,7 @@ func sendSidMessage(
|
||||
TransactionID: transactionID,
|
||||
Sid: sid,
|
||||
Response: false,
|
||||
Nonce: strings.Repeat("0", rand.IntN(20)),
|
||||
Nonce: strings.Repeat("0", rand.Intn(20)),
|
||||
}
|
||||
buf, err := EncodeMessage(m, key)
|
||||
if err != nil {
|
||||
@@ -351,14 +351,14 @@ func sendSidMessage(
|
||||
uConn := ipv4.NewConn(conn)
|
||||
original, err := uConn.TTL()
|
||||
if err != nil {
|
||||
xl.Tracef("get ttl error %v", err)
|
||||
xl.Trace("get ttl error %v", err)
|
||||
return err
|
||||
}
|
||||
xl.Tracef("original ttl %d", original)
|
||||
xl.Trace("original ttl %d", original)
|
||||
|
||||
err = uConn.SetTTL(ttl)
|
||||
if err != nil {
|
||||
xl.Tracef("set ttl error %v", err)
|
||||
xl.Trace("set ttl error %v", err)
|
||||
} else {
|
||||
defer func() {
|
||||
_ = uConn.SetTTL(original)
|
||||
@@ -377,12 +377,12 @@ func sendSidMessageToRangePorts(
|
||||
sendFunc func(*net.UDPConn, string) error,
|
||||
) {
|
||||
xl := xlog.FromContextSafe(ctx)
|
||||
for _, ip := range slices.Compact(parseIPs(addrs)) {
|
||||
for _, ip := range lo.Uniq(parseIPs(addrs)) {
|
||||
for _, portsRange := range ports {
|
||||
for i := portsRange.From; i <= portsRange.To; i++ {
|
||||
detectAddr := net.JoinHostPort(ip, strconv.Itoa(i))
|
||||
if err := sendFunc(conn, detectAddr); err != nil {
|
||||
xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
|
||||
xl.Trace("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
|
||||
}
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}
|
||||
@@ -398,7 +398,7 @@ func sendSidMessageToRandomPorts(
|
||||
used := sets.New[int]()
|
||||
getUnusedPort := func() int {
|
||||
for i := 0; i < 10; i++ {
|
||||
port := rand.IntN(65535-1024) + 1024
|
||||
port := rand.Intn(65535-1024) + 1024
|
||||
if !used.Has(port) {
|
||||
used.Insert(port)
|
||||
return port
|
||||
@@ -419,10 +419,10 @@ func sendSidMessageToRandomPorts(
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ip := range slices.Compact(parseIPs(addrs)) {
|
||||
for _, ip := range lo.Uniq(parseIPs(addrs)) {
|
||||
detectAddr := net.JoinHostPort(ip, strconv.Itoa(port))
|
||||
if err := sendFunc(conn, detectAddr); err != nil {
|
||||
xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
|
||||
xl.Trace("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 15)
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/fatedier/golib/crypto"
|
||||
"github.com/pion/stun/v2"
|
||||
"github.com/pion/stun"
|
||||
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
)
|
||||
|
@@ -19,15 +19,11 @@ package plugin
|
||||
import (
|
||||
"crypto/tls"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -57,11 +53,7 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
rp := &httputil.ReverseProxy{
|
||||
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
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Scheme = "https"
|
||||
req.URL.Host = p.opts.LocalAddr
|
||||
if p.opts.HostHeaderRewrite != "" {
|
||||
@@ -71,9 +63,7 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
},
|
||||
Transport: tr,
|
||||
BufferPool: pool.NewBuffer(32 * 1024),
|
||||
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
p.s = &http.Server{
|
||||
|
@@ -54,8 +54,7 @@ func NewHTTPProxyPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
hp.s = &http.Server{
|
||||
Handler: hp,
|
||||
ReadHeaderTimeout: 60 * time.Second,
|
||||
Handler: hp,
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
@@ -20,17 +20,12 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"time"
|
||||
|
||||
"github.com/fatedier/golib/pool"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/transport"
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
@@ -55,10 +50,7 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
rp := &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
|
||||
r.SetXForwarded()
|
||||
req := r.Out
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Scheme = "http"
|
||||
req.URL.Host = p.opts.LocalAddr
|
||||
if p.opts.HostHeaderRewrite != "" {
|
||||
@@ -68,13 +60,10 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
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: 60 * time.Second,
|
||||
Handler: rp,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -108,11 +97,8 @@ func (p *HTTPS2HTTPPlugin) genTLSConfig() (*tls.Config, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) {
|
||||
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
if extra.SrcAddr != nil {
|
||||
wrapConn.SetRemoteAddr(extra.SrcAddr)
|
||||
}
|
||||
_ = p.l.PutConn(wrapConn)
|
||||
}
|
||||
|
||||
|
@@ -20,17 +20,12 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"time"
|
||||
|
||||
"github.com/fatedier/golib/pool"
|
||||
|
||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||
"github.com/fatedier/frp/pkg/transport"
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
@@ -60,10 +55,7 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
}
|
||||
|
||||
rp := &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
|
||||
r.SetXForwarded()
|
||||
req := r.Out
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Scheme = "https"
|
||||
req.URL.Host = p.opts.LocalAddr
|
||||
if p.opts.HostHeaderRewrite != "" {
|
||||
@@ -73,14 +65,11 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
},
|
||||
Transport: tr,
|
||||
BufferPool: pool.NewBuffer(32 * 1024),
|
||||
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
p.s = &http.Server{
|
||||
Handler: rp,
|
||||
ReadHeaderTimeout: 60 * time.Second,
|
||||
Handler: rp,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -114,11 +103,8 @@ func (p *HTTPS2HTTPSPlugin) genTLSConfig() (*tls.Config, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extra *ExtraInfo) {
|
||||
func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, _ *ExtraInfo) {
|
||||
wrapConn := netpkg.WrapReadWriteCloserToConn(conn, realConn)
|
||||
if extra.SrcAddr != nil {
|
||||
wrapConn.SetRemoteAddr(extra.SrcAddr)
|
||||
}
|
||||
_ = p.l.PutConn(wrapConn)
|
||||
}
|
||||
|
||||
|
@@ -50,8 +50,6 @@ func Create(name string, options v1.ClientPluginOptions) (p Plugin, err error) {
|
||||
|
||||
type ExtraInfo struct {
|
||||
ProxyProtocolHeader *pp.Header
|
||||
SrcAddr net.Addr
|
||||
DstAddr net.Addr
|
||||
}
|
||||
|
||||
type Plugin interface {
|
||||
|
@@ -60,8 +60,7 @@ func NewStaticFilePlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
||||
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")
|
||||
sp.s = &http.Server{
|
||||
Handler: router,
|
||||
ReadHeaderTimeout: 60 * time.Second,
|
||||
Handler: router,
|
||||
}
|
||||
go func() {
|
||||
_ = sp.s.Serve(listener)
|
||||
|
@@ -86,7 +86,7 @@ func (m *Manager) Login(content *LoginContent) (*LoginContent, error) {
|
||||
for _, p := range m.loginPlugins {
|
||||
res, retContent, err = p.Handle(ctx, OpLogin, *content)
|
||||
if err != nil {
|
||||
xl.Warnf("send Login request to plugin [%s] error: %v", p.Name(), err)
|
||||
xl.Warn("send Login request to plugin [%s] error: %v", p.Name(), err)
|
||||
return nil, errors.New("send Login request to plugin error")
|
||||
}
|
||||
if res.Reject {
|
||||
@@ -120,7 +120,7 @@ func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) {
|
||||
for _, p := range m.newProxyPlugins {
|
||||
res, retContent, err = p.Handle(ctx, OpNewProxy, *content)
|
||||
if err != nil {
|
||||
xl.Warnf("send NewProxy request to plugin [%s] error: %v", p.Name(), err)
|
||||
xl.Warn("send NewProxy request to plugin [%s] error: %v", p.Name(), err)
|
||||
return nil, errors.New("send NewProxy request to plugin error")
|
||||
}
|
||||
if res.Reject {
|
||||
@@ -147,7 +147,7 @@ func (m *Manager) CloseProxy(content *CloseProxyContent) error {
|
||||
for _, p := range m.closeProxyPlugins {
|
||||
_, _, err := p.Handle(ctx, OpCloseProxy, *content)
|
||||
if err != nil {
|
||||
xl.Warnf("send CloseProxy request to plugin [%s] error: %v", p.Name(), err)
|
||||
xl.Warn("send CloseProxy request to plugin [%s] error: %v", p.Name(), err)
|
||||
errs = append(errs, fmt.Sprintf("[%s]: %v", p.Name(), err))
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,7 @@ func (m *Manager) Ping(content *PingContent) (*PingContent, error) {
|
||||
for _, p := range m.pingPlugins {
|
||||
res, retContent, err = p.Handle(ctx, OpPing, *content)
|
||||
if err != nil {
|
||||
xl.Warnf("send Ping request to plugin [%s] error: %v", p.Name(), err)
|
||||
xl.Warn("send Ping request to plugin [%s] error: %v", p.Name(), err)
|
||||
return nil, errors.New("send Ping request to plugin error")
|
||||
}
|
||||
if res.Reject {
|
||||
@@ -213,7 +213,7 @@ func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent,
|
||||
for _, p := range m.newWorkConnPlugins {
|
||||
res, retContent, err = p.Handle(ctx, OpNewWorkConn, *content)
|
||||
if err != nil {
|
||||
xl.Warnf("send NewWorkConn request to plugin [%s] error: %v", p.Name(), err)
|
||||
xl.Warn("send NewWorkConn request to plugin [%s] error: %v", p.Name(), err)
|
||||
return nil, errors.New("send NewWorkConn request to plugin error")
|
||||
}
|
||||
if res.Reject {
|
||||
@@ -247,7 +247,7 @@ func (m *Manager) NewUserConn(content *NewUserConnContent) (*NewUserConnContent,
|
||||
for _, p := range m.newUserConnPlugins {
|
||||
res, retContent, err = p.Handle(ctx, OpNewUserConn, *content)
|
||||
if err != nil {
|
||||
xl.Infof("send NewUserConn request to plugin [%s] error: %v", p.Name(), err)
|
||||
xl.Info("send NewUserConn request to plugin [%s] error: %v", p.Name(), err)
|
||||
return nil, errors.New("send NewUserConn request to plugin error")
|
||||
}
|
||||
if res.Reject {
|
||||
|
@@ -75,7 +75,7 @@ func NewGateway(
|
||||
sshConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
authorizedKeysMap, err := loadAuthorizedKeysFromFile(cfg.AuthorizedKeysFile)
|
||||
if err != nil {
|
||||
log.Errorf("load authorized keys file error: %v", err)
|
||||
log.Error("load authorized keys file error: %v", err)
|
||||
return nil, fmt.Errorf("internal error")
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func (g *Gateway) handleConn(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
if err := ts.Run(); err != nil {
|
||||
log.Errorf("ssh tunnel server run error: %v", err)
|
||||
log.Error("ssh tunnel server run error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,12 +20,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
libio "github.com/fatedier/golib/io"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
"golang.org/x/crypto/ssh"
|
||||
@@ -123,7 +123,7 @@ func (s *TunnelServer) Run() error {
|
||||
// join workConn and ssh channel
|
||||
c, err := s.openConn(addr)
|
||||
if err != nil {
|
||||
log.Tracef("open conn error: %v", err)
|
||||
log.Trace("open conn error: %v", err)
|
||||
workConn.Close()
|
||||
return false
|
||||
}
|
||||
@@ -167,7 +167,7 @@ func (s *TunnelServer) Run() error {
|
||||
|
||||
if ps, err := s.waitProxyStatusReady(pc.GetBaseConfig().Name, time.Second); err != nil {
|
||||
s.writeToClient(err.Error())
|
||||
log.Warnf("wait proxy status ready error: %v", err)
|
||||
log.Warn("wait proxy status ready error: %v", err)
|
||||
} else {
|
||||
// success
|
||||
s.writeToClient(createSuccessInfo(clientCfg.User, pc, ps))
|
||||
@@ -175,7 +175,7 @@ func (s *TunnelServer) Run() error {
|
||||
}
|
||||
|
||||
s.vc.Close()
|
||||
log.Tracef("ssh tunnel connection from %v closed", sshConn.RemoteAddr())
|
||||
log.Trace("ssh tunnel connection from %v closed", sshConn.RemoteAddr())
|
||||
s.closeDoneChOnce.Do(func() {
|
||||
_ = sshConn.Close()
|
||||
close(s.doneCh)
|
||||
@@ -262,7 +262,7 @@ func (s *TunnelServer) parseClientAndProxyConfigurer(_ *tcpipForward, extraPaylo
|
||||
}
|
||||
proxyType := strings.TrimSpace(args[0])
|
||||
supportTypes := []string{"tcp", "http", "https", "tcpmux", "stcp"}
|
||||
if !slices.Contains(supportTypes, proxyType) {
|
||||
if !lo.Contains(supportTypes, proxyType) {
|
||||
return nil, nil, helpMessage, fmt.Errorf("invalid proxy type: %s, support types: %v", proxyType, supportTypes)
|
||||
}
|
||||
pc := v1.NewProxyConfigurerByType(v1.ProxyType(proxyType))
|
||||
@@ -363,13 +363,11 @@ func (s *TunnelServer) waitProxyStatusReady(name string, timeout time.Duration)
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
statusExporter := s.vc.Service().StatusExporter()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
ps, ok := statusExporter.GetProxyStatus(name)
|
||||
if !ok {
|
||||
ps, err := s.vc.Service().GetProxyStatus(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
switch ps.Phase {
|
||||
|
@@ -15,95 +15,78 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"fmt"
|
||||
|
||||
"github.com/fatedier/golib/log"
|
||||
"github.com/fatedier/beego/logs"
|
||||
)
|
||||
|
||||
var (
|
||||
TraceLevel = log.TraceLevel
|
||||
DebugLevel = log.DebugLevel
|
||||
InfoLevel = log.InfoLevel
|
||||
WarnLevel = log.WarnLevel
|
||||
ErrorLevel = log.ErrorLevel
|
||||
)
|
||||
|
||||
var Logger *log.Logger
|
||||
// Log is the under log object
|
||||
var Log *logs.BeeLogger
|
||||
|
||||
func init() {
|
||||
Logger = log.New(
|
||||
log.WithCaller(true),
|
||||
log.AddCallerSkip(1),
|
||||
log.WithLevel(log.InfoLevel),
|
||||
)
|
||||
Log = logs.NewLogger(200)
|
||||
Log.EnableFuncCallDepth(true)
|
||||
Log.SetLogFuncCallDepth(Log.GetLogFuncCallDepth() + 1)
|
||||
}
|
||||
|
||||
func InitLogger(logPath string, levelStr string, maxDays int, disableLogColor bool) {
|
||||
options := []log.Option{}
|
||||
if logPath == "console" {
|
||||
if !disableLogColor {
|
||||
options = append(options,
|
||||
log.WithOutput(log.NewConsoleWriter(log.ConsoleConfig{
|
||||
Colorful: true,
|
||||
}, os.Stdout)),
|
||||
)
|
||||
func InitLog(logFile string, logLevel string, maxdays int64, disableLogColor bool) {
|
||||
SetLogFile(logFile, maxdays, disableLogColor)
|
||||
SetLogLevel(logLevel)
|
||||
}
|
||||
|
||||
// SetLogFile to configure log params
|
||||
func SetLogFile(logFile string, maxdays int64, disableLogColor bool) {
|
||||
if logFile == "console" {
|
||||
params := ""
|
||||
if disableLogColor {
|
||||
params = `{"color": false}`
|
||||
}
|
||||
_ = Log.SetLogger("console", params)
|
||||
} else {
|
||||
writer := log.NewRotateFileWriter(log.RotateFileConfig{
|
||||
FileName: logPath,
|
||||
Mode: log.RotateFileModeDaily,
|
||||
MaxDays: maxDays,
|
||||
})
|
||||
writer.Init()
|
||||
options = append(options, log.WithOutput(writer))
|
||||
}
|
||||
|
||||
level, err := log.ParseLevel(levelStr)
|
||||
if err != nil {
|
||||
level = log.InfoLevel
|
||||
}
|
||||
options = append(options, log.WithLevel(level))
|
||||
Logger = Logger.WithOptions(options...)
|
||||
}
|
||||
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
Logger.Errorf(format, v...)
|
||||
}
|
||||
|
||||
func Warnf(format string, v ...interface{}) {
|
||||
Logger.Warnf(format, v...)
|
||||
}
|
||||
|
||||
func Infof(format string, v ...interface{}) {
|
||||
Logger.Infof(format, v...)
|
||||
}
|
||||
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
Logger.Debugf(format, v...)
|
||||
}
|
||||
|
||||
func Tracef(format string, v ...interface{}) {
|
||||
Logger.Tracef(format, v...)
|
||||
}
|
||||
|
||||
func Logf(level log.Level, offset int, format string, v ...interface{}) {
|
||||
Logger.Logf(level, offset, format, v...)
|
||||
}
|
||||
|
||||
type WriteLogger struct {
|
||||
level log.Level
|
||||
offset int
|
||||
}
|
||||
|
||||
func NewWriteLogger(level log.Level, offset int) *WriteLogger {
|
||||
return &WriteLogger{
|
||||
level: level,
|
||||
offset: offset,
|
||||
params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays)
|
||||
_ = Log.SetLogger("file", params)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// SetLogLevel set log level, default is warning
|
||||
// value: error, warning, info, debug, trace
|
||||
func SetLogLevel(logLevel string) {
|
||||
var level int
|
||||
switch logLevel {
|
||||
case "error":
|
||||
level = 3
|
||||
case "warn":
|
||||
level = 4
|
||||
case "info":
|
||||
level = 6
|
||||
case "debug":
|
||||
level = 7
|
||||
case "trace":
|
||||
level = 8
|
||||
default:
|
||||
level = 4 // warning
|
||||
}
|
||||
Log.SetLevel(level)
|
||||
}
|
||||
|
||||
// wrap log
|
||||
|
||||
func Error(format string, v ...interface{}) {
|
||||
Log.Error(format, v...)
|
||||
}
|
||||
|
||||
func Warn(format string, v ...interface{}) {
|
||||
Log.Warn(format, v...)
|
||||
}
|
||||
|
||||
func Info(format string, v ...interface{}) {
|
||||
Log.Info(format, v...)
|
||||
}
|
||||
|
||||
func Debug(format string, v ...interface{}) {
|
||||
Log.Debug(format, v...)
|
||||
}
|
||||
|
||||
func Trace(format string, v ...interface{}) {
|
||||
Log.Trace(format, v...)
|
||||
}
|
||||
|
@@ -76,11 +76,9 @@ type WrapReadWriteCloserConn struct {
|
||||
io.ReadWriteCloser
|
||||
|
||||
underConn net.Conn
|
||||
|
||||
remoteAddr net.Addr
|
||||
}
|
||||
|
||||
func WrapReadWriteCloserToConn(rwc io.ReadWriteCloser, underConn net.Conn) *WrapReadWriteCloserConn {
|
||||
func WrapReadWriteCloserToConn(rwc io.ReadWriteCloser, underConn net.Conn) net.Conn {
|
||||
return &WrapReadWriteCloserConn{
|
||||
ReadWriteCloser: rwc,
|
||||
underConn: underConn,
|
||||
@@ -94,14 +92,7 @@ func (conn *WrapReadWriteCloserConn) LocalAddr() net.Addr {
|
||||
return (*net.TCPAddr)(nil)
|
||||
}
|
||||
|
||||
func (conn *WrapReadWriteCloserConn) SetRemoteAddr(addr net.Addr) {
|
||||
conn.remoteAddr = addr
|
||||
}
|
||||
|
||||
func (conn *WrapReadWriteCloserConn) RemoteAddr() net.Addr {
|
||||
if conn.remoteAddr != nil {
|
||||
return conn.remoteAddr
|
||||
}
|
||||
if conn.underConn != nil {
|
||||
return conn.underConn.RemoteAddr()
|
||||
}
|
||||
|
@@ -5,11 +5,11 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
libnet "github.com/fatedier/golib/net"
|
||||
libdial "github.com/fatedier/golib/net/dial"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libnet.AfterHookFunc {
|
||||
func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libdial.AfterHookFunc {
|
||||
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
||||
if enableTLS && !disableCustomTLSHeadByte {
|
||||
_, err := c.Write([]byte{byte(FRPTLSHeadByte)})
|
||||
@@ -21,7 +21,7 @@ func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) li
|
||||
}
|
||||
}
|
||||
|
||||
func DialHookWebsocket(protocol string, host string) libnet.AfterHookFunc {
|
||||
func DialHookWebsocket(protocol string, host string) libdial.AfterHookFunc {
|
||||
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
||||
if protocol != "wss" {
|
||||
protocol = "ws"
|
||||
|
@@ -26,8 +26,8 @@ func SetDefaultDNSAddress(dnsAddress string) {
|
||||
// Change default dns server
|
||||
net.DefaultResolver = &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
|
||||
return net.Dial(network, dnsAddress)
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return net.Dial("udp", dnsAddress)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,30 @@ import (
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
)
|
||||
|
||||
type HTTPAuthWrapper struct {
|
||||
h http.Handler
|
||||
user string
|
||||
passwd string
|
||||
}
|
||||
|
||||
func NewHTTPBasicAuthWrapper(h http.Handler, user, passwd string) http.Handler {
|
||||
return &HTTPAuthWrapper{
|
||||
h: h,
|
||||
user: user,
|
||||
passwd: passwd,
|
||||
}
|
||||
}
|
||||
|
||||
func (aw *HTTPAuthWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
user, passwd, hasAuth := r.BasicAuth()
|
||||
if (aw.user == "" && aw.passwd == "") || (hasAuth && user == aw.user && passwd == aw.passwd) {
|
||||
aw.h.ServeHTTP(w, r)
|
||||
} else {
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
type HTTPAuthMiddleware struct {
|
||||
user string
|
||||
passwd string
|
||||
|
@@ -18,7 +18,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go/v5"
|
||||
kcp "github.com/fatedier/kcp-go"
|
||||
)
|
||||
|
||||
type KCPListener struct {
|
||||
@@ -85,15 +85,7 @@ func (l *KCPListener) Addr() net.Addr {
|
||||
}
|
||||
|
||||
func NewKCPConnFromUDP(conn *net.UDPConn, connected bool, raddr string) (net.Conn, error) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pConn net.PacketConn = conn
|
||||
if connected {
|
||||
pConn = &ConnectedUDPConn{conn}
|
||||
}
|
||||
kcpConn, err := kcp.NewConn3(1, udpAddr, nil, 10, 3, pConn)
|
||||
kcpConn, err := kcp.NewConnEx(1, connected, raddr, nil, 10, 3, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
@@ -40,9 +40,8 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
||||
}))
|
||||
|
||||
wl.server = &http.Server{
|
||||
Addr: ln.Addr().String(),
|
||||
Handler: muxer,
|
||||
ReadHeaderTimeout: 60 * time.Second,
|
||||
Addr: ln.Addr().String(),
|
||||
Handler: muxer,
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -51,6 +50,15 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
||||
return
|
||||
}
|
||||
|
||||
func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error) {
|
||||
tcpLn, err := net.Listen("tcp", net.JoinHostPort(bindAddr, strconv.Itoa(bindPort)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := NewWebsocketListener(tcpLn)
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (p *WebsocketListener) Accept() (net.Conn, error) {
|
||||
c, ok := <-p.acceptCh
|
||||
if !ok {
|
||||
|
@@ -1,22 +0,0 @@
|
||||
// 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() {
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
// 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, _ string) (net.Conn, error) {
|
||||
return net.Dial(network, "8.8.8.8:53")
|
||||
},
|
||||
}
|
||||
}
|
@@ -20,7 +20,7 @@ import (
|
||||
"crypto/subtle"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
mathrand "math/rand/v2"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -47,6 +47,16 @@ func RandIDWithLen(idLen int) (id string, err error) {
|
||||
return id[:idLen], nil
|
||||
}
|
||||
|
||||
// RandIDWithRandLen return a rand string with length between [start, end).
|
||||
func RandIDWithRandLen(start, end int) (id string, err error) {
|
||||
if start >= end {
|
||||
err = fmt.Errorf("start should be less than end")
|
||||
return
|
||||
}
|
||||
idLen := mathrand.Intn(end-start) + start
|
||||
return RandIDWithLen(idLen)
|
||||
}
|
||||
|
||||
func GetAuthKey(token string, timestamp int64) (key string) {
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write([]byte(token))
|
||||
@@ -124,7 +134,7 @@ func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Durati
|
||||
if max <= min {
|
||||
n = min
|
||||
} else {
|
||||
n = mathrand.Int64N(max-min) + min
|
||||
n = mathrand.Int63n(max-min) + min
|
||||
}
|
||||
d := duration * time.Duration(n) / time.Duration(1000)
|
||||
time.Sleep(d)
|
||||
|
@@ -14,6 +14,48 @@ func TestRandId(t *testing.T) {
|
||||
assert.Equal(16, len(id))
|
||||
}
|
||||
|
||||
func TestRandIDWithRandLen(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
start int
|
||||
end int
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "start and end are equal",
|
||||
start: 5,
|
||||
end: 5,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "start is less than end",
|
||||
start: 5,
|
||||
end: 10,
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "start is greater than end",
|
||||
start: 10,
|
||||
end: 5,
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
id, err := RandIDWithRandLen(tt.start, tt.end)
|
||||
if tt.expectErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.GreaterOrEqual(len(id), tt.start)
|
||||
assert.Less(len(id), tt.end)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuthKey(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
key := GetAuthKey("1234", 1488720000)
|
||||
|
@@ -14,8 +14,34 @@
|
||||
|
||||
package version
|
||||
|
||||
var version = "0.57.0"
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var version = "0.54.0"
|
||||
|
||||
func Full() string {
|
||||
return version
|
||||
}
|
||||
|
||||
func getSubVersion(v string, position int) int64 {
|
||||
arr := strings.Split(v, ".")
|
||||
if len(arr) < 3 {
|
||||
return 0
|
||||
}
|
||||
res, _ := strconv.ParseInt(arr[position], 10, 64)
|
||||
return res
|
||||
}
|
||||
|
||||
func Proto(v string) int64 {
|
||||
return getSubVersion(v, 0)
|
||||
}
|
||||
|
||||
func Major(v string) int64 {
|
||||
return getSubVersion(v, 1)
|
||||
}
|
||||
|
||||
func Minor(v string) int64 {
|
||||
return getSubVersion(v, 2)
|
||||
}
|
||||
|
53
pkg/util/version/version_test.go
Normal file
53
pkg/util/version/version_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2016 fatedier, fatedier@gmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFull(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
version := Full()
|
||||
arr := strings.Split(version, ".")
|
||||
assert.Equal(3, len(arr))
|
||||
|
||||
proto, err := strconv.ParseInt(arr[0], 10, 64)
|
||||
assert.NoError(err)
|
||||
assert.True(proto >= 0)
|
||||
|
||||
major, err := strconv.ParseInt(arr[1], 10, 64)
|
||||
assert.NoError(err)
|
||||
assert.True(major >= 0)
|
||||
|
||||
minor, err := strconv.ParseInt(arr[2], 10, 64)
|
||||
assert.NoError(err)
|
||||
assert.True(minor >= 0)
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
proto := Proto(Full())
|
||||
major := Major(Full())
|
||||
minor := Minor(Full())
|
||||
parseVersion := fmt.Sprintf("%d.%d.%d", proto, major, minor)
|
||||
version := Full()
|
||||
assert.Equal(parseVersion, version)
|
||||
}
|
@@ -15,11 +15,12 @@
|
||||
package vhost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
stdlog "log"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
"github.com/fatedier/golib/pool"
|
||||
|
||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
logpkg "github.com/fatedier/frp/pkg/util/log"
|
||||
)
|
||||
|
||||
var ErrNoRouteFound = errors.New("no route found")
|
||||
@@ -57,10 +58,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
}
|
||||
proxy := &httputil.ReverseProxy{
|
||||
// Modify incoming requests by route policies.
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
|
||||
r.SetXForwarded()
|
||||
req := r.Out
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Scheme = "http"
|
||||
reqRouteInfo := req.Context().Value(RouteInfoKey).(*RequestRouteInfo)
|
||||
oldHost, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
|
||||
@@ -76,7 +74,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
// ignore error here, it will use CreateConnFn instead later
|
||||
endpoint, _ = rc.ChooseEndpointFn()
|
||||
reqRouteInfo.Endpoint = endpoint
|
||||
log.Tracef("choose endpoint name [%s] for http request host [%s] path [%s] httpuser [%s]",
|
||||
logpkg.Trace("choose endpoint name [%s] for http request host [%s] path [%s] httpuser [%s]",
|
||||
endpoint, oldHost, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
|
||||
}
|
||||
// Set {domain}.{location}.{routeByHTTPUser}.{endpoint} as URL host here to let http transport reuse connections.
|
||||
@@ -115,16 +113,10 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
BufferPool: pool.NewBuffer(32 * 1024),
|
||||
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||
BufferPool: newWrapPool(),
|
||||
ErrorLog: log.New(newWrapLogger(), "", 0),
|
||||
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||
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
|
||||
}
|
||||
}
|
||||
logpkg.Warn("do http proxy request [host: %s] error: %v", req.Host, err)
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
_, _ = rw.Write(getNotFoundPageContent())
|
||||
},
|
||||
@@ -151,7 +143,7 @@ func (rp *HTTPReverseProxy) UnRegister(routeCfg RouteConfig) {
|
||||
func (rp *HTTPReverseProxy) GetRouteConfig(domain, location, routeByHTTPUser string) *RouteConfig {
|
||||
vr, ok := rp.getVhost(domain, location, routeByHTTPUser)
|
||||
if ok {
|
||||
log.Debugf("get new HTTP request host [%s] path [%s] httpuser [%s]", domain, location, routeByHTTPUser)
|
||||
logpkg.Debug("get new HTTP request host [%s] path [%s] httpuser [%s]", domain, location, routeByHTTPUser)
|
||||
return vr.payload.(*RouteConfig)
|
||||
}
|
||||
return nil
|
||||
@@ -327,3 +319,20 @@ func (rp *HTTPReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||
rp.proxy.ServeHTTP(rw, newreq)
|
||||
}
|
||||
}
|
||||
|
||||
type wrapPool struct{}
|
||||
|
||||
func newWrapPool() *wrapPool { return &wrapPool{} }
|
||||
|
||||
func (p *wrapPool) Get() []byte { return pool.GetBuf(32 * 1024) }
|
||||
|
||||
func (p *wrapPool) Put(buf []byte) { pool.PutBuf(buf) }
|
||||
|
||||
type wrapLogger struct{}
|
||||
|
||||
func newWrapLogger() *wrapLogger { return &wrapLogger{} }
|
||||
|
||||
func (l *wrapLogger) Write(p []byte) (n int, err error) {
|
||||
logpkg.Warn("%s", string(bytes.TrimRight(p, "\n")))
|
||||
return len(p), nil
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
func TestGetHTTPSHostname(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
l, err := net.Listen("tcp", "127.0.0.1:")
|
||||
l, err := net.Listen("tcp", ":")
|
||||
require.NoError(err)
|
||||
defer l.Close()
|
||||
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
logpkg "github.com/fatedier/frp/pkg/util/log"
|
||||
"github.com/fatedier/frp/pkg/util/version"
|
||||
)
|
||||
|
||||
@@ -58,7 +58,7 @@ func getNotFoundPageContent() []byte {
|
||||
if NotFoundPagePath != "" {
|
||||
buf, err = os.ReadFile(NotFoundPagePath)
|
||||
if err != nil {
|
||||
log.Warnf("read custom 404 page error: %v", err)
|
||||
logpkg.Warn("read custom 404 page error: %v", err)
|
||||
buf = []byte(NotFound)
|
||||
}
|
||||
} else {
|
||||
|
@@ -1,9 +1,8 @@
|
||||
package vhost
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"errors"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@@ -59,10 +58,7 @@ func (r *Routers) Add(domain, location, httpUser string, payload interface{}) er
|
||||
payload: payload,
|
||||
}
|
||||
vrs = append(vrs, vr)
|
||||
|
||||
slices.SortFunc(vrs, func(a, b *Router) int {
|
||||
return -cmp.Compare(a.location, b.location)
|
||||
})
|
||||
sort.Sort(sort.Reverse(ByLocation(vrs)))
|
||||
|
||||
routersByHTTPUser[httpUser] = vrs
|
||||
r.indexByDomain[domain] = routersByHTTPUser
|
||||
@@ -134,3 +130,18 @@ func (r *Routers) exist(host, path, httpUser string) (route *Router, exist bool)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// sort by location
|
||||
type ByLocation []*Router
|
||||
|
||||
func (a ByLocation) Len() int {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func (a ByLocation) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
|
||||
func (a ByLocation) Less(i, j int) bool {
|
||||
return strings.Compare(a[i].location, a[j].location) < 0
|
||||
}
|
||||
|
@@ -203,7 +203,7 @@ func (v *Muxer) handle(c net.Conn) {
|
||||
|
||||
sConn, reqInfoMap, err := v.vhostFunc(c)
|
||||
if err != nil {
|
||||
log.Debugf("get hostname from http/https request error: %v", err)
|
||||
log.Debug("get hostname from http/https request error: %v", err)
|
||||
_ = c.Close()
|
||||
return
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func (v *Muxer) handle(c net.Conn) {
|
||||
httpUser := reqInfoMap["HTTPUser"]
|
||||
l, ok := v.getListener(name, path, httpUser)
|
||||
if !ok {
|
||||
log.Debugf("http request for host [%s] path [%s] httpUser [%s] not found", name, path, httpUser)
|
||||
log.Debug("http request for host [%s] path [%s] httpUser [%s] not found", name, path, httpUser)
|
||||
v.failHook(sConn)
|
||||
return
|
||||
}
|
||||
@@ -221,7 +221,7 @@ func (v *Muxer) handle(c net.Conn) {
|
||||
xl := xlog.FromContextSafe(l.ctx)
|
||||
if v.successHook != nil {
|
||||
if err := v.successHook(c, reqInfoMap); err != nil {
|
||||
xl.Infof("success func failure on vhost connection: %v", err)
|
||||
xl.Info("success func failure on vhost connection: %v", err)
|
||||
_ = c.Close()
|
||||
return
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func (v *Muxer) handle(c net.Conn) {
|
||||
if l.mux.checkAuth != nil && l.username != "" {
|
||||
ok, err := l.mux.checkAuth(c, l.username, l.password, reqInfoMap)
|
||||
if !ok || err != nil {
|
||||
xl.Debugf("auth failed for user: %s", l.username)
|
||||
xl.Debug("auth failed for user: %s", l.username)
|
||||
_ = c.Close()
|
||||
return
|
||||
}
|
||||
@@ -244,12 +244,12 @@ func (v *Muxer) handle(c net.Conn) {
|
||||
}
|
||||
c = sConn
|
||||
|
||||
xl.Debugf("new request host [%s] path [%s] httpUser [%s]", name, path, httpUser)
|
||||
xl.Debug("new request host [%s] path [%s] httpUser [%s]", name, path, httpUser)
|
||||
err = errors.PanicToError(func() {
|
||||
l.accept <- c
|
||||
})
|
||||
if err != nil {
|
||||
xl.Warnf("listener is already closed, ignore this request")
|
||||
xl.Warn("listener is already closed, ignore this request")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,10 +278,10 @@ func (l *Listener) Accept() (net.Conn, error) {
|
||||
if l.mux.rewriteHost != nil {
|
||||
sConn, err := l.mux.rewriteHost(conn, l.rewriteHost)
|
||||
if err != nil {
|
||||
xl.Warnf("host header rewrite failed: %v", err)
|
||||
xl.Warn("host header rewrite failed: %v", err)
|
||||
return nil, fmt.Errorf("host header rewrite failed")
|
||||
}
|
||||
xl.Debugf("rewrite host to [%s] success", l.rewriteHost)
|
||||
xl.Debug("rewrite host to [%s] success", l.rewriteHost)
|
||||
conn = sConn
|
||||
}
|
||||
return netpkg.NewContextConn(l.ctx, conn), nil
|
||||
|
@@ -15,7 +15,8 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fatedier/frp/pkg/util/util"
|
||||
@@ -173,3 +174,21 @@ func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
|
||||
return period
|
||||
}), true, stopCh)
|
||||
}
|
||||
|
||||
func MergeAndCloseOnAnyStopChannel[T any](upstreams ...<-chan T) <-chan T {
|
||||
out := make(chan T)
|
||||
closeOnce := sync.Once{}
|
||||
for _, upstream := range upstreams {
|
||||
ch := upstream
|
||||
go func() {
|
||||
select {
|
||||
case <-ch:
|
||||
closeOnce.Do(func() {
|
||||
close(out)
|
||||
})
|
||||
case <-out:
|
||||
}
|
||||
}()
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
@@ -15,8 +15,7 @@
|
||||
package xlog
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/fatedier/frp/pkg/util/log"
|
||||
)
|
||||
@@ -78,8 +77,8 @@ func (l *Logger) AddPrefix(prefix LogPrefix) *Logger {
|
||||
}
|
||||
|
||||
func (l *Logger) renderPrefixString() {
|
||||
slices.SortStableFunc(l.prefixes, func(a, b LogPrefix) int {
|
||||
return cmp.Compare(a.Priority, b.Priority)
|
||||
sort.SliceStable(l.prefixes, func(i, j int) bool {
|
||||
return l.prefixes[i].Priority < l.prefixes[j].Priority
|
||||
})
|
||||
l.prefixString = ""
|
||||
for _, v := range l.prefixes {
|
||||
@@ -94,22 +93,22 @@ func (l *Logger) Spawn() *Logger {
|
||||
return nl
|
||||
}
|
||||
|
||||
func (l *Logger) Errorf(format string, v ...interface{}) {
|
||||
log.Logger.Errorf(l.prefixString+format, v...)
|
||||
func (l *Logger) Error(format string, v ...interface{}) {
|
||||
log.Log.Error(l.prefixString+format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Warnf(format string, v ...interface{}) {
|
||||
log.Logger.Warnf(l.prefixString+format, v...)
|
||||
func (l *Logger) Warn(format string, v ...interface{}) {
|
||||
log.Log.Warn(l.prefixString+format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Infof(format string, v ...interface{}) {
|
||||
log.Logger.Infof(l.prefixString+format, v...)
|
||||
func (l *Logger) Info(format string, v ...interface{}) {
|
||||
log.Log.Info(l.prefixString+format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Debugf(format string, v ...interface{}) {
|
||||
log.Logger.Debugf(l.prefixString+format, v...)
|
||||
func (l *Logger) Debug(format string, v ...interface{}) {
|
||||
log.Log.Debug(l.prefixString+format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Tracef(format string, v ...interface{}) {
|
||||
log.Logger.Tracef(l.prefixString+format, v...)
|
||||
func (l *Logger) Trace(format string, v ...interface{}) {
|
||||
log.Log.Trace(l.prefixString+format, v...)
|
||||
}
|
||||
|
@@ -224,7 +224,7 @@ func (ctl *Control) Close() error {
|
||||
|
||||
func (ctl *Control) Replaced(newCtl *Control) {
|
||||
xl := ctl.xl
|
||||
xl.Infof("Replaced by client [%s]", newCtl.runID)
|
||||
xl.Info("Replaced by client [%s]", newCtl.runID)
|
||||
ctl.runID = ""
|
||||
ctl.conn.Close()
|
||||
}
|
||||
@@ -233,17 +233,17 @@ func (ctl *Control) RegisterWorkConn(conn net.Conn) error {
|
||||
xl := ctl.xl
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
xl.Errorf("panic error: %v", err)
|
||||
xl.Errorf(string(debug.Stack()))
|
||||
xl.Error("panic error: %v", err)
|
||||
xl.Error(string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case ctl.workConnCh <- conn:
|
||||
xl.Debugf("new work connection registered")
|
||||
xl.Debug("new work connection registered")
|
||||
return nil
|
||||
default:
|
||||
xl.Debugf("work connection pool is full, discarding")
|
||||
xl.Debug("work connection pool is full, discarding")
|
||||
return fmt.Errorf("work connection pool is full, discarding")
|
||||
}
|
||||
}
|
||||
@@ -256,8 +256,8 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
||||
xl := ctl.xl
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
xl.Errorf("panic error: %v", err)
|
||||
xl.Errorf(string(debug.Stack()))
|
||||
xl.Error("panic error: %v", err)
|
||||
xl.Error(string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -269,7 +269,7 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
||||
err = pkgerr.ErrCtlClosed
|
||||
return
|
||||
}
|
||||
xl.Debugf("get work connection from pool")
|
||||
xl.Debug("get work connection from pool")
|
||||
default:
|
||||
// no work connections available in the poll, send message to frpc to get more
|
||||
if err := ctl.msgDispatcher.Send(&msg.ReqWorkConn{}); err != nil {
|
||||
@@ -280,13 +280,13 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
||||
case workConn, ok = <-ctl.workConnCh:
|
||||
if !ok {
|
||||
err = pkgerr.ErrCtlClosed
|
||||
xl.Warnf("no work connections available, %v", err)
|
||||
xl.Warn("no work connections available, %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
case <-time.After(time.Duration(ctl.serverCfg.UserConnTimeout) * time.Second):
|
||||
err = fmt.Errorf("timeout trying to get work connection")
|
||||
xl.Warnf("%v", err)
|
||||
xl.Warn("%v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -297,18 +297,20 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
||||
}
|
||||
|
||||
func (ctl *Control) heartbeatWorker() {
|
||||
if ctl.serverCfg.Transport.HeartbeatTimeout <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// Don't need application heartbeat if TCPMux is enabled,
|
||||
// yamux will do same thing.
|
||||
// TODO(fatedier): let default HeartbeatTimeout to -1 if TCPMux is enabled. Users can still set it to positive value to enable it.
|
||||
if !lo.FromPtr(ctl.serverCfg.Transport.TCPMux) && ctl.serverCfg.Transport.HeartbeatTimeout > 0 {
|
||||
go wait.Until(func() {
|
||||
if time.Since(ctl.lastPing.Load().(time.Time)) > time.Duration(ctl.serverCfg.Transport.HeartbeatTimeout)*time.Second {
|
||||
xl.Warn("heartbeat timeout")
|
||||
ctl.conn.Close()
|
||||
return
|
||||
}
|
||||
}, time.Second, ctl.doneCh)
|
||||
}
|
||||
}
|
||||
|
||||
// block until Control closed
|
||||
@@ -354,7 +356,7 @@ func (ctl *Control) worker() {
|
||||
}
|
||||
|
||||
metrics.Server.CloseClient()
|
||||
xl.Infof("client exit success")
|
||||
xl.Info("client exit success")
|
||||
close(ctl.doneCh)
|
||||
}
|
||||
|
||||
@@ -391,12 +393,12 @@ func (ctl *Control) handleNewProxy(m msg.Message) {
|
||||
ProxyName: inMsg.ProxyName,
|
||||
}
|
||||
if err != nil {
|
||||
xl.Warnf("new proxy [%s] type [%s] error: %v", inMsg.ProxyName, inMsg.ProxyType, err)
|
||||
xl.Warn("new proxy [%s] type [%s] error: %v", inMsg.ProxyName, inMsg.ProxyType, err)
|
||||
resp.Error = util.GenerateResponseErrorString(fmt.Sprintf("new proxy [%s] error", inMsg.ProxyName),
|
||||
err, lo.FromPtr(ctl.serverCfg.DetailedErrorsToClient))
|
||||
} else {
|
||||
resp.RemoteAddr = remoteAddr
|
||||
xl.Infof("new proxy [%s] type [%s] success", inMsg.ProxyName, inMsg.ProxyType)
|
||||
xl.Info("new proxy [%s] type [%s] success", inMsg.ProxyName, inMsg.ProxyType)
|
||||
metrics.Server.NewProxy(inMsg.ProxyName, inMsg.ProxyType)
|
||||
}
|
||||
_ = ctl.msgDispatcher.Send(resp)
|
||||
@@ -420,14 +422,14 @@ func (ctl *Control) handlePing(m msg.Message) {
|
||||
err = ctl.authVerifier.VerifyPing(inMsg)
|
||||
}
|
||||
if err != nil {
|
||||
xl.Warnf("received invalid ping: %v", err)
|
||||
xl.Warn("received invalid ping: %v", err)
|
||||
_ = ctl.msgDispatcher.Send(&msg.Pong{
|
||||
Error: util.GenerateResponseErrorString("invalid ping", err, lo.FromPtr(ctl.serverCfg.DetailedErrorsToClient)),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctl.lastPing.Store(time.Now())
|
||||
xl.Debugf("receive heartbeat")
|
||||
xl.Debug("receive heartbeat")
|
||||
_ = ctl.msgDispatcher.Send(&msg.Pong{})
|
||||
}
|
||||
|
||||
@@ -450,7 +452,7 @@ func (ctl *Control) handleCloseProxy(m msg.Message) {
|
||||
xl := ctl.xl
|
||||
inMsg := m.(*msg.CloseProxy)
|
||||
_ = ctl.CloseProxy(inMsg)
|
||||
xl.Infof("close proxy [%s] success", inMsg.ProxyName)
|
||||
xl.Info("close proxy [%s] success", inMsg.ProxyName)
|
||||
}
|
||||
|
||||
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user