mirror of
https://github.com/fatedier/frp.git
synced 2025-07-27 15:45:39 +00: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
|
||||
run: |
|
||||
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
|
||||
echo ::set-env name=TAG_NAME::${{ github.event.inputs.tag }}
|
||||
echo "TAG_NAME=${{ github.event.inputs.tag }}" >> $GITHUB_ENV
|
||||
fi
|
||||
# prepare image tags
|
||||
-
|
||||
name: Prepare Image Tags
|
||||
run: |
|
||||
echo ::set-env name=DOCKERFILE_FRPC_PATH::dockerfiles/Dockerfile-for-frpc
|
||||
echo ::set-env name=DOCKERFILE_FRPS_PATH::dockerfiles/Dockerfile-for-frps
|
||||
echo ::set-env name=TAG_FRPC::fatedier/frpc:$TAG_NAME
|
||||
echo ::set-env name=TAG_FRPS::fatedier/frps:$TAG_NAME
|
||||
echo ::set-env name=TAG_FRPC_GPR::ghcr.io/fatedier/frpc:$TAG_NAME
|
||||
echo ::set-env name=TAG_FRPS_GPR::ghcr.io/fatedier/frps:$TAG_NAME
|
||||
echo "DOCKERFILE_FRPC_PATH=dockerfiles/Dockerfile-for-frpc" >> $GITHUB_ENV
|
||||
echo "DOCKERFILE_FRPS_PATH=dockerfiles/Dockerfile-for-frps" >> $GITHUB_ENV
|
||||
echo "TAG_FRPC=fatedier/frpc:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||
echo "TAG_FRPS=fatedier/frps:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||
echo "TAG_FRPC_GPR=ghcr.io/fatedier/frpc:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||
echo "TAG_FRPS_GPR=ghcr.io/fatedier/frps:${{ env.TAG_NAME }}" >> $GITHUB_ENV
|
||||
# build images
|
||||
-
|
||||
name: Build Images
|
||||
run: |
|
||||
# for Docker hub
|
||||
docker build --file $DOCKERFILE_FRPC_PATH --tag $TAG_FRPC .
|
||||
docker build --file $DOCKERFILE_FRPS_PATH --tag $TAG_FRPS .
|
||||
docker build --file ${{ env.DOCKERFILE_FRPC_PATH }} --tag ${{ env.TAG_FRPC }} .
|
||||
docker build --file ${{ env.DOCKERFILE_FRPS_PATH }} --tag ${{ env.TAG_FRPS }} .
|
||||
# for GPR
|
||||
docker build --file $DOCKERFILE_FRPC_PATH --tag $TAG_FRPC_GPR .
|
||||
docker build --file $DOCKERFILE_FRPS_PATH --tag $TAG_FRPS_GPR .
|
||||
docker build --file ${{ env.DOCKERFILE_FRPC_PATH }} --tag ${{ env.TAG_FRPC_GPR }} .
|
||||
docker build --file ${{ env.DOCKERFILE_FRPS_PATH }} --tag ${{ env.TAG_FRPS_GPR }} .
|
||||
# push to dockerhub
|
||||
-
|
||||
name: Publish to Dockerhub
|
||||
run: |
|
||||
echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login --username ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
|
||||
docker push $TAG_FRPC
|
||||
docker push $TAG_FRPS
|
||||
docker push ${{ env.TAG_FRPC }}
|
||||
docker push ${{ env.TAG_FRPS }}
|
||||
# push to gpr
|
||||
-
|
||||
name: Publish to GPR
|
||||
run: |
|
||||
echo ${{ secrets.GPR_TOKEN }} | docker login ghcr.io --username ${{ github.repository_owner }} --password-stdin
|
||||
docker push $TAG_FRPC_GPR
|
||||
docker push $TAG_FRPS_GPR
|
||||
docker push ${{ env.TAG_FRPC_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/
|
||||
test/bin/
|
||||
vendor/
|
||||
dist/
|
||||
|
||||
# Cache
|
||||
*.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 ./...
|
||||
|
||||
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:
|
||||
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
|
||||
|
||||
|
@@ -7,32 +7,29 @@ all: build
|
||||
build: 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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_darwin_amd64 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_freebsd_386 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_freebsd_amd64 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_386 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_amd64 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_arm ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_arm64 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_windows_386.exe ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_windows_amd64.exe ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips64 ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips64le ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mips ./cmd/frps
|
||||
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 -trimpath -ldflags "$(LDFLAGS)" -o ./release/frps_linux_mipsle ./cmd/frps
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# frp
|
||||
|
||||
[](https://travis-ci.org/fatedier/frp)
|
||||
[](https://circleci.com/gh/fatedier/frp)
|
||||
[](https://github.com/fatedier/frp/releases)
|
||||
|
||||
[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 (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -222,8 +222,10 @@ func (ctl *Control) connectServer() (conn net.Conn, err error) {
|
||||
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 {
|
||||
xl.Warn("start new connection to server error: %v", err)
|
||||
return
|
||||
@@ -295,7 +297,7 @@ func (ctl *Control) msgHandler() {
|
||||
}()
|
||||
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()
|
||||
hbCheck := time.NewTicker(time.Second)
|
||||
defer hbCheck.Stop()
|
||||
@@ -314,7 +316,7 @@ func (ctl *Control) msgHandler() {
|
||||
}
|
||||
ctl.sendCh <- pingMsg
|
||||
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")
|
||||
// let reader() stop
|
||||
ctl.conn.Close()
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -215,8 +216,9 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@@ -157,17 +157,16 @@ func parseClientCommonCfgFromIni(content string) (config.ClientCommonConf, error
|
||||
func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
|
||||
cfg = config.GetDefaultClientConf()
|
||||
|
||||
strs := strings.Split(serverAddr, ":")
|
||||
if len(strs) < 2 {
|
||||
err = fmt.Errorf("invalid server_addr")
|
||||
ipStr, portStr, err := net.SplitHostPort(serverAddr)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid server_addr: %v", err)
|
||||
return
|
||||
}
|
||||
if strs[0] != "" {
|
||||
cfg.ServerAddr = strs[0]
|
||||
}
|
||||
cfg.ServerPort, err = strconv.Atoi(strs[1])
|
||||
|
||||
cfg.ServerAddr = ipStr
|
||||
cfg.ServerPort, err = strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid server_addr")
|
||||
err = fmt.Errorf("invalid server_addr: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -49,6 +49,7 @@ var (
|
||||
dashboardPort int
|
||||
dashboardUser string
|
||||
dashboardPwd string
|
||||
enablePrometheus bool
|
||||
assetsDir string
|
||||
logFile string
|
||||
logLevel string
|
||||
@@ -79,6 +80,7 @@ func init() {
|
||||
rootCmd.PersistentFlags().IntVarP(&dashboardPort, "dashboard_port", "", 0, "dashboard port")
|
||||
rootCmd.PersistentFlags().StringVarP(&dashboardUser, "dashboard_user", "", "admin", "dashboard user")
|
||||
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(&logLevel, "log_level", "", "info", "log level")
|
||||
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days")
|
||||
@@ -103,6 +105,7 @@ var rootCmd = &cobra.Command{
|
||||
var cfg config.ServerCommonConf
|
||||
var err error
|
||||
if cfgFile != "" {
|
||||
log.Info("frps uses config file: %s", cfgFile)
|
||||
var content string
|
||||
content, err = config.GetRenderedConfFromFile(cfgFile)
|
||||
if err != nil {
|
||||
@@ -110,6 +113,7 @@ var rootCmd = &cobra.Command{
|
||||
}
|
||||
cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
|
||||
} else {
|
||||
log.Info("frps uses command line arguments for config")
|
||||
cfg, err = parseServerCommonCfg(CfgFileTypeCmd, "")
|
||||
}
|
||||
if err != nil {
|
||||
@@ -171,6 +175,7 @@ func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
|
||||
cfg.DashboardPort = dashboardPort
|
||||
cfg.DashboardUser = dashboardUser
|
||||
cfg.DashboardPwd = dashboardPwd
|
||||
cfg.EnablePrometheus = enablePrometheus
|
||||
cfg.LogFile = logFile
|
||||
cfg.LogLevel = logLevel
|
||||
cfg.LogMaxDays = logMaxDays
|
||||
@@ -209,7 +214,7 @@ func runServer(cfg config.ServerCommonConf) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("start frps success")
|
||||
log.Info("frps started successfully")
|
||||
svr.Run()
|
||||
return
|
||||
}
|
||||
|
@@ -23,15 +23,30 @@ log_max_days = 3
|
||||
disable_log_color = false
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# auth token
|
||||
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
|
||||
admin_addr = 127.0.0.1
|
||||
admin_port = 7400
|
||||
|
@@ -23,7 +23,7 @@ vhost_https_port = 443
|
||||
# response header timeout(seconds) for vhost http server, default is 60s
|
||||
# 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
|
||||
# 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.
|
||||
@@ -44,6 +44,7 @@ enable_prometheus = true
|
||||
|
||||
# dashboard assets directory(only for debug mode)
|
||||
# assets_dir = ./static
|
||||
|
||||
# console or real logFile path like ./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.
|
||||
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 "oidc" is specified - OIDC (Open ID Connect) token will be issued using OIDC settings. By default, this value is "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
|
||||
|
||||
# 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
|
||||
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 "".
|
||||
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 "".
|
||||
oidc_client_secret =
|
||||
oidc_audience =
|
||||
|
||||
# OidcAudience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
|
||||
oidc_audience =
|
||||
# oidc_skip_expiry_check specifies whether to skip checking if the OIDC token is expired.
|
||||
# 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_token_endpoint_url =
|
||||
|
||||
# oidc_skip_issuer_check specifies whether to skip checking if the OIDC token's issuer claim matches the issuer specified in OidcIssuer.
|
||||
# By default, this value is false.
|
||||
oidc_skip_issuer_check = false
|
||||
|
||||
# heartbeat configure, it's not recommended to modify the default value
|
||||
# the default value of heartbeat_timeout is 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
|
||||
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_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_cert_file = server.crt
|
||||
|
@@ -209,9 +209,10 @@ path = /handler
|
||||
ops = NewProxy
|
||||
```
|
||||
|
||||
addr: the address where the external RPC service listens on.
|
||||
path: http request url path for the POST request.
|
||||
ops: operations plugin needs to handle (e.g. "Login", "NewProxy", ...).
|
||||
- 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.
|
||||
- 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
|
||||
|
||||
|
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/fatedier/frp
|
||||
|
||||
go 1.12
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
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
|
||||
// server, in seconds. It is not recommended to change this value. By
|
||||
// default, this value is 30.
|
||||
HeartBeatInterval int64 `json:"heartbeat_interval"`
|
||||
HeartbeatInterval int64 `json:"heartbeat_interval"`
|
||||
// HeartBeatTimeout specifies the maximum allowed heartbeat response delay
|
||||
// before the connection is terminated, in seconds. It is not recommended
|
||||
// to change this value. By default, this value is 90.
|
||||
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
|
||||
HeartbeatTimeout int64 `json:"heartbeat_timeout"`
|
||||
// Client meta info
|
||||
Metas map[string]string `json:"metas"`
|
||||
// UDPPacketSize specifies the udp packet size
|
||||
@@ -160,8 +160,8 @@ func GetDefaultClientConf() ClientCommonConf {
|
||||
TLSCertFile: "",
|
||||
TLSKeyFile: "",
|
||||
TLSTrustedCaFile: "",
|
||||
HeartBeatInterval: 30,
|
||||
HeartBeatTimeout: 90,
|
||||
HeartbeatInterval: 30,
|
||||
HeartbeatTimeout: 90,
|
||||
Metas: make(map[string]string),
|
||||
UDPPacketSize: 1500,
|
||||
}
|
||||
@@ -312,7 +312,7 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
|
||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout")
|
||||
return
|
||||
}
|
||||
cfg.HeartBeatTimeout = v
|
||||
cfg.HeartbeatTimeout = v
|
||||
}
|
||||
|
||||
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")
|
||||
return
|
||||
}
|
||||
cfg.HeartBeatInterval = v
|
||||
cfg.HeartbeatInterval = v
|
||||
}
|
||||
for k, v := range conf.Section("common") {
|
||||
if strings.HasPrefix(k, "meta_") {
|
||||
@@ -338,12 +338,12 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, 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")
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ type ServerCommonConf struct {
|
||||
// AssetsDir specifies the local directory that the dashboard will load
|
||||
// resources from. If this value is "", assets will be loaded from the
|
||||
// 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
|
||||
// only be used if LogWay is set appropriately. By default, this value is
|
||||
// "console".
|
||||
@@ -154,7 +154,7 @@ type ServerCommonConf struct {
|
||||
// HeartBeatTimeout specifies the maximum time to wait for a heartbeat
|
||||
// before terminating the connection. It is not recommended to change this
|
||||
// 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
|
||||
// connection. By default, this value is 10.
|
||||
UserConnTimeout int64 `json:"user_conn_timeout"`
|
||||
@@ -199,7 +199,7 @@ func GetDefaultServerConf() ServerCommonConf {
|
||||
TLSCertFile: "",
|
||||
TLSKeyFile: "",
|
||||
TLSTrustedCaFile: "",
|
||||
HeartBeatTimeout: 90,
|
||||
HeartbeatTimeout: 90,
|
||||
UserConnTimeout: 10,
|
||||
Custom404Page: "",
|
||||
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")
|
||||
return
|
||||
}
|
||||
cfg.HeartBeatTimeout = v
|
||||
cfg.HeartbeatTimeout = v
|
||||
}
|
||||
|
||||
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 {
|
||||
if strings.HasPrefix(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{
|
||||
Name: name,
|
||||
Addr: section["addr"],
|
||||
Path: section["path"],
|
||||
Ops: strings.Split(section["ops"], ","),
|
||||
Name: name,
|
||||
Addr: section["addr"],
|
||||
Path: section["path"],
|
||||
Ops: strings.Split(section["ops"], ","),
|
||||
TLSVerify: tls_verify,
|
||||
}
|
||||
for i := range options.Ops {
|
||||
options.Ops[i] = strings.TrimSpace(options.Ops[i])
|
||||
|
@@ -17,19 +17,22 @@ package plugin
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HTTPPluginOptions struct {
|
||||
Name string
|
||||
Addr string
|
||||
Path string
|
||||
Ops []string
|
||||
Name string
|
||||
Addr string
|
||||
Path string
|
||||
Ops []string
|
||||
TLSVerify bool
|
||||
}
|
||||
|
||||
type httpPlugin struct {
|
||||
@@ -40,10 +43,25 @@ type httpPlugin struct {
|
||||
}
|
||||
|
||||
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{
|
||||
options: options,
|
||||
url: fmt.Sprintf("http://%s%s", options.Addr, options.Path),
|
||||
client: &http.Client{},
|
||||
url: url,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
@@ -33,6 +34,7 @@ func OkResponse() *http.Response {
|
||||
return res
|
||||
}
|
||||
|
||||
// TODO: use "CanonicalHost" func to replace all "GetHostFromAddr" func.
|
||||
func GetHostFromAddr(addr string) (host string) {
|
||||
strs := strings.Split(addr, ":")
|
||||
if len(strs) > 1 {
|
||||
@@ -42,3 +44,34 @@ func GetHostFromAddr(addr string) (host string) {
|
||||
}
|
||||
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"
|
||||
)
|
||||
|
||||
var version string = "0.34.2"
|
||||
var version string = "0.35.1"
|
||||
|
||||
func Full() string {
|
||||
return version
|
||||
|
@@ -17,6 +17,7 @@ package vhost
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -59,20 +60,25 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
||||
req.URL.Scheme = "http"
|
||||
url := req.Context().Value(RouteInfoURL).(string)
|
||||
oldHost := util.GetHostFromAddr(req.Context().Value(RouteInfoHost).(string))
|
||||
host := rp.GetRealHost(oldHost, url)
|
||||
if host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
req.URL.Host = req.Host
|
||||
rc := rp.GetRouteConfig(oldHost, url)
|
||||
if rc != nil {
|
||||
if rc.RewriteHost != "" {
|
||||
req.Host = rc.RewriteHost
|
||||
}
|
||||
// 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 headers {
|
||||
req.Header.Set(k, v)
|
||||
for k, v := range rc.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
} else {
|
||||
req.URL.Host = req.Host
|
||||
}
|
||||
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
ResponseHeaderTimeout: rp.responseHeaderTimeout,
|
||||
DisableKeepAlives: true,
|
||||
IdleConnTimeout: 60 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
url := ctx.Value(RouteInfoURL).(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)
|
||||
}
|
||||
|
||||
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) {
|
||||
vr, ok := rp.getVhost(domain, location)
|
||||
if ok {
|
||||
|
@@ -144,7 +144,7 @@ func (v *Muxer) handle(c net.Conn) {
|
||||
|
||||
sConn, reqInfoMap, err := v.vhostFunc(c)
|
||||
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()
|
||||
return
|
||||
}
|
||||
|
@@ -408,7 +408,7 @@ func (ctl *Control) manager() {
|
||||
for {
|
||||
select {
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
@@ -74,7 +74,7 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||
SubdomainHost: svr.cfg.SubDomainHost,
|
||||
MaxPoolCount: svr.cfg.MaxPoolCount,
|
||||
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
|
||||
HeartBeatTimeout: svr.cfg.HeartBeatTimeout,
|
||||
HeartBeatTimeout: svr.cfg.HeartbeatTimeout,
|
||||
|
||||
TotalTrafficIn: serverStats.TotalTrafficIn,
|
||||
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)
|
||||
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())
|
||||
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")
|
||||
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)
|
||||
}
|
||||
}(listener)
|
||||
|
@@ -139,6 +139,7 @@ func TestHealthCheck(t *testing.T) {
|
||||
}
|
||||
|
||||
httpSvc3 := mock.NewHTTPServer(15005, func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(time.Second)
|
||||
w.Write([]byte("http3"))
|
||||
})
|
||||
err = httpSvc3.Start()
|
||||
@@ -147,6 +148,7 @@ func TestHealthCheck(t *testing.T) {
|
||||
}
|
||||
|
||||
httpSvc4 := mock.NewHTTPServer(15006, func(w http.ResponseWriter, r *http.Request) {
|
||||
time.Sleep(time.Second)
|
||||
w.Write([]byte("http4"))
|
||||
})
|
||||
err = httpSvc4.Start()
|
||||
@@ -277,16 +279,30 @@ func TestHealthCheck(t *testing.T) {
|
||||
|
||||
// ****** load balancing type http ******
|
||||
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, "")
|
||||
assert.NoError(err)
|
||||
assert.Equal(200, code)
|
||||
result = append(result, body)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
||||
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, "")
|
||||
assert.NoError(err)
|
||||
assert.Equal(200, code)
|
||||
result = append(result, body)
|
||||
go func() {
|
||||
defer wait.Done()
|
||||
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
||||
assert.NoError(err)
|
||||
assert.Equal(200, code)
|
||||
mu.Lock()
|
||||
result = append(result, body)
|
||||
mu.Unlock()
|
||||
}()
|
||||
wait.Wait()
|
||||
|
||||
assert.Contains(result, "http3")
|
||||
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>
|
||||
</header>
|
||||
<section>
|
||||
<el-row :gutter="20">
|
||||
<el-row>
|
||||
<el-col id="side-nav" :xs="24" :md="4">
|
||||
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect">
|
||||
<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