mirror of
https://github.com/fatedier/frp.git
synced 2026-03-20 16:59:18 +08:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bf1eb8565 | ||
|
|
a821db3f45 | ||
|
|
ecb6ed9258 | ||
|
|
b2ae433e18 | ||
|
|
b26080589b | ||
|
|
aff979c2b6 | ||
|
|
46f809d711 | ||
|
|
72595b2da8 | ||
|
|
c842558ace | ||
|
|
ed61049041 | ||
|
|
abe6f580c0 | ||
|
|
e940066012 | ||
|
|
1e846df870 | ||
|
|
0ab055e946 | ||
|
|
fca59c71e2 | ||
|
|
fae2f8768d | ||
|
|
3d9499f554 | ||
|
|
7adeeedd55 | ||
|
|
127a31ea6a | ||
|
|
a85bd9a4d9 | ||
|
|
01d551ec8d | ||
|
|
16cabf4127 | ||
|
|
968be4a2c2 | ||
|
|
aa0a41ee4e | ||
|
|
8a779eb88c | ||
|
|
0138dbd352 | ||
|
|
9b45c93c14 | ||
|
|
191da54980 | ||
|
|
c3b7575453 |
25
.circleci/config.yml
Normal file
25
.circleci/config.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
test1:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.15-node
|
||||||
|
working_directory: /go/src/github.com/fatedier/frp
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: make
|
||||||
|
- run: make alltest
|
||||||
|
test2:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.14-node
|
||||||
|
working_directory: /go/src/github.com/fatedier/frp
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: make
|
||||||
|
- run: make alltest
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
build_and_test:
|
||||||
|
jobs:
|
||||||
|
- test1
|
||||||
|
- test2
|
||||||
29
.github/ISSUE_TEMPLATE
vendored
29
.github/ISSUE_TEMPLATE
vendored
@@ -1,29 +0,0 @@
|
|||||||
Issue is only used for submiting bug report and documents typo. If there are same issues or answers can be found in documents, we will close it directly.
|
|
||||||
|
|
||||||
Use the commands below to provide key information from your environment:
|
|
||||||
You do NOT have to include this information if this is a FEATURE REQUEST
|
|
||||||
|
|
||||||
**What version of frp are you using (./frpc -v or ./frps -v)?**
|
|
||||||
|
|
||||||
|
|
||||||
**What operating system and processor architecture are you using (`go env`)?**
|
|
||||||
|
|
||||||
|
|
||||||
**Configures you used:**
|
|
||||||
|
|
||||||
|
|
||||||
**Steps to reproduce the issue:**
|
|
||||||
1.
|
|
||||||
2.
|
|
||||||
3.
|
|
||||||
|
|
||||||
**Describe the results you received:**
|
|
||||||
|
|
||||||
|
|
||||||
**Describe the results you expected:**
|
|
||||||
|
|
||||||
|
|
||||||
**Additional information you deem important (e.g. issue happens only occasionally):**
|
|
||||||
|
|
||||||
|
|
||||||
**Can you point out what caused this issue (optional)**
|
|
||||||
44
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
44
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Bug Report for FRP
|
||||||
|
title: ''
|
||||||
|
labels: Requires Testing
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- From Chinese to English by machine translation, welcome to revise and polish. -->
|
||||||
|
|
||||||
|
<!-- ⚠️⚠️ Incomplete reports will be marked as invalid, and closed, with few exceptions ⚠️⚠️ -->
|
||||||
|
<!-- in addition, please use search well so that the same solution can be found in the feedback, we will close it directly -->
|
||||||
|
<!-- for convenience of differentiation, use FRPS or FRPC to refer to the FRP server or client -->
|
||||||
|
|
||||||
|
**[REQUIRED] hat version of frp are you using**
|
||||||
|
<!-- Use ./frpc -v or ./frps -v -->
|
||||||
|
Version:
|
||||||
|
|
||||||
|
**[REQUIRED] What operating system and processor architecture are you using**
|
||||||
|
OS:
|
||||||
|
CPU architecture:
|
||||||
|
|
||||||
|
**[REQUIRED] description of errors**
|
||||||
|
|
||||||
|
**confile**
|
||||||
|
<!-- Please pay attention to hiding the token, server_addr and other privacy information -->
|
||||||
|
|
||||||
|
**log file**
|
||||||
|
<!-- If the file is too large, use Pastebin, for example https://pastebin.ubuntu.com/ -->
|
||||||
|
|
||||||
|
**Steps to reproduce the issue**
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
**Supplementary information**
|
||||||
|
|
||||||
|
**Can you guess what caused this issue**
|
||||||
|
|
||||||
|
**Checklist**:
|
||||||
|
<!--- Make sure you've completed the following steps (put an "X" between of brackets): -->
|
||||||
|
- [] I included all information required in the sections above
|
||||||
|
- [] I made sure there are no duplicates of this report [(Use Search)](https://github.com/fatedier/frp/issues?q=is%3Aissue)
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: DOCS
|
||||||
|
url: https://github.com/fatedier/frp
|
||||||
|
about: Here you can find out how to configure frp.
|
||||||
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: "[+] Enhancement"
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- From Chinese to English by machine translation, welcome to revise and polish. -->
|
||||||
|
|
||||||
|
**The solution you want**
|
||||||
|
<!--A clear and concise description of the solution you want. -->
|
||||||
|
|
||||||
|
**Alternatives considered**
|
||||||
|
<!--A clear and concise description of any alternative solutions or features you have considered. -->
|
||||||
|
|
||||||
|
**How to implement this function**
|
||||||
|
<!--Implementation steps for the solution you want. -->
|
||||||
|
|
||||||
|
**Application scenarios of this function**
|
||||||
|
<!--Make a clear and concise description of the application scenario of the solution you want. -->
|
||||||
32
.github/workflows/build-and-push-image.yml
vendored
32
.github/workflows/build-and-push-image.yml
vendored
@@ -75,41 +75,41 @@ jobs:
|
|||||||
name: Get Image Tag Name
|
name: Get Image Tag Name
|
||||||
run: |
|
run: |
|
||||||
if [ x${{ github.event.inputs.tag }} == x"" ]; then
|
if [ x${{ github.event.inputs.tag }} == x"" ]; then
|
||||||
echo ::set-env name=TAG_NAME::${GITHUB_REF#refs/*/}
|
echo "TAG_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo ::set-env name=TAG_NAME::${{ github.event.inputs.tag }}
|
echo "TAG_NAME=${{ github.event.inputs.tag }}" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
# prepare image tags
|
# prepare image tags
|
||||||
-
|
-
|
||||||
name: Prepare Image Tags
|
name: Prepare Image Tags
|
||||||
run: |
|
run: |
|
||||||
echo ::set-env name=DOCKERFILE_FRPC_PATH::dockerfiles/Dockerfile-for-frpc
|
echo "DOCKERFILE_FRPC_PATH=dockerfiles/Dockerfile-for-frpc" >> $GITHUB_ENV
|
||||||
echo ::set-env name=DOCKERFILE_FRPS_PATH::dockerfiles/Dockerfile-for-frps
|
echo "DOCKERFILE_FRPS_PATH=dockerfiles/Dockerfile-for-frps" >> $GITHUB_ENV
|
||||||
echo ::set-env name=TAG_FRPC::fatedier/frpc:$TAG_NAME
|
echo "TAG_FRPC=fatedier/frpc:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||||
echo ::set-env name=TAG_FRPS::fatedier/frps:$TAG_NAME
|
echo "TAG_FRPS=fatedier/frps:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||||
echo ::set-env name=TAG_FRPC_GPR::ghcr.io/fatedier/frpc:$TAG_NAME
|
echo "TAG_FRPC_GPR=ghcr.io/fatedier/frpc:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||||
echo ::set-env name=TAG_FRPS_GPR::ghcr.io/fatedier/frps:$TAG_NAME
|
echo "TAG_FRPS_GPR=ghcr.io/fatedier/frps:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||||
# build images
|
# build images
|
||||||
-
|
-
|
||||||
name: Build Images
|
name: Build Images
|
||||||
run: |
|
run: |
|
||||||
# for Docker hub
|
# for Docker hub
|
||||||
docker build --file $DOCKERFILE_FRPC_PATH --tag $TAG_FRPC .
|
docker build --file ${{ env.DOCKERFILE_FRPC_PATH }} --tag ${{ env.TAG_FRPC }} .
|
||||||
docker build --file $DOCKERFILE_FRPS_PATH --tag $TAG_FRPS .
|
docker build --file ${{ env.DOCKERFILE_FRPS_PATH }} --tag ${{ env.TAG_FRPS }} .
|
||||||
# for GPR
|
# for GPR
|
||||||
docker build --file $DOCKERFILE_FRPC_PATH --tag $TAG_FRPC_GPR .
|
docker build --file ${{ env.DOCKERFILE_FRPC_PATH }} --tag ${{ env.TAG_FRPC_GPR }} .
|
||||||
docker build --file $DOCKERFILE_FRPS_PATH --tag $TAG_FRPS_GPR .
|
docker build --file ${{ env.DOCKERFILE_FRPS_PATH }} --tag ${{ env.TAG_FRPS_GPR }} .
|
||||||
# push to dockerhub
|
# push to dockerhub
|
||||||
-
|
-
|
||||||
name: Publish to Dockerhub
|
name: Publish to Dockerhub
|
||||||
run: |
|
run: |
|
||||||
echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login --username ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
|
echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login --username ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
|
||||||
docker push $TAG_FRPC
|
docker push ${{ env.TAG_FRPC }}
|
||||||
docker push $TAG_FRPS
|
docker push ${{ env.TAG_FRPS }}
|
||||||
# push to gpr
|
# push to gpr
|
||||||
-
|
-
|
||||||
name: Publish to GPR
|
name: Publish to GPR
|
||||||
run: |
|
run: |
|
||||||
echo ${{ secrets.GPR_TOKEN }} | docker login ghcr.io --username ${{ github.repository_owner }} --password-stdin
|
echo ${{ secrets.GPR_TOKEN }} | docker login ghcr.io --username ${{ github.repository_owner }} --password-stdin
|
||||||
docker push $TAG_FRPC_GPR
|
docker push ${{ env.TAG_FRPC_GPR }}
|
||||||
docker push $TAG_FRPS_GPR
|
docker push ${{ env.TAG_FRPS_GPR }}
|
||||||
|
|||||||
30
.github/workflows/goreleaser.yml
vendored
Normal file
30
.github/workflows/goreleaser.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: goreleaser
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
goreleaser:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.15
|
||||||
|
|
||||||
|
- name: Make All
|
||||||
|
run: |
|
||||||
|
./package.sh
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist --release-notes=./Release.md
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GPR_TOKEN }}
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,6 +29,7 @@ packages/
|
|||||||
release/
|
release/
|
||||||
test/bin/
|
test/bin/
|
||||||
vendor/
|
vendor/
|
||||||
|
dist/
|
||||||
|
|
||||||
# Cache
|
# Cache
|
||||||
*.swp
|
*.swp
|
||||||
|
|||||||
19
.goreleaser.yml
Normal file
19
.goreleaser.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
builds:
|
||||||
|
- skip: true
|
||||||
|
checksum:
|
||||||
|
name_template: 'checksums.txt'
|
||||||
|
release:
|
||||||
|
# Same as for github
|
||||||
|
# Note: it can only be one: either github, gitlab or gitea
|
||||||
|
github:
|
||||||
|
owner: fatedier
|
||||||
|
name: frp
|
||||||
|
|
||||||
|
draft: false
|
||||||
|
|
||||||
|
# You can add extra pre-existing files to the release.
|
||||||
|
# The filename on the release will be the last part of the path (base). If
|
||||||
|
# another file with the same name exists, the latest one found will be used.
|
||||||
|
# Defaults to empty.
|
||||||
|
extra_files:
|
||||||
|
- glob: ./release/packages/*
|
||||||
12
.travis.yml
12
.travis.yml
@@ -1,12 +0,0 @@
|
|||||||
sudo: false
|
|
||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.13.x
|
|
||||||
- 1.14.x
|
|
||||||
|
|
||||||
install:
|
|
||||||
- make
|
|
||||||
|
|
||||||
script:
|
|
||||||
- make alltest
|
|
||||||
4
Makefile
4
Makefile
@@ -20,10 +20,10 @@ fmt:
|
|||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
|
||||||
frps:
|
frps:
|
||||||
env CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o bin/frps ./cmd/frps
|
env CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o bin/frps ./cmd/frps
|
||||||
|
|
||||||
frpc:
|
frpc:
|
||||||
env CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o bin/frpc ./cmd/frpc
|
env CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o bin/frpc ./cmd/frpc
|
||||||
|
|
||||||
test: gotest
|
test: gotest
|
||||||
|
|
||||||
|
|||||||
@@ -7,32 +7,29 @@ all: build
|
|||||||
build: app
|
build: app
|
||||||
|
|
||||||
app:
|
app:
|
||||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_darwin_amd64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_darwin_amd64 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frps_darwin_amd64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_darwin_amd64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_freebsd_386 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_freebsd_386 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./release/frps_freebsd_386 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_freebsd_386 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_freebsd_amd64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_freebsd_amd64 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frps_freebsd_amd64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_freebsd_amd64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_386 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_386 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_386 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_386 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_amd64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_amd64 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_amd64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_amd64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_arm ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_arm ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_arm ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_arm ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_arm64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_arm64 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_arm64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_arm64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_windows_386.exe ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_windows_386.exe ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./release/frps_windows_386.exe ./cmd/frps
|
env CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_windows_386.exe ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_windows_amd64.exe ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_windows_amd64.exe ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./release/frps_windows_amd64.exe ./cmd/frps
|
env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_windows_amd64.exe ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mips64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mips64 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mips64le ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mips64le ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips64le ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips64le ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mips ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mips ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mipsle ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frpc_linux_mipsle ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mipsle ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mipsle ./cmd/frps
|
||||||
|
|
||||||
temp:
|
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_amd64 ./cmd/frps
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# frp
|
# frp
|
||||||
|
|
||||||
[](https://travis-ci.org/fatedier/frp)
|
[](https://circleci.com/gh/fatedier/frp)
|
||||||
[](https://github.com/fatedier/frp/releases)
|
[](https://github.com/fatedier/frp/releases)
|
||||||
|
|
||||||
[README](README.md) | [中文文档](README_zh.md)
|
[README](README.md) | [中文文档](README_zh.md)
|
||||||
|
|||||||
3
Release.md
Normal file
3
Release.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
### Fix
|
||||||
|
|
||||||
|
* Reduce binary file size.
|
||||||
BIN
assets/frpc/static/535877f50039c0cb49a6196a5b7517cd.woff
Normal file
BIN
assets/frpc/static/535877f50039c0cb49a6196a5b7517cd.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/frpc/static/732389ded34cb9c52dd88271f1345af9.ttf
Normal file
BIN
assets/frpc/static/732389ded34cb9c52dd88271f1345af9.ttf
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?d2cd6337d30c7b22e836"></script><script type="text/javascript" src="vendor.js?edb271e1d9c81f857840"></script></body> </html>
|
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?f30e0e5ff7dbde4611e0"></script><script type="text/javascript" src="vendor.js?a82aed5fb0b844cbdb29"></script></body> </html>
|
||||||
@@ -1 +1 @@
|
|||||||
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"edb271e1d9c81f857840"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
|
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"a82aed5fb0b844cbdb29"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
assets/frps/static/535877f50039c0cb49a6196a5b7517cd.woff
Normal file
BIN
assets/frps/static/535877f50039c0cb49a6196a5b7517cd.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/frps/static/732389ded34cb9c52dd88271f1345af9.ttf
Normal file
BIN
assets/frps/static/732389ded34cb9c52dd88271f1345af9.ttf
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?14bea8276eef86cc7c61"></script><script type="text/javascript" src="vendor.js?51925ec1a77936b64d61"></script></body> </html>
|
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?b8b55d8156200869417b"></script><script type="text/javascript" src="vendor.js?3e078a9d741093b909de"></script></body> </html>
|
||||||
@@ -1 +1 @@
|
|||||||
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"51925ec1a77936b64d61"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
|
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,u,c){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(e[i]=u[i]);for(r&&r(t,u,c);s.length;)s.shift()();if(c)for(l=0;l<c.length;l++)f=n(n.s=c[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var u=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=u;var c=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"3e078a9d741093b909de"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,c.appendChild(i),u},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -17,10 +17,10 @@ package client
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -222,8 +222,10 @@ func (ctl *Control) connectServer() (conn net.Conn, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HTTPProxy, ctl.clientCfg.Protocol,
|
|
||||||
fmt.Sprintf("%s:%d", ctl.clientCfg.ServerAddr, ctl.clientCfg.ServerPort), tlsConfig)
|
address := net.JoinHostPort(ctl.clientCfg.ServerAddr, strconv.Itoa(ctl.clientCfg.ServerPort))
|
||||||
|
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HTTPProxy, ctl.clientCfg.Protocol, address, tlsConfig)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xl.Warn("start new connection to server error: %v", err)
|
xl.Warn("start new connection to server error: %v", err)
|
||||||
return
|
return
|
||||||
@@ -295,7 +297,7 @@ func (ctl *Control) msgHandler() {
|
|||||||
}()
|
}()
|
||||||
defer ctl.msgHandlerShutdown.Done()
|
defer ctl.msgHandlerShutdown.Done()
|
||||||
|
|
||||||
hbSend := time.NewTicker(time.Duration(ctl.clientCfg.HeartBeatInterval) * time.Second)
|
hbSend := time.NewTicker(time.Duration(ctl.clientCfg.HeartbeatInterval) * time.Second)
|
||||||
defer hbSend.Stop()
|
defer hbSend.Stop()
|
||||||
hbCheck := time.NewTicker(time.Second)
|
hbCheck := time.NewTicker(time.Second)
|
||||||
defer hbCheck.Stop()
|
defer hbCheck.Stop()
|
||||||
@@ -314,7 +316,7 @@ func (ctl *Control) msgHandler() {
|
|||||||
}
|
}
|
||||||
ctl.sendCh <- pingMsg
|
ctl.sendCh <- pingMsg
|
||||||
case <-hbCheck.C:
|
case <-hbCheck.C:
|
||||||
if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartbeatTimeout)*time.Second {
|
||||||
xl.Warn("heartbeat timeout")
|
xl.Warn("heartbeat timeout")
|
||||||
// let reader() stop
|
// let reader() stop
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -215,8 +216,9 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HTTPProxy, svr.cfg.Protocol,
|
|
||||||
fmt.Sprintf("%s:%d", svr.cfg.ServerAddr, svr.cfg.ServerPort), tlsConfig)
|
address := net.JoinHostPort(svr.cfg.ServerAddr, strconv.Itoa(svr.cfg.ServerPort))
|
||||||
|
conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HTTPProxy, svr.cfg.Protocol, address, tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,17 +157,16 @@ func parseClientCommonCfgFromIni(content string) (config.ClientCommonConf, error
|
|||||||
func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
|
func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
|
||||||
cfg = config.GetDefaultClientConf()
|
cfg = config.GetDefaultClientConf()
|
||||||
|
|
||||||
strs := strings.Split(serverAddr, ":")
|
ipStr, portStr, err := net.SplitHostPort(serverAddr)
|
||||||
if len(strs) < 2 {
|
if err != nil {
|
||||||
err = fmt.Errorf("invalid server_addr")
|
err = fmt.Errorf("invalid server_addr: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strs[0] != "" {
|
|
||||||
cfg.ServerAddr = strs[0]
|
cfg.ServerAddr = ipStr
|
||||||
}
|
cfg.ServerPort, err = strconv.Atoi(portStr)
|
||||||
cfg.ServerPort, err = strconv.Atoi(strs[1])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("invalid server_addr")
|
err = fmt.Errorf("invalid server_addr: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ var (
|
|||||||
dashboardPort int
|
dashboardPort int
|
||||||
dashboardUser string
|
dashboardUser string
|
||||||
dashboardPwd string
|
dashboardPwd string
|
||||||
|
enablePrometheus bool
|
||||||
assetsDir string
|
assetsDir string
|
||||||
logFile string
|
logFile string
|
||||||
logLevel string
|
logLevel string
|
||||||
@@ -79,6 +80,7 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().IntVarP(&dashboardPort, "dashboard_port", "", 0, "dashboard port")
|
rootCmd.PersistentFlags().IntVarP(&dashboardPort, "dashboard_port", "", 0, "dashboard port")
|
||||||
rootCmd.PersistentFlags().StringVarP(&dashboardUser, "dashboard_user", "", "admin", "dashboard user")
|
rootCmd.PersistentFlags().StringVarP(&dashboardUser, "dashboard_user", "", "admin", "dashboard user")
|
||||||
rootCmd.PersistentFlags().StringVarP(&dashboardPwd, "dashboard_pwd", "", "admin", "dashboard password")
|
rootCmd.PersistentFlags().StringVarP(&dashboardPwd, "dashboard_pwd", "", "admin", "dashboard password")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&enablePrometheus, "enable_prometheus", "", false, "enable prometheus dashboard")
|
||||||
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
|
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
|
||||||
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days")
|
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days")
|
||||||
@@ -103,6 +105,7 @@ var rootCmd = &cobra.Command{
|
|||||||
var cfg config.ServerCommonConf
|
var cfg config.ServerCommonConf
|
||||||
var err error
|
var err error
|
||||||
if cfgFile != "" {
|
if cfgFile != "" {
|
||||||
|
log.Info("frps uses config file: %s", cfgFile)
|
||||||
var content string
|
var content string
|
||||||
content, err = config.GetRenderedConfFromFile(cfgFile)
|
content, err = config.GetRenderedConfFromFile(cfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -110,6 +113,7 @@ var rootCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
|
cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
|
||||||
} else {
|
} else {
|
||||||
|
log.Info("frps uses command line arguments for config")
|
||||||
cfg, err = parseServerCommonCfg(CfgFileTypeCmd, "")
|
cfg, err = parseServerCommonCfg(CfgFileTypeCmd, "")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -171,6 +175,7 @@ func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
|
|||||||
cfg.DashboardPort = dashboardPort
|
cfg.DashboardPort = dashboardPort
|
||||||
cfg.DashboardUser = dashboardUser
|
cfg.DashboardUser = dashboardUser
|
||||||
cfg.DashboardPwd = dashboardPwd
|
cfg.DashboardPwd = dashboardPwd
|
||||||
|
cfg.EnablePrometheus = enablePrometheus
|
||||||
cfg.LogFile = logFile
|
cfg.LogFile = logFile
|
||||||
cfg.LogLevel = logLevel
|
cfg.LogLevel = logLevel
|
||||||
cfg.LogMaxDays = logMaxDays
|
cfg.LogMaxDays = logMaxDays
|
||||||
@@ -209,7 +214,7 @@ func runServer(cfg config.ServerCommonConf) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("start frps success")
|
log.Info("frps started successfully")
|
||||||
svr.Run()
|
svr.Run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,30 @@ log_max_days = 3
|
|||||||
disable_log_color = false
|
disable_log_color = false
|
||||||
|
|
||||||
# for authentication, should be same as your frps.ini
|
# for authentication, should be same as your frps.ini
|
||||||
# AuthenticateHeartBeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
|
# authenticate_heartbeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
|
||||||
authenticate_heartbeats = false
|
authenticate_heartbeats = false
|
||||||
|
|
||||||
# AuthenticateNewWorkConns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
|
# authenticate_new_work_conns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
|
||||||
authenticate_new_work_conns = false
|
authenticate_new_work_conns = false
|
||||||
|
|
||||||
# auth token
|
# auth token
|
||||||
token = 12345678
|
token = 12345678
|
||||||
|
|
||||||
|
# oidc_client_id specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
|
||||||
|
# By default, this value is "".
|
||||||
|
oidc_client_id =
|
||||||
|
|
||||||
|
# oidc_client_secret specifies the client secret to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
|
||||||
|
# By default, this value is "".
|
||||||
|
oidc_client_secret =
|
||||||
|
|
||||||
|
# oidc_audience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
|
||||||
|
oidc_audience =
|
||||||
|
|
||||||
|
# oidc_token_endpoint_url specifies the URL which implements OIDC Token Endpoint.
|
||||||
|
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
|
||||||
|
oidc_token_endpoint_url =
|
||||||
|
|
||||||
# set admin address for control frpc's action by http api such as reload
|
# set admin address for control frpc's action by http api such as reload
|
||||||
admin_addr = 127.0.0.1
|
admin_addr = 127.0.0.1
|
||||||
admin_port = 7400
|
admin_port = 7400
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ vhost_https_port = 443
|
|||||||
# response header timeout(seconds) for vhost http server, default is 60s
|
# response header timeout(seconds) for vhost http server, default is 60s
|
||||||
# vhost_http_timeout = 60
|
# vhost_http_timeout = 60
|
||||||
|
|
||||||
# TcpMuxHttpConnectPort specifies the port that the server listens for TCP
|
# tcpmux_httpconnect_port specifies the port that the server listens for TCP
|
||||||
# HTTP CONNECT requests. If the value is 0, the server will not multiplex TCP
|
# HTTP CONNECT requests. If the value is 0, the server will not multiplex TCP
|
||||||
# requests on one single port. If it's not - it will listen on this value for
|
# requests on one single port. If it's not - it will listen on this value for
|
||||||
# HTTP CONNECT requests. By default, this value is 0.
|
# HTTP CONNECT requests. By default, this value is 0.
|
||||||
@@ -44,6 +44,7 @@ enable_prometheus = true
|
|||||||
|
|
||||||
# dashboard assets directory(only for debug mode)
|
# dashboard assets directory(only for debug mode)
|
||||||
# assets_dir = ./static
|
# assets_dir = ./static
|
||||||
|
|
||||||
# console or real logFile path like ./frps.log
|
# console or real logFile path like ./frps.log
|
||||||
log_file = ./frps.log
|
log_file = ./frps.log
|
||||||
|
|
||||||
@@ -58,12 +59,12 @@ disable_log_color = false
|
|||||||
# DetailedErrorsToClient defines whether to send the specific error (with debug info) to frpc. By default, this value is true.
|
# DetailedErrorsToClient defines whether to send the specific error (with debug info) to frpc. By default, this value is true.
|
||||||
detailed_errors_to_client = true
|
detailed_errors_to_client = true
|
||||||
|
|
||||||
# AuthenticationMethod specifies what authentication method to use authenticate frpc with frps.
|
# authentication_method specifies what authentication method to use authenticate frpc with frps.
|
||||||
# If "token" is specified - token will be read into login message.
|
# If "token" is specified - token will be read into login message.
|
||||||
# If "oidc" is specified - OIDC (Open ID Connect) token will be issued using OIDC settings. By default, this value is "token".
|
# If "oidc" is specified - OIDC (Open ID Connect) token will be issued using OIDC settings. By default, this value is "token".
|
||||||
authentication_method = token
|
authentication_method = token
|
||||||
|
|
||||||
# AuthenticateHeartBeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
|
# authenticate_heartbeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
|
||||||
authenticate_heartbeats = false
|
authenticate_heartbeats = false
|
||||||
|
|
||||||
# AuthenticateNewWorkConns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
|
# AuthenticateNewWorkConns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
|
||||||
@@ -72,25 +73,31 @@ authenticate_new_work_conns = false
|
|||||||
# auth token
|
# auth token
|
||||||
token = 12345678
|
token = 12345678
|
||||||
|
|
||||||
# OidcClientId specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
|
# oidc_issuer specifies the issuer to verify OIDC tokens with.
|
||||||
# By default, this value is "".
|
# By default, this value is "".
|
||||||
oidc_client_id =
|
oidc_issuer =
|
||||||
|
|
||||||
# OidcClientSecret specifies the client secret to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
|
# oidc_audience specifies the audience OIDC tokens should contain when validated.
|
||||||
# By default, this value is "".
|
# By default, this value is "".
|
||||||
oidc_client_secret =
|
oidc_audience =
|
||||||
|
|
||||||
# OidcAudience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
|
# oidc_skip_expiry_check specifies whether to skip checking if the OIDC token is expired.
|
||||||
oidc_audience =
|
# By default, this value is false.
|
||||||
|
oidc_skip_expiry_check = false
|
||||||
|
|
||||||
# OidcTokenEndpointUrl specifies the URL which implements OIDC Token Endpoint.
|
|
||||||
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
|
# oidc_skip_issuer_check specifies whether to skip checking if the OIDC token's issuer claim matches the issuer specified in OidcIssuer.
|
||||||
oidc_token_endpoint_url =
|
# By default, this value is false.
|
||||||
|
oidc_skip_issuer_check = false
|
||||||
|
|
||||||
# heartbeat configure, it's not recommended to modify the default value
|
# heartbeat configure, it's not recommended to modify the default value
|
||||||
# the default value of heartbeat_timeout is 90
|
# the default value of heartbeat_timeout is 90
|
||||||
# heartbeat_timeout = 90
|
# heartbeat_timeout = 90
|
||||||
|
|
||||||
|
# user_conn_timeout configure, it's not recommended to modify the default value
|
||||||
|
# the default value of user_conn_timeout is 10
|
||||||
|
# user_conn_timeout = 10
|
||||||
|
|
||||||
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
||||||
allow_ports = 2000-3000,3001,3003,4000-50000
|
allow_ports = 2000-3000,3001,3003,4000-50000
|
||||||
|
|
||||||
@@ -100,7 +107,7 @@ max_pool_count = 5
|
|||||||
# max ports can be used for each client, default value is 0 means no limit
|
# max ports can be used for each client, default value is 0 means no limit
|
||||||
max_ports_per_client = 0
|
max_ports_per_client = 0
|
||||||
|
|
||||||
# TlsOnly specifies whether to only accept TLS-encrypted connections. By default, the value is false.
|
# tls_only specifies whether to only accept TLS-encrypted connections. By default, the value is false.
|
||||||
tls_only = false
|
tls_only = false
|
||||||
|
|
||||||
# tls_cert_file = server.crt
|
# tls_cert_file = server.crt
|
||||||
|
|||||||
@@ -209,9 +209,10 @@ path = /handler
|
|||||||
ops = NewProxy
|
ops = NewProxy
|
||||||
```
|
```
|
||||||
|
|
||||||
addr: the address where the external RPC service listens on.
|
- addr: the address where the external RPC service listens. Defaults to http. For https, specify the schema: `addr = https://127.0.0.1:9001`.
|
||||||
path: http request url path for the POST request.
|
- path: http request url path for the POST request.
|
||||||
ops: operations plugin needs to handle (e.g. "Login", "NewProxy", ...).
|
- ops: operations plugin needs to handle (e.g. "Login", "NewProxy", ...).
|
||||||
|
- tls_verify: When the schema is https, we verify by default. Set this value to false if you want to skip verification.
|
||||||
|
|
||||||
### Metadata
|
### Metadata
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module github.com/fatedier/frp
|
module github.com/fatedier/frp
|
||||||
|
|
||||||
go 1.12
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||||
|
|||||||
@@ -121,11 +121,11 @@ type ClientCommonConf struct {
|
|||||||
// HeartBeatInterval specifies at what interval heartbeats are sent to the
|
// HeartBeatInterval specifies at what interval heartbeats are sent to the
|
||||||
// server, in seconds. It is not recommended to change this value. By
|
// server, in seconds. It is not recommended to change this value. By
|
||||||
// default, this value is 30.
|
// default, this value is 30.
|
||||||
HeartBeatInterval int64 `json:"heartbeat_interval"`
|
HeartbeatInterval int64 `json:"heartbeat_interval"`
|
||||||
// HeartBeatTimeout specifies the maximum allowed heartbeat response delay
|
// HeartBeatTimeout specifies the maximum allowed heartbeat response delay
|
||||||
// before the connection is terminated, in seconds. It is not recommended
|
// before the connection is terminated, in seconds. It is not recommended
|
||||||
// to change this value. By default, this value is 90.
|
// to change this value. By default, this value is 90.
|
||||||
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
|
HeartbeatTimeout int64 `json:"heartbeat_timeout"`
|
||||||
// Client meta info
|
// Client meta info
|
||||||
Metas map[string]string `json:"metas"`
|
Metas map[string]string `json:"metas"`
|
||||||
// UDPPacketSize specifies the udp packet size
|
// UDPPacketSize specifies the udp packet size
|
||||||
@@ -160,8 +160,8 @@ func GetDefaultClientConf() ClientCommonConf {
|
|||||||
TLSCertFile: "",
|
TLSCertFile: "",
|
||||||
TLSKeyFile: "",
|
TLSKeyFile: "",
|
||||||
TLSTrustedCaFile: "",
|
TLSTrustedCaFile: "",
|
||||||
HeartBeatInterval: 30,
|
HeartbeatInterval: 30,
|
||||||
HeartBeatTimeout: 90,
|
HeartbeatTimeout: 90,
|
||||||
Metas: make(map[string]string),
|
Metas: make(map[string]string),
|
||||||
UDPPacketSize: 1500,
|
UDPPacketSize: 1500,
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,7 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
|
|||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.HeartBeatTimeout = v
|
cfg.HeartbeatTimeout = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if tmpStr, ok = conf.Get("common", "heartbeat_interval"); ok {
|
if tmpStr, ok = conf.Get("common", "heartbeat_interval"); ok {
|
||||||
@@ -320,7 +320,7 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
|
|||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.HeartBeatInterval = v
|
cfg.HeartbeatInterval = v
|
||||||
}
|
}
|
||||||
for k, v := range conf.Section("common") {
|
for k, v := range conf.Section("common") {
|
||||||
if strings.HasPrefix(k, "meta_") {
|
if strings.HasPrefix(k, "meta_") {
|
||||||
@@ -338,12 +338,12 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *ClientCommonConf) Check() (err error) {
|
func (cfg *ClientCommonConf) Check() (err error) {
|
||||||
if cfg.HeartBeatInterval <= 0 {
|
if cfg.HeartbeatInterval <= 0 {
|
||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.HeartBeatTimeout < cfg.HeartBeatInterval {
|
if cfg.HeartbeatTimeout < cfg.HeartbeatInterval {
|
||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ type ServerCommonConf struct {
|
|||||||
// AssetsDir specifies the local directory that the dashboard will load
|
// AssetsDir specifies the local directory that the dashboard will load
|
||||||
// resources from. If this value is "", assets will be loaded from the
|
// resources from. If this value is "", assets will be loaded from the
|
||||||
// bundled executable using statik. By default, this value is "".
|
// bundled executable using statik. By default, this value is "".
|
||||||
AssetsDir string `json:"asserts_dir"`
|
AssetsDir string `json:"assets_dir"`
|
||||||
// LogFile specifies a file where logs will be written to. This value will
|
// LogFile specifies a file where logs will be written to. This value will
|
||||||
// only be used if LogWay is set appropriately. By default, this value is
|
// only be used if LogWay is set appropriately. By default, this value is
|
||||||
// "console".
|
// "console".
|
||||||
@@ -154,7 +154,7 @@ type ServerCommonConf struct {
|
|||||||
// HeartBeatTimeout specifies the maximum time to wait for a heartbeat
|
// HeartBeatTimeout specifies the maximum time to wait for a heartbeat
|
||||||
// before terminating the connection. It is not recommended to change this
|
// before terminating the connection. It is not recommended to change this
|
||||||
// value. By default, this value is 90.
|
// value. By default, this value is 90.
|
||||||
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
|
HeartbeatTimeout int64 `json:"heartbeat_timeout"`
|
||||||
// UserConnTimeout specifies the maximum time to wait for a work
|
// UserConnTimeout specifies the maximum time to wait for a work
|
||||||
// connection. By default, this value is 10.
|
// connection. By default, this value is 10.
|
||||||
UserConnTimeout int64 `json:"user_conn_timeout"`
|
UserConnTimeout int64 `json:"user_conn_timeout"`
|
||||||
@@ -199,7 +199,7 @@ func GetDefaultServerConf() ServerCommonConf {
|
|||||||
TLSCertFile: "",
|
TLSCertFile: "",
|
||||||
TLSKeyFile: "",
|
TLSKeyFile: "",
|
||||||
TLSTrustedCaFile: "",
|
TLSTrustedCaFile: "",
|
||||||
HeartBeatTimeout: 90,
|
HeartbeatTimeout: 90,
|
||||||
UserConnTimeout: 10,
|
UserConnTimeout: 10,
|
||||||
Custom404Page: "",
|
Custom404Page: "",
|
||||||
HTTPPlugins: make(map[string]plugin.HTTPPluginOptions),
|
HTTPPlugins: make(map[string]plugin.HTTPPluginOptions),
|
||||||
@@ -421,7 +421,7 @@ func UnmarshalServerConfFromIni(content string) (cfg ServerCommonConf, err error
|
|||||||
err = fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
err = fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.HeartBeatTimeout = v
|
cfg.HeartbeatTimeout = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if tmpStr, ok = conf.Get("common", "tls_only"); ok && tmpStr == "true" {
|
if tmpStr, ok = conf.Get("common", "tls_only"); ok && tmpStr == "true" {
|
||||||
@@ -458,11 +458,16 @@ func UnmarshalPluginsFromIni(sections ini.File, cfg *ServerCommonConf) {
|
|||||||
for name, section := range sections {
|
for name, section := range sections {
|
||||||
if strings.HasPrefix(name, "plugin.") {
|
if strings.HasPrefix(name, "plugin.") {
|
||||||
name = strings.TrimSpace(strings.TrimPrefix(name, "plugin."))
|
name = strings.TrimSpace(strings.TrimPrefix(name, "plugin."))
|
||||||
|
var tls_verify, err = strconv.ParseBool(section["tls_verify"])
|
||||||
|
if err != nil {
|
||||||
|
tls_verify = true
|
||||||
|
}
|
||||||
options := plugin.HTTPPluginOptions{
|
options := plugin.HTTPPluginOptions{
|
||||||
Name: name,
|
Name: name,
|
||||||
Addr: section["addr"],
|
Addr: section["addr"],
|
||||||
Path: section["path"],
|
Path: section["path"],
|
||||||
Ops: strings.Split(section["ops"], ","),
|
Ops: strings.Split(section["ops"], ","),
|
||||||
|
TLSVerify: tls_verify,
|
||||||
}
|
}
|
||||||
for i := range options.Ops {
|
for i := range options.Ops {
|
||||||
options.Ops[i] = strings.TrimSpace(options.Ops[i])
|
options.Ops[i] = strings.TrimSpace(options.Ops[i])
|
||||||
|
|||||||
@@ -17,19 +17,22 @@ package plugin
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTPPluginOptions struct {
|
type HTTPPluginOptions struct {
|
||||||
Name string
|
Name string
|
||||||
Addr string
|
Addr string
|
||||||
Path string
|
Path string
|
||||||
Ops []string
|
Ops []string
|
||||||
|
TLSVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpPlugin struct {
|
type httpPlugin struct {
|
||||||
@@ -40,10 +43,25 @@ type httpPlugin struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin {
|
func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin {
|
||||||
|
var url = fmt.Sprintf("%s%s", options.Addr, options.Path)
|
||||||
|
|
||||||
|
var client *http.Client
|
||||||
|
if strings.HasPrefix(url, "https://") {
|
||||||
|
tr := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: options.TLSVerify == false},
|
||||||
|
}
|
||||||
|
client = &http.Client{Transport: tr}
|
||||||
|
} else {
|
||||||
|
client = &http.Client{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
|
||||||
|
url = "http://" + url
|
||||||
|
}
|
||||||
return &httpPlugin{
|
return &httpPlugin{
|
||||||
options: options,
|
options: options,
|
||||||
url: fmt.Sprintf("http://%s%s", options.Addr, options.Path),
|
url: url,
|
||||||
client: &http.Client{},
|
client: client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -33,6 +34,7 @@ func OkResponse() *http.Response {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use "CanonicalHost" func to replace all "GetHostFromAddr" func.
|
||||||
func GetHostFromAddr(addr string) (host string) {
|
func GetHostFromAddr(addr string) (host string) {
|
||||||
strs := strings.Split(addr, ":")
|
strs := strings.Split(addr, ":")
|
||||||
if len(strs) > 1 {
|
if len(strs) > 1 {
|
||||||
@@ -42,3 +44,34 @@ func GetHostFromAddr(addr string) (host string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canonicalHost strips port from host if present and returns the canonicalized
|
||||||
|
// host name.
|
||||||
|
func CanonicalHost(host string) (string, error) {
|
||||||
|
var err error
|
||||||
|
host = strings.ToLower(host)
|
||||||
|
if hasPort(host) {
|
||||||
|
host, _, err = net.SplitHostPort(host)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(host, ".") {
|
||||||
|
// Strip trailing dot from fully qualified domain names.
|
||||||
|
host = host[:len(host)-1]
|
||||||
|
}
|
||||||
|
return host, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasPort reports whether host contains a port number. host may be a host
|
||||||
|
// name, an IPv4 or an IPv6 address.
|
||||||
|
func hasPort(host string) bool {
|
||||||
|
colons := strings.Count(host, ":")
|
||||||
|
if colons == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if colons == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return host[0] == '[' && strings.Contains(host, "]:")
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.34.2"
|
var version string = "0.35.1"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package vhost
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@@ -59,20 +60,25 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
|||||||
req.URL.Scheme = "http"
|
req.URL.Scheme = "http"
|
||||||
url := req.Context().Value(RouteInfoURL).(string)
|
url := req.Context().Value(RouteInfoURL).(string)
|
||||||
oldHost := util.GetHostFromAddr(req.Context().Value(RouteInfoHost).(string))
|
oldHost := util.GetHostFromAddr(req.Context().Value(RouteInfoHost).(string))
|
||||||
host := rp.GetRealHost(oldHost, url)
|
rc := rp.GetRouteConfig(oldHost, url)
|
||||||
if host != "" {
|
if rc != nil {
|
||||||
req.Host = host
|
if rc.RewriteHost != "" {
|
||||||
}
|
req.Host = rc.RewriteHost
|
||||||
req.URL.Host = req.Host
|
}
|
||||||
|
// Set {domain}.{location} as URL host here to let http transport reuse connections.
|
||||||
|
req.URL.Host = rc.Domain + "." + base64.StdEncoding.EncodeToString([]byte(rc.Location))
|
||||||
|
|
||||||
headers := rp.GetHeaders(oldHost, url)
|
for k, v := range rc.Headers {
|
||||||
for k, v := range headers {
|
req.Header.Set(k, v)
|
||||||
req.Header.Set(k, v)
|
}
|
||||||
|
} else {
|
||||||
|
req.URL.Host = req.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
ResponseHeaderTimeout: rp.responseHeaderTimeout,
|
ResponseHeaderTimeout: rp.responseHeaderTimeout,
|
||||||
DisableKeepAlives: true,
|
IdleConnTimeout: 60 * time.Second,
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
url := ctx.Value(RouteInfoURL).(string)
|
url := ctx.Value(RouteInfoURL).(string)
|
||||||
host := util.GetHostFromAddr(ctx.Value(RouteInfoHost).(string))
|
host := util.GetHostFromAddr(ctx.Value(RouteInfoHost).(string))
|
||||||
@@ -107,6 +113,14 @@ func (rp *HTTPReverseProxy) UnRegister(domain string, location string) {
|
|||||||
rp.vhostRouter.Del(domain, location)
|
rp.vhostRouter.Del(domain, location)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rp *HTTPReverseProxy) GetRouteConfig(domain string, location string) *RouteConfig {
|
||||||
|
vr, ok := rp.getVhost(domain, location)
|
||||||
|
if ok {
|
||||||
|
return vr.payload.(*RouteConfig)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (rp *HTTPReverseProxy) GetRealHost(domain string, location string) (host string) {
|
func (rp *HTTPReverseProxy) GetRealHost(domain string, location string) (host string) {
|
||||||
vr, ok := rp.getVhost(domain, location)
|
vr, ok := rp.getVhost(domain, location)
|
||||||
if ok {
|
if ok {
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ func (v *Muxer) handle(c net.Conn) {
|
|||||||
|
|
||||||
sConn, reqInfoMap, err := v.vhostFunc(c)
|
sConn, reqInfoMap, err := v.vhostFunc(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("get hostname from http/https request error: %v", err)
|
log.Debug("get hostname from http/https request error: %v", err)
|
||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ func (ctl *Control) manager() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-heartbeat.C:
|
case <-heartbeat.C:
|
||||||
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartbeatTimeout)*time.Second {
|
||||||
xl.Warn("heartbeat timeout")
|
xl.Warn("heartbeat timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
SubdomainHost: svr.cfg.SubDomainHost,
|
SubdomainHost: svr.cfg.SubDomainHost,
|
||||||
MaxPoolCount: svr.cfg.MaxPoolCount,
|
MaxPoolCount: svr.cfg.MaxPoolCount,
|
||||||
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
|
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
|
||||||
HeartBeatTimeout: svr.cfg.HeartBeatTimeout,
|
HeartBeatTimeout: svr.cfg.HeartbeatTimeout,
|
||||||
|
|
||||||
TotalTrafficIn: serverStats.TotalTrafficIn,
|
TotalTrafficIn: serverStats.TotalTrafficIn,
|
||||||
TotalTrafficOut: serverStats.TotalTrafficOut,
|
TotalTrafficOut: serverStats.TotalTrafficOut,
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
|
|||||||
xl.Warn("failed to get work connection: %v", err)
|
xl.Warn("failed to get work connection: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
xl.Info("get a new work connection: [%s]", workConn.RemoteAddr().String())
|
xl.Debug("get a new work connection: [%s]", workConn.RemoteAddr().String())
|
||||||
xl.Spawn().AppendPrefix(pxy.GetName())
|
xl.Spawn().AppendPrefix(pxy.GetName())
|
||||||
workConn = frpNet.NewContextConn(pxy.ctx, workConn)
|
workConn = frpNet.NewContextConn(pxy.ctx, workConn)
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn,
|
|||||||
xl.Info("listener is closed")
|
xl.Info("listener is closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
xl.Debug("get a user connection [%s]", c.RemoteAddr().String())
|
xl.Info("get a user connection [%s]", c.RemoteAddr().String())
|
||||||
go handler(p, c, pxy.serverCfg)
|
go handler(p, c, pxy.serverCfg)
|
||||||
}
|
}
|
||||||
}(listener)
|
}(listener)
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ func TestHealthCheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
httpSvc3 := mock.NewHTTPServer(15005, func(w http.ResponseWriter, r *http.Request) {
|
httpSvc3 := mock.NewHTTPServer(15005, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
time.Sleep(time.Second)
|
||||||
w.Write([]byte("http3"))
|
w.Write([]byte("http3"))
|
||||||
})
|
})
|
||||||
err = httpSvc3.Start()
|
err = httpSvc3.Start()
|
||||||
@@ -147,6 +148,7 @@ func TestHealthCheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
httpSvc4 := mock.NewHTTPServer(15006, func(w http.ResponseWriter, r *http.Request) {
|
httpSvc4 := mock.NewHTTPServer(15006, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
time.Sleep(time.Second)
|
||||||
w.Write([]byte("http4"))
|
w.Write([]byte("http4"))
|
||||||
})
|
})
|
||||||
err = httpSvc4.Start()
|
err = httpSvc4.Start()
|
||||||
@@ -277,16 +279,30 @@ func TestHealthCheck(t *testing.T) {
|
|||||||
|
|
||||||
// ****** load balancing type http ******
|
// ****** load balancing type http ******
|
||||||
result = make([]string, 0)
|
result = make([]string, 0)
|
||||||
|
var wait sync.WaitGroup
|
||||||
|
var mu sync.Mutex
|
||||||
|
wait.Add(2)
|
||||||
|
|
||||||
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
go func() {
|
||||||
assert.NoError(err)
|
defer wait.Done()
|
||||||
assert.Equal(200, code)
|
code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
||||||
result = append(result, body)
|
assert.NoError(err)
|
||||||
|
assert.Equal(200, code)
|
||||||
|
mu.Lock()
|
||||||
|
result = append(result, body)
|
||||||
|
mu.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
go func() {
|
||||||
assert.NoError(err)
|
defer wait.Done()
|
||||||
assert.Equal(200, code)
|
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
||||||
result = append(result, body)
|
assert.NoError(err)
|
||||||
|
assert.Equal(200, code)
|
||||||
|
mu.Lock()
|
||||||
|
result = append(result, body)
|
||||||
|
mu.Unlock()
|
||||||
|
}()
|
||||||
|
wait.Wait()
|
||||||
|
|
||||||
assert.Contains(result, "http3")
|
assert.Contains(result, "http3")
|
||||||
assert.Contains(result, "http4")
|
assert.Contains(result, "http4")
|
||||||
|
|||||||
9334
web/frpc/package-lock.json
generated
9334
web/frpc/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
3454
web/frpc/yarn.lock
3454
web/frpc/yarn.lock
File diff suppressed because it is too large
Load Diff
9334
web/frps/package-lock.json
generated
9334
web/frps/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<el-row :gutter="20">
|
<el-row>
|
||||||
<el-col id="side-nav" :xs="24" :md="4">
|
<el-col id="side-nav" :xs="24" :md="4">
|
||||||
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect">
|
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect">
|
||||||
<el-menu-item index="/">Overview</el-menu-item>
|
<el-menu-item index="/">Overview</el-menu-item>
|
||||||
|
|||||||
6377
web/frps/yarn.lock
Normal file
6377
web/frps/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user