From ad3548d3322c007773d495436dfa7abadae8aac4 Mon Sep 17 00:00:00 2001 From: bobo liu <7552030+fakeboboliu@users.noreply.github.com> Date: Sat, 14 Jan 2023 21:43:26 +0800 Subject: [PATCH 01/13] optimize: GetAuthKey (#3254) --- pkg/util/util/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/util/util/util.go b/pkg/util/util/util.go index b13f9a7..b72209c 100644 --- a/pkg/util/util/util.go +++ b/pkg/util/util/util.go @@ -44,9 +44,9 @@ func RandIDWithLen(idLen int) (id string, err error) { } func GetAuthKey(token string, timestamp int64) (key string) { - token += fmt.Sprintf("%d", timestamp) md5Ctx := md5.New() md5Ctx.Write([]byte(token)) + md5Ctx.Write([]byte(strconv.FormatInt(timestamp, 10))) data := md5Ctx.Sum(nil) return hex.EncodeToString(data) } From 0eecab06c17d69ba11a84162aae35ed7d94f0423 Mon Sep 17 00:00:00 2001 From: Richard Kovacs Date: Sun, 15 Jan 2023 12:15:48 +0100 Subject: [PATCH 02/13] Fix basic example server to join in readme (#3209) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57a6894..a02d0a5 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ Note that `local_port` (listened on client) and `remote_port` (exposed on server `./frpc -c ./frpc.ini` -5. From another machine, SSH to server B like this (assuming that username is `test`): +5. From another machine, SSH to server B via server A like this (assuming that username is `test`): `ssh -oPort=6000 test@x.x.x.x` From d205c264807b49f773f37a1efeeea86f39637e99 Mon Sep 17 00:00:00 2001 From: Gerhard Tan Date: Sun, 29 Jan 2023 23:54:40 +0800 Subject: [PATCH 03/13] Bugfix: add ipv6 parsing for custom DNS server (#3266) --- client/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/service.go b/client/service.go index b72fea7..99201f0 100644 --- a/client/service.go +++ b/client/service.go @@ -114,8 +114,8 @@ func (svr *Service) Run() error { // set custom DNSServer if svr.cfg.DNSServer != "" { dnsAddr := svr.cfg.DNSServer - if !strings.Contains(dnsAddr, ":") { - dnsAddr += ":53" + if _, _, err := net.SplitHostPort(dnsAddr); err != nil { + dnsAddr = net.JoinHostPort(dnsAddr, "53") } // Change default dns server for frpc net.DefaultResolver = &net.Resolver{ From 24c7d1d9e2efeaa5b72159d9fc2127e3a7d751dc Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 1 Feb 2023 11:19:31 +0800 Subject: [PATCH 04/13] clean Release.md --- Release.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Release.md b/Release.md index 6738c32..e69de29 100644 --- a/Release.md +++ b/Release.md @@ -1,4 +0,0 @@ -### Fix - -* Server Plugin send incorrect op name for NewWorkConn. -* QUIC stream leak. From b1b8d9a82b7c4e0b0b999ec173e1038533fe88eb Mon Sep 17 00:00:00 2001 From: Gerhard Tan Date: Wed, 1 Feb 2023 13:09:31 +0800 Subject: [PATCH 05/13] frpc: do a graceful close for quic protocol at exit (#3282) --- cmd/frpc/sub/root.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd/frpc/sub/root.go b/cmd/frpc/sub/root.go index cea8ecc..19206c6 100644 --- a/cmd/frpc/sub/root.go +++ b/cmd/frpc/sub/root.go @@ -216,15 +216,16 @@ func startService( return } - kcpDoneCh := make(chan struct{}) - // Capture the exit signal if we use kcp. - if cfg.Protocol == "kcp" { - go handleSignal(svr, kcpDoneCh) + closedDoneCh := make(chan struct{}) + shouldGracefulClose := cfg.Protocol == "kcp" || cfg.Protocol == "quic" + // Capture the exit signal if we use kcp or quic. + if shouldGracefulClose { + go handleSignal(svr, closedDoneCh) } err = svr.Run() - if err == nil && cfg.Protocol == "kcp" { - <-kcpDoneCh + if err == nil && shouldGracefulClose { + <-closedDoneCh } return } From 5e17bc7bf173e15e70a51d90b240736b01fa1c17 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 2 Feb 2023 12:03:20 +0800 Subject: [PATCH 06/13] remove sponsors --- README.md | 4 ---- README_zh.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/README.md b/README.md index a02d0a5..ff22141 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,6 @@ -

Silver Sponsors

- -* Sakura Frp - 欢迎点击 "加入我们" - ## What is frp? frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it supports **TCP** and **UDP**, as well as **HTTP** and **HTTPS** protocols, where requests can be forwarded to internal services by domain name. diff --git a/README_zh.md b/README_zh.md index e0612bb..1cc7b4e 100644 --- a/README_zh.md +++ b/README_zh.md @@ -18,10 +18,6 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP -

Silver Sponsors

- -* Sakura Frp - 欢迎点击 "加入我们" - ## 为什么使用 frp ? 通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括: From 6b3daffaf09bd5fecc55d5a0fdf6b1b91624a71c Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 2 Feb 2023 20:20:17 +0800 Subject: [PATCH 07/13] upgrade quic-go and change import path (#3286) --- client/service.go | 2 +- go.mod | 13 +++++++------ go.sum | 26 ++++++++++++++------------ pkg/util/net/conn.go | 2 +- server/service.go | 2 +- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/client/service.go b/client/service.go index 99201f0..c8d92c6 100644 --- a/client/service.go +++ b/client/service.go @@ -31,7 +31,7 @@ import ( "github.com/fatedier/golib/crypto" libdial "github.com/fatedier/golib/net/dial" fmux "github.com/hashicorp/yamux" - quic "github.com/lucas-clemente/quic-go" + quic "github.com/quic-go/quic-go" "github.com/fatedier/frp/assets" "github.com/fatedier/frp/pkg/auth" diff --git a/go.mod b/go.mod index d518a61..386aedb 100644 --- a/go.mod +++ b/go.mod @@ -13,11 +13,11 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/yamux v0.1.1 - github.com/lucas-clemente/quic-go v0.31.0 github.com/onsi/ginkgo v1.16.4 github.com/onsi/gomega v1.20.2 github.com/pires/go-proxyproto v0.6.2 github.com/prometheus/client_golang v1.13.0 + github.com/quic-go/quic-go v0.32.0 github.com/rodaine/table v1.0.1 github.com/spf13/cobra v1.1.3 github.com/stretchr/testify v1.7.0 @@ -47,8 +47,6 @@ require ( github.com/klauspost/cpuid/v2 v2.0.6 // indirect github.com/klauspost/reedsolomon v1.9.15 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect @@ -57,16 +55,19 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect + github.com/quic-go/qtls-go1-18 v0.2.0 // indirect + github.com/quic-go/qtls-go1-19 v0.2.0 // indirect + github.com/quic-go/qtls-go1-20 v0.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect github.com/tjfoc/gmsm v1.4.1 // indirect golang.org/x/crypto v0.4.0 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/sys v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/tools v0.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect diff --git a/go.sum b/go.sum index 3471287..521f06b 100644 --- a/go.sum +++ b/go.sum @@ -307,13 +307,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/lucas-clemente/quic-go v0.31.0 h1:MfNp3fk0wjWRajw6quMFA3ap1AVtlU+2mtwmbVogB2M= -github.com/lucas-clemente/quic-go v0.31.0/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI= -github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE= -github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= @@ -392,6 +386,14 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= +github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= +github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk= +github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= +github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA= +github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo= github.com/rodaine/table v1.0.1 h1:U/VwCnUxlVYxw8+NJiLIuCxA/xa6jL38MY3FYysVWWQ= github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -478,8 +480,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -505,8 +507,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -748,8 +750,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/util/net/conn.go b/pkg/util/net/conn.go index a09da99..fb2ff67 100644 --- a/pkg/util/net/conn.go +++ b/pkg/util/net/conn.go @@ -22,7 +22,7 @@ import ( "sync/atomic" "time" - quic "github.com/lucas-clemente/quic-go" + quic "github.com/quic-go/quic-go" "github.com/fatedier/frp/pkg/util/xlog" ) diff --git a/server/service.go b/server/service.go index fc59b39..e2f8494 100644 --- a/server/service.go +++ b/server/service.go @@ -28,7 +28,7 @@ import ( "github.com/fatedier/golib/net/mux" fmux "github.com/hashicorp/yamux" - quic "github.com/lucas-clemente/quic-go" + quic "github.com/quic-go/quic-go" "github.com/fatedier/frp/assets" "github.com/fatedier/frp/pkg/auth" From 100148d9254c4be710d171788a764435f4fc301b Mon Sep 17 00:00:00 2001 From: fatedier Date: Sun, 5 Feb 2023 20:52:36 +0800 Subject: [PATCH 08/13] support go1.20 (#3287) --- .circleci/config.yml | 4 ++-- .github/workflows/golangci-lint.yml | 4 ++-- .github/workflows/goreleaser.yml | 2 +- .golangci.yml | 8 ++++++-- client/service.go | 2 -- cmd/frps/main.go | 4 ---- dockerfiles/Dockerfile-for-frpc | 2 +- dockerfiles/Dockerfile-for-frps | 2 +- go.mod | 2 +- 9 files changed, 14 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7499579..b8dca0e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: go-version-latest: docker: - - image: cimg/go:1.19-node + - image: cimg/go:1.20-node resource_class: large steps: - checkout @@ -10,7 +10,7 @@ jobs: - run: make alltest go-version-last: docker: - - image: cimg/go:1.18-node + - image: cimg/go:1.19-node resource_class: large steps: - checkout diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index c9051f3..0aa1c5d 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -16,13 +16,13 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.49.0 + version: v1.51 # Optional: golangci-lint command line arguments. # args: --issues-exit-code=0 diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index d0234d5..484167a 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: '1.20' - name: Make All run: | diff --git a/.golangci.yml b/.golangci.yml index 39c8e3f..0fe5d72 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,5 @@ service: - # When updating this, also update the version stored in docker/build-tools/Dockerfile in the istio/tools repo. - golangci-lint-version: 1.49.x # use the fixed version to not introduce new linters unexpectedly + golangci-lint-version: 1.51.x # use the fixed version to not introduce new linters unexpectedly run: concurrency: 4 @@ -127,6 +126,11 @@ issues: - errcheck - maligned + # keep it until we only support go1.20 + - linters: + - staticcheck + text: "SA1019: rand.Seed has been deprecated" + # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all # excluded by default patterns execute `golangci-lint run --help`. diff --git a/client/service.go b/client/service.go index c8d92c6..90d5b3a 100644 --- a/client/service.go +++ b/client/service.go @@ -19,7 +19,6 @@ import ( "crypto/tls" "fmt" "io" - "math/rand" "net" "runtime" "strconv" @@ -47,7 +46,6 @@ import ( func init() { crypto.DefaultSalt = "frp" - rand.Seed(time.Now().UnixNano()) } // Service is a client service. diff --git a/cmd/frps/main.go b/cmd/frps/main.go index 56477aa..a7c1e9b 100644 --- a/cmd/frps/main.go +++ b/cmd/frps/main.go @@ -15,9 +15,6 @@ package main import ( - "math/rand" - "time" - "github.com/fatedier/golib/crypto" _ "github.com/fatedier/frp/assets/frps" @@ -26,7 +23,6 @@ import ( func main() { crypto.DefaultSalt = "frp" - rand.Seed(time.Now().UnixNano()) Execute() } diff --git a/dockerfiles/Dockerfile-for-frpc b/dockerfiles/Dockerfile-for-frpc index b749be0..96a3d8b 100644 --- a/dockerfiles/Dockerfile-for-frpc +++ b/dockerfiles/Dockerfile-for-frpc @@ -1,4 +1,4 @@ -FROM golang:1.19 AS building +FROM golang:1.20 AS building COPY . /building WORKDIR /building diff --git a/dockerfiles/Dockerfile-for-frps b/dockerfiles/Dockerfile-for-frps index cd71612..12d5201 100644 --- a/dockerfiles/Dockerfile-for-frps +++ b/dockerfiles/Dockerfile-for-frps @@ -1,4 +1,4 @@ -FROM golang:1.19 AS building +FROM golang:1.20 AS building COPY . /building WORKDIR /building diff --git a/go.mod b/go.mod index 386aedb..dd63184 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/fatedier/frp -go 1.19 +go 1.20 require ( github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 From 113e3b0b0d823724fdeca97d7d293b459de98cdc Mon Sep 17 00:00:00 2001 From: fatedier Date: Mon, 6 Feb 2023 15:55:33 +0800 Subject: [PATCH 09/13] revert random change (#3292) --- client/service.go | 3 +++ cmd/frps/main.go | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/client/service.go b/client/service.go index 90d5b3a..bac5716 100644 --- a/client/service.go +++ b/client/service.go @@ -19,6 +19,7 @@ import ( "crypto/tls" "fmt" "io" + "math/rand" "net" "runtime" "strconv" @@ -46,6 +47,8 @@ import ( func init() { crypto.DefaultSalt = "frp" + // TODO: remove this when we drop support for go1.19 + rand.Seed(time.Now().UnixNano()) } // Service is a client service. diff --git a/cmd/frps/main.go b/cmd/frps/main.go index a7c1e9b..6ae5378 100644 --- a/cmd/frps/main.go +++ b/cmd/frps/main.go @@ -15,6 +15,9 @@ package main import ( + "math/rand" + "time" + "github.com/fatedier/golib/crypto" _ "github.com/fatedier/frp/assets/frps" @@ -23,6 +26,8 @@ import ( func main() { crypto.DefaultSalt = "frp" + // TODO: remove this when we drop support for go1.19 + rand.Seed(time.Now().UnixNano()) Execute() } From aa31d7ad0bdcc05ee0a4add6cfd0eacf04c241c5 Mon Sep 17 00:00:00 2001 From: Craig O'Donnell Date: Wed, 8 Feb 2023 11:38:36 -0500 Subject: [PATCH 10/13] support bandwidth_limit set by server plugin (#3271) * support bandwidth_limit set by server plugin * limiter at proxy level * bandwidth_limit_mode * updates tests for bandwidth_limit_mode default * bandwidth_limit_mode as string * add checkForSrv for bandwidth_limit_mode * bandwidth_limit flags for sub cmds * gci write --- README.md | 3 +++ client/proxy/proxy.go | 2 +- cmd/frpc/sub/http.go | 8 +++++++ cmd/frpc/sub/https.go | 8 +++++++ cmd/frpc/sub/root.go | 38 ++++++++++++++++--------------- cmd/frpc/sub/stcp.go | 8 +++++++ cmd/frpc/sub/sudp.go | 8 +++++++ cmd/frpc/sub/tcp.go | 8 +++++++ cmd/frpc/sub/tcpmux.go | 8 +++++++ cmd/frpc/sub/udp.go | 8 +++++++ cmd/frpc/sub/xtcp.go | 8 +++++++ conf/frpc_full.ini | 2 ++ doc/server_plugin.md | 2 ++ pkg/config/client_test.go | 35 ++++++++++++++++++++++------ pkg/config/proxy.go | 48 +++++++++++++++++++++++++++++++++++++++ pkg/config/proxy_test.go | 29 +++++++++++++++++------ pkg/config/types.go | 3 +++ pkg/msg/msg.go | 20 +++++++++------- server/proxy/http.go | 13 +++++++++++ server/proxy/https.go | 6 +++++ server/proxy/proxy.go | 19 ++++++++++++++++ server/proxy/stcp.go | 6 +++++ server/proxy/sudp.go | 6 +++++ server/proxy/tcp.go | 6 +++++ server/proxy/tcpmux.go | 6 +++++ server/proxy/udp.go | 12 ++++++++++ server/proxy/xtcp.go | 5 ++++ 27 files changed, 284 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index ff22141..73e48c7 100644 --- a/README.md +++ b/README.md @@ -713,10 +713,13 @@ type = tcp local_port = 22 remote_port = 6000 bandwidth_limit = 1MB +bandwidth_limit_mode = client ``` Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`. +Set `bandwidth_limit_mode` to `client` or `server` to limit bandwidth on the client or server side. Default is `client`. + ### TCP Stream Multiplexing frp supports tcp stream multiplexing since v0.10.0 like HTTP2 Multiplexing, in which case all logic connections to the same frpc are multiplexed into the same TCP connection. diff --git a/client/proxy/proxy.go b/client/proxy/proxy.go index 158773b..98a8a67 100644 --- a/client/proxy/proxy.go +++ b/client/proxy/proxy.go @@ -54,7 +54,7 @@ type Proxy interface { func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) { var limiter *rate.Limiter limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() - if limitBytes > 0 { + if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeClient { limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes)) } diff --git a/cmd/frpc/sub/http.go b/cmd/frpc/sub/http.go index 4e193b7..22eeefe 100644 --- a/cmd/frpc/sub/http.go +++ b/cmd/frpc/sub/http.go @@ -39,6 +39,8 @@ func init() { httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite") httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") httpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + httpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + httpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(httpCmd) } @@ -70,6 +72,12 @@ var httpCmd = &cobra.Command{ cfg.HostHeaderRewrite = hostHeaderRewrite cfg.UseEncryption = useEncryption cfg.UseCompression = useCompression + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { diff --git a/cmd/frpc/sub/https.go b/cmd/frpc/sub/https.go index 8a14d39..187aa99 100644 --- a/cmd/frpc/sub/https.go +++ b/cmd/frpc/sub/https.go @@ -35,6 +35,8 @@ func init() { httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain") httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") httpsCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + httpsCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + httpsCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(httpsCmd) } @@ -62,6 +64,12 @@ var httpsCmd = &cobra.Command{ cfg.SubDomain = subDomain cfg.UseEncryption = useEncryption cfg.UseCompression = useCompression + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { diff --git a/cmd/frpc/sub/root.go b/cmd/frpc/sub/root.go index 19206c6..cd39d88 100644 --- a/cmd/frpc/sub/root.go +++ b/cmd/frpc/sub/root.go @@ -54,24 +54,26 @@ var ( logMaxDays int disableLogColor bool - proxyName string - localIP string - localPort int - remotePort int - useEncryption bool - useCompression bool - customDomains string - subDomain string - httpUser string - httpPwd string - locations string - hostHeaderRewrite string - role string - sk string - multiplexer string - serverName string - bindAddr string - bindPort int + proxyName string + localIP string + localPort int + remotePort int + useEncryption bool + useCompression bool + bandwidthLimit string + bandwidthLimitMode string + customDomains string + subDomain string + httpUser string + httpPwd string + locations string + hostHeaderRewrite string + role string + sk string + multiplexer string + serverName string + bindAddr string + bindPort int tlsEnable bool ) diff --git a/cmd/frpc/sub/stcp.go b/cmd/frpc/sub/stcp.go index d84b23b..ad0a57c 100644 --- a/cmd/frpc/sub/stcp.go +++ b/cmd/frpc/sub/stcp.go @@ -37,6 +37,8 @@ func init() { stcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") stcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + stcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + stcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(stcpCmd) } @@ -70,6 +72,12 @@ var stcpCmd = &cobra.Command{ cfg.Sk = sk cfg.LocalIP = localIP cfg.LocalPort = localPort + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { fmt.Println(err) diff --git a/cmd/frpc/sub/sudp.go b/cmd/frpc/sub/sudp.go index f96a12e..0ae8498 100644 --- a/cmd/frpc/sub/sudp.go +++ b/cmd/frpc/sub/sudp.go @@ -37,6 +37,8 @@ func init() { sudpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") sudpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") sudpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + sudpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + sudpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(sudpCmd) } @@ -70,6 +72,12 @@ var sudpCmd = &cobra.Command{ cfg.Sk = sk cfg.LocalIP = localIP cfg.LocalPort = localPort + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { fmt.Println(err) diff --git a/cmd/frpc/sub/tcp.go b/cmd/frpc/sub/tcp.go index 7e86734..2c597f1 100644 --- a/cmd/frpc/sub/tcp.go +++ b/cmd/frpc/sub/tcp.go @@ -33,6 +33,8 @@ func init() { tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port") tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") tcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + tcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + tcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(tcpCmd) } @@ -59,6 +61,12 @@ var tcpCmd = &cobra.Command{ cfg.RemotePort = remotePort cfg.UseEncryption = useEncryption cfg.UseCompression = useCompression + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { diff --git a/cmd/frpc/sub/tcpmux.go b/cmd/frpc/sub/tcpmux.go index cef845d..ecdd600 100644 --- a/cmd/frpc/sub/tcpmux.go +++ b/cmd/frpc/sub/tcpmux.go @@ -36,6 +36,8 @@ func init() { tcpMuxCmd.PersistentFlags().StringVarP(&multiplexer, "mux", "", "", "multiplexer") tcpMuxCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") tcpMuxCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + tcpMuxCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + tcpMuxCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(tcpMuxCmd) } @@ -64,6 +66,12 @@ var tcpMuxCmd = &cobra.Command{ cfg.Multiplexer = multiplexer cfg.UseEncryption = useEncryption cfg.UseCompression = useCompression + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { diff --git a/cmd/frpc/sub/udp.go b/cmd/frpc/sub/udp.go index 984ad06..f9dfa3f 100644 --- a/cmd/frpc/sub/udp.go +++ b/cmd/frpc/sub/udp.go @@ -33,6 +33,8 @@ func init() { udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port") udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") udpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + udpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + udpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(udpCmd) } @@ -59,6 +61,12 @@ var udpCmd = &cobra.Command{ cfg.RemotePort = remotePort cfg.UseEncryption = useEncryption cfg.UseCompression = useCompression + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { diff --git a/cmd/frpc/sub/xtcp.go b/cmd/frpc/sub/xtcp.go index b842698..ea201d5 100644 --- a/cmd/frpc/sub/xtcp.go +++ b/cmd/frpc/sub/xtcp.go @@ -37,6 +37,8 @@ func init() { xtcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") xtcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") + xtcpCmd.PersistentFlags().StringVarP(&bandwidthLimit, "bandwidth_limit", "", "", "bandwidth limit") + xtcpCmd.PersistentFlags().StringVarP(&bandwidthLimitMode, "bandwidth_limit_mode", "", config.BandwidthLimitModeClient, "bandwidth limit mode") rootCmd.AddCommand(xtcpCmd) } @@ -70,6 +72,12 @@ var xtcpCmd = &cobra.Command{ cfg.Sk = sk cfg.LocalIP = localIP cfg.LocalPort = localPort + cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + cfg.BandwidthLimitMode = bandwidthLimitMode err = cfg.CheckForCli() if err != nil { fmt.Println(err) diff --git a/conf/frpc_full.ini b/conf/frpc_full.ini index 8e39de1..29f6bca 100644 --- a/conf/frpc_full.ini +++ b/conf/frpc_full.ini @@ -154,6 +154,8 @@ local_ip = 127.0.0.1 local_port = 22 # limit bandwidth for this proxy, unit is KB and MB bandwidth_limit = 1MB +# where to limit bandwidth, can be 'client' or 'server', default is 'client' +bandwidth_limit_mode = client # true or false, if true, messages between frps and frpc will be encrypted, default is false use_encryption = false # if true, message will be compressed diff --git a/doc/server_plugin.md b/doc/server_plugin.md index d73d243..f4e377f 100644 --- a/doc/server_plugin.md +++ b/doc/server_plugin.md @@ -110,6 +110,8 @@ Create new proxy "proxy_type": , "use_encryption": , "use_compression": , + "bandwidth_limit": , + "bandwidth_limit_mode": , "group": , "group_key": , diff --git a/pkg/config/client_test.go b/pkg/config/client_test.go index 9cf8c80..79eef5f 100644 --- a/pkg/config/client_test.go +++ b/pkg/config/client_test.go @@ -74,6 +74,7 @@ var testClientBytesWithFull = []byte(` local_ip = 127.0.0.9 local_port = 29 bandwidth_limit = 19MB + bandwidth_limit_mode = server use_encryption use_compression remote_port = 6009 @@ -309,13 +310,14 @@ func Test_LoadClientBasicConf(t *testing.T) { proxyExpected := map[string]ProxyConf{ testUser + ".ssh": &TCPProxyConf{ BaseProxyConf: BaseProxyConf{ - ProxyName: testUser + ".ssh", - ProxyType: consts.TCPProxy, - UseCompression: true, - UseEncryption: true, - Group: "test_group", - GroupKey: "123456", - BandwidthLimit: MustBandwidthQuantity("19MB"), + ProxyName: testUser + ".ssh", + ProxyType: consts.TCPProxy, + UseCompression: true, + UseEncryption: true, + Group: "test_group", + GroupKey: "123456", + BandwidthLimit: MustBandwidthQuantity("19MB"), + BandwidthLimitMode: BandwidthLimitModeServer, Metas: map[string]string{ "var1": "123", "var2": "234", @@ -342,6 +344,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 29, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 9, }, @@ -353,6 +356,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 6010, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6010, }, @@ -364,6 +368,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 6011, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6011, }, @@ -375,6 +380,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 6019, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6019, }, @@ -388,6 +394,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 59, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6009, }, @@ -401,6 +408,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 6000, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6000, }, @@ -414,6 +422,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 6010, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6010, }, @@ -427,6 +436,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 6011, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6011, }, @@ -447,6 +457,7 @@ func Test_LoadClientBasicConf(t *testing.T) { HealthCheckIntervalS: 19, HealthCheckURL: "http://127.0.0.9:89/status", }, + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"web02.yourdomain.com"}, @@ -471,6 +482,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalPort: 8009, }, ProxyProtocolVersion: "v2", + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"web02.yourdomain.com"}, @@ -485,6 +497,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.1", LocalPort: 22, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, Role: "server", Sk: "abcdefg", @@ -497,6 +510,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.1", LocalPort: 22, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, Role: "server", Sk: "abcdefg", @@ -509,6 +523,7 @@ func Test_LoadClientBasicConf(t *testing.T) { LocalIP: "127.0.0.1", LocalPort: 10701, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"tunnel1"}, @@ -527,6 +542,7 @@ func Test_LoadClientBasicConf(t *testing.T) { "plugin_unix_path": "/var/run/docker.sock", }, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6003, }, @@ -542,6 +558,7 @@ func Test_LoadClientBasicConf(t *testing.T) { "plugin_http_passwd": "abc", }, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6004, }, @@ -557,6 +574,7 @@ func Test_LoadClientBasicConf(t *testing.T) { "plugin_passwd": "abc", }, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6005, }, @@ -574,6 +592,7 @@ func Test_LoadClientBasicConf(t *testing.T) { "plugin_http_passwd": "abc", }, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6006, }, @@ -592,6 +611,7 @@ func Test_LoadClientBasicConf(t *testing.T) { "plugin_header_X-From-Where": "frp", }, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"test.yourdomain.com"}, @@ -610,6 +630,7 @@ func Test_LoadClientBasicConf(t *testing.T) { "plugin_header_X-From-Where": "frp", }, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"test.yourdomain.com"}, diff --git a/pkg/config/proxy.go b/pkg/config/proxy.go index 92b499f..3419f48 100644 --- a/pkg/config/proxy.go +++ b/pkg/config/proxy.go @@ -141,6 +141,10 @@ type BaseProxyConf struct { // BandwidthLimit limit the bandwidth // 0 means no limit BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"` + // BandwidthLimitMode specifies whether to limit the bandwidth on the + // client or server side. Valid values include "client" and "server". + // By default, this value is "client". + BandwidthLimitMode string `ini:"bandwidth_limit_mode" json:"bandwidth_limit_mode"` // meta info for each proxy Metas map[string]string `ini:"-" json:"metas"` @@ -319,6 +323,7 @@ func defaultBaseProxyConf(proxyType string) BaseProxyConf { LocalSvrConf: LocalSvrConf{ LocalIP: "127.0.0.1", }, + BandwidthLimitMode: BandwidthLimitModeClient, } } @@ -335,6 +340,7 @@ func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool { cfg.GroupKey != cmp.GroupKey || cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion || !cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) || + cfg.BandwidthLimitMode != cmp.BandwidthLimitMode || !reflect.DeepEqual(cfg.Metas, cmp.Metas) { return false } @@ -389,6 +395,8 @@ func (cfg *BaseProxyConf) marshalToMsg(pMsg *msg.NewProxy) { pMsg.ProxyType = cfg.ProxyType pMsg.UseEncryption = cfg.UseEncryption pMsg.UseCompression = cfg.UseCompression + pMsg.BandwidthLimit = cfg.BandwidthLimit.String() + pMsg.BandwidthLimitMode = cfg.BandwidthLimitMode pMsg.Group = cfg.Group pMsg.GroupKey = cfg.GroupKey pMsg.Metas = cfg.Metas @@ -399,6 +407,8 @@ func (cfg *BaseProxyConf) unmarshalFromMsg(pMsg *msg.NewProxy) { cfg.ProxyType = pMsg.ProxyType cfg.UseEncryption = pMsg.UseEncryption cfg.UseCompression = pMsg.UseCompression + cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit) + cfg.BandwidthLimitMode = pMsg.BandwidthLimitMode cfg.Group = pMsg.Group cfg.GroupKey = pMsg.GroupKey cfg.Metas = pMsg.Metas @@ -411,6 +421,10 @@ func (cfg *BaseProxyConf) checkForCli() (err error) { } } + if cfg.BandwidthLimitMode != "client" && cfg.BandwidthLimitMode != "server" { + return fmt.Errorf("bandwidth_limit_mode should be client or server") + } + if err = cfg.LocalSvrConf.checkForCli(); err != nil { return } @@ -420,6 +434,13 @@ func (cfg *BaseProxyConf) checkForCli() (err error) { return nil } +func (cfg *BaseProxyConf) checkForSvr() (err error) { + if cfg.BandwidthLimitMode != "client" && cfg.BandwidthLimitMode != "server" { + return fmt.Errorf("bandwidth_limit_mode should be client or server") + } + return nil +} + // DomainConf func (cfg *DomainConf) check() (err error) { if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" { @@ -557,6 +578,9 @@ func (cfg *TCPProxyConf) CheckForCli() (err error) { } func (cfg *TCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } return nil } @@ -632,6 +656,10 @@ func (cfg *TCPMuxProxyConf) CheckForCli() (err error) { } func (cfg *TCPMuxProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } + if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer { return fmt.Errorf("proxy [%s] incorrect multiplexer [%s]", cfg.ProxyName, cfg.Multiplexer) } @@ -703,6 +731,9 @@ func (cfg *UDPProxyConf) CheckForCli() (err error) { } func (cfg *UDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } return nil } @@ -788,6 +819,10 @@ func (cfg *HTTPProxyConf) CheckForCli() (err error) { } func (cfg *HTTPProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } + if serverCfg.VhostHTTPPort == 0 { return fmt.Errorf("type [http] not support when vhost_http_port is not set") } @@ -860,6 +895,10 @@ func (cfg *HTTPSProxyConf) CheckForCli() (err error) { } func (cfg *HTTPSProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } + if serverCfg.VhostHTTPSPort == 0 { return fmt.Errorf("type [https] not support when vhost_https_port is not set") } @@ -932,6 +971,9 @@ func (cfg *SUDPProxyConf) CheckForCli() (err error) { } func (cfg *SUDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } return nil } @@ -998,6 +1040,9 @@ func (cfg *STCPProxyConf) CheckForCli() (err error) { } func (cfg *STCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } return nil } @@ -1064,5 +1109,8 @@ func (cfg *XTCPProxyConf) CheckForCli() (err error) { } func (cfg *XTCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { + if err := cfg.BaseProxyConf.checkForSvr(); err != nil { + return err + } return nil } diff --git a/pkg/config/proxy_test.go b/pkg/config/proxy_test.go index c603dd7..894d6fd 100644 --- a/pkg/config/proxy_test.go +++ b/pkg/config/proxy_test.go @@ -58,6 +58,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { local_ip = 127.0.0.9 local_port = 29 bandwidth_limit = 19MB + bandwidth_limit_mode = server use_encryption use_compression remote_port = 6009 @@ -71,13 +72,14 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { meta_var2 = 234`), expected: &TCPProxyConf{ BaseProxyConf: BaseProxyConf{ - ProxyName: testProxyPrefix + "ssh", - ProxyType: consts.TCPProxy, - UseCompression: true, - UseEncryption: true, - Group: "test_group", - GroupKey: "123456", - BandwidthLimit: MustBandwidthQuantity("19MB"), + ProxyName: testProxyPrefix + "ssh", + ProxyType: consts.TCPProxy, + UseCompression: true, + UseEncryption: true, + Group: "test_group", + GroupKey: "123456", + BandwidthLimit: MustBandwidthQuantity("19MB"), + BandwidthLimitMode: BandwidthLimitModeServer, Metas: map[string]string{ "var1": "123", "var2": "234", @@ -114,6 +116,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 29, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 9, }, @@ -139,6 +142,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 59, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6009, }, @@ -182,6 +186,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { HealthCheckIntervalS: 19, HealthCheckURL: "http://127.0.0.9:89/status", }, + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"web02.yourdomain.com"}, @@ -220,6 +225,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { LocalPort: 8009, }, ProxyProtocolVersion: "v2", + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"web02.yourdomain.com"}, @@ -246,6 +252,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.1", LocalPort: 22, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, Role: "server", Sk: "abcdefg", @@ -270,6 +277,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.1", LocalPort: 22, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, Role: "server", Sk: "abcdefg", @@ -293,6 +301,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.1", LocalPort: 10701, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, DomainConf: DomainConf{ CustomDomains: []string{"tunnel1"}, @@ -347,6 +356,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 6010, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6010, }, @@ -358,6 +368,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 6011, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6011, }, @@ -369,6 +380,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) { LocalIP: "127.0.0.9", LocalPort: 6019, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6019, }, @@ -396,6 +408,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 6000, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6000, }, @@ -409,6 +422,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 6010, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6010, }, @@ -422,6 +436,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) { LocalIP: "114.114.114.114", LocalPort: 6011, }, + BandwidthLimitMode: BandwidthLimitModeClient, }, RemotePort: 6011, }, diff --git a/pkg/config/types.go b/pkg/config/types.go index 28a0e46..7aefee1 100644 --- a/pkg/config/types.go +++ b/pkg/config/types.go @@ -24,6 +24,9 @@ import ( const ( MB = 1024 * 1024 KB = 1024 + + BandwidthLimitModeClient = "client" + BandwidthLimitModeServer = "server" ) type BandwidthQuantity struct { diff --git a/pkg/msg/msg.go b/pkg/msg/msg.go index 4b2823c..33e8fe5 100644 --- a/pkg/msg/msg.go +++ b/pkg/msg/msg.go @@ -14,7 +14,9 @@ package msg -import "net" +import ( + "net" +) const ( TypeLogin = 'o' @@ -83,13 +85,15 @@ type LoginResp struct { // When frpc login success, send this message to frps for running a new proxy. type NewProxy struct { - ProxyName string `json:"proxy_name,omitempty"` - ProxyType string `json:"proxy_type,omitempty"` - UseEncryption bool `json:"use_encryption,omitempty"` - UseCompression bool `json:"use_compression,omitempty"` - Group string `json:"group,omitempty"` - GroupKey string `json:"group_key,omitempty"` - Metas map[string]string `json:"metas,omitempty"` + ProxyName string `json:"proxy_name,omitempty"` + ProxyType string `json:"proxy_type,omitempty"` + UseEncryption bool `json:"use_encryption,omitempty"` + UseCompression bool `json:"use_compression,omitempty"` + BandwidthLimit string `json:"bandwidth_limit,omitempty"` + BandwidthLimitMode string `json:"bandwidth_limit_mode,omitempty"` + Group string `json:"group,omitempty"` + GroupKey string `json:"group_key,omitempty"` + Metas map[string]string `json:"metas,omitempty"` // tcp and udp only RemotePort int `json:"remote_port,omitempty"` diff --git a/server/proxy/http.go b/server/proxy/http.go index e70cb65..0f25c8c 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -20,8 +20,10 @@ import ( "strings" frpIo "github.com/fatedier/golib/io" + "golang.org/x/time/rate" "github.com/fatedier/frp/pkg/config" + "github.com/fatedier/frp/pkg/util/limit" frpNet "github.com/fatedier/frp/pkg/util/net" "github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/vhost" @@ -135,6 +137,10 @@ func (pxy *HTTPProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *HTTPProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) { xl := pxy.xl rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr) @@ -160,6 +166,13 @@ func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err err if pxy.cfg.UseCompression { rwc = frpIo.WithCompression(rwc) } + + if pxy.GetLimiter() != nil { + rwc = frpIo.WrapReadWriteCloser(limit.NewReader(rwc, pxy.GetLimiter()), limit.NewWriter(rwc, pxy.GetLimiter()), func() error { + return rwc.Close() + }) + } + workConn = frpNet.WrapReadWriteCloserToConn(rwc, tmpConn) workConn = frpNet.WrapStatsConn(workConn, pxy.updateStatsAfterClosedConn) metrics.Server.OpenConnection(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType) diff --git a/server/proxy/https.go b/server/proxy/https.go index 42ecf35..1fb579e 100644 --- a/server/proxy/https.go +++ b/server/proxy/https.go @@ -17,6 +17,8 @@ package proxy import ( "strings" + "golang.org/x/time/rate" + "github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/vhost" @@ -74,6 +76,10 @@ func (pxy *HTTPSProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *HTTPSProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *HTTPSProxy) Close() { pxy.BaseProxy.Close() } diff --git a/server/proxy/proxy.go b/server/proxy/proxy.go index 808d931..0681370 100644 --- a/server/proxy/proxy.go +++ b/server/proxy/proxy.go @@ -24,10 +24,12 @@ import ( "time" frpIo "github.com/fatedier/golib/io" + "golang.org/x/time/rate" "github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/msg" plugin "github.com/fatedier/frp/pkg/plugin/server" + "github.com/fatedier/frp/pkg/util/limit" frpNet "github.com/fatedier/frp/pkg/util/net" "github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/server/controller" @@ -45,6 +47,7 @@ type Proxy interface { GetUsedPortsNum() int GetResourceController() *controller.ResourceController GetUserInfo() plugin.UserInfo + GetLimiter() *rate.Limiter Close() } @@ -56,6 +59,7 @@ type BaseProxy struct { poolCount int getWorkConnFn GetWorkConnFn serverCfg config.ServerCommonConf + limiter *rate.Limiter userInfo plugin.UserInfo mu sync.RWMutex @@ -187,6 +191,13 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, ) (pxy Proxy, err error) { xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName) + + var limiter *rate.Limiter + limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() + if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeServer { + limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes)) + } + basePxy := BaseProxy{ name: pxyConf.GetBaseInfo().ProxyName, rc: rc, @@ -194,6 +205,7 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso poolCount: poolCount, getWorkConnFn: getWorkConnFn, serverCfg: serverCfg, + limiter: limiter, xl: xl, ctx: xlog.NewContext(ctx, xl), userInfo: userInfo, @@ -287,6 +299,13 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv if cfg.UseCompression { local = frpIo.WithCompression(local) } + + if pxy.GetLimiter() != nil { + local = frpIo.WrapReadWriteCloser(limit.NewReader(local, pxy.GetLimiter()), limit.NewWriter(local, pxy.GetLimiter()), func() error { + return local.Close() + }) + } + xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(), workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String()) diff --git a/server/proxy/stcp.go b/server/proxy/stcp.go index 5ac47ea..2ece405 100644 --- a/server/proxy/stcp.go +++ b/server/proxy/stcp.go @@ -15,6 +15,8 @@ package proxy import ( + "golang.org/x/time/rate" + "github.com/fatedier/frp/pkg/config" ) @@ -41,6 +43,10 @@ func (pxy *STCPProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *STCPProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *STCPProxy) Close() { pxy.BaseProxy.Close() pxy.rc.VisitorManager.CloseListener(pxy.GetName()) diff --git a/server/proxy/sudp.go b/server/proxy/sudp.go index c4dba6d..93707f2 100644 --- a/server/proxy/sudp.go +++ b/server/proxy/sudp.go @@ -15,6 +15,8 @@ package proxy import ( + "golang.org/x/time/rate" + "github.com/fatedier/frp/pkg/config" ) @@ -42,6 +44,10 @@ func (pxy *SUDPProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *SUDPProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *SUDPProxy) Close() { pxy.BaseProxy.Close() pxy.rc.VisitorManager.CloseListener(pxy.GetName()) diff --git a/server/proxy/tcp.go b/server/proxy/tcp.go index 0cf9c5f..1ba0fb1 100644 --- a/server/proxy/tcp.go +++ b/server/proxy/tcp.go @@ -19,6 +19,8 @@ import ( "net" "strconv" + "golang.org/x/time/rate" + "github.com/fatedier/frp/pkg/config" ) @@ -74,6 +76,10 @@ func (pxy *TCPProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *TCPProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *TCPProxy) Close() { pxy.BaseProxy.Close() if pxy.cfg.Group == "" { diff --git a/server/proxy/tcpmux.go b/server/proxy/tcpmux.go index b812e60..4b413c3 100644 --- a/server/proxy/tcpmux.go +++ b/server/proxy/tcpmux.go @@ -19,6 +19,8 @@ import ( "net" "strings" + "golang.org/x/time/rate" + "github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/util/util" @@ -94,6 +96,10 @@ func (pxy *TCPMuxProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *TCPMuxProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *TCPMuxProxy) Close() { pxy.BaseProxy.Close() } diff --git a/server/proxy/udp.go b/server/proxy/udp.go index 5386554..3a136c3 100644 --- a/server/proxy/udp.go +++ b/server/proxy/udp.go @@ -24,10 +24,12 @@ import ( "github.com/fatedier/golib/errors" frpIo "github.com/fatedier/golib/io" + "golang.org/x/time/rate" "github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/proto/udp" + "github.com/fatedier/frp/pkg/util/limit" frpNet "github.com/fatedier/frp/pkg/util/net" "github.com/fatedier/frp/server/metrics" ) @@ -198,6 +200,12 @@ func (pxy *UDPProxy) Run() (remoteAddr string, err error) { rwc = frpIo.WithCompression(rwc) } + if pxy.GetLimiter() != nil { + rwc = frpIo.WrapReadWriteCloser(limit.NewReader(rwc, pxy.GetLimiter()), limit.NewWriter(rwc, pxy.GetLimiter()), func() error { + return rwc.Close() + }) + } + pxy.workConn = frpNet.WrapReadWriteCloserToConn(rwc, workConn) ctx, cancel := context.WithCancel(context.Background()) go workConnReaderFn(pxy.workConn) @@ -225,6 +233,10 @@ func (pxy *UDPProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *UDPProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *UDPProxy) Close() { pxy.mu.Lock() defer pxy.mu.Unlock() diff --git a/server/proxy/xtcp.go b/server/proxy/xtcp.go index a1b45d5..b6c7be3 100644 --- a/server/proxy/xtcp.go +++ b/server/proxy/xtcp.go @@ -18,6 +18,7 @@ import ( "fmt" "github.com/fatedier/golib/errors" + "golang.org/x/time/rate" "github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/msg" @@ -88,6 +89,10 @@ func (pxy *XTCPProxy) GetConf() config.ProxyConf { return pxy.cfg } +func (pxy *XTCPProxy) GetLimiter() *rate.Limiter { + return pxy.limiter +} + func (pxy *XTCPProxy) Close() { pxy.BaseProxy.Close() pxy.rc.NatHoleController.CloseClient(pxy.GetName()) From 38d42dbe4b00b6bc07406ce4a16a06d77d50c800 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 9 Feb 2023 00:59:40 +0800 Subject: [PATCH 11/13] release: prepare for 0.47.0 (#3296) --- pkg/util/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index 849002d..49d5643 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -19,7 +19,7 @@ import ( "strings" ) -var version = "0.46.1" +var version = "0.47.0" func Full() string { return version From 89fff7d11de98d48b36283a5508aa6f5078e246e Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 9 Feb 2023 01:11:00 +0800 Subject: [PATCH 12/13] e2e: add test case for bandwidth_limit_mode server (#3295) --- Makefile | 3 ++ test/e2e/features/bandwidth_limit.go | 64 ++++++++++++++++++++++++++-- test/e2e/framework/process.go | 4 +- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d3f09bd..4600abc 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,9 @@ file: fmt: go fmt ./... +fmt-more: + gofumpt -l -w . + vet: go vet ./... diff --git a/test/e2e/features/bandwidth_limit.go b/test/e2e/features/bandwidth_limit.go index a912b06..238055a 100644 --- a/test/e2e/features/bandwidth_limit.go +++ b/test/e2e/features/bandwidth_limit.go @@ -7,16 +7,18 @@ import ( "github.com/onsi/ginkgo" + plugin "github.com/fatedier/frp/pkg/plugin/server" "github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/pkg/request" + plugintest "github.com/fatedier/frp/test/e2e/plugin" ) var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() { f := framework.NewDefaultFramework() - ginkgo.It("Proxy Bandwidth Limit", func() { + ginkgo.It("Proxy Bandwidth Limit by Client", func() { serverConf := consts.DefaultServerConfig clientConf := consts.DefaultClientConfig @@ -40,8 +42,64 @@ var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() { framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) { r.Body([]byte(content)).Timeout(30 * time.Second) }).ExpectResp([]byte(content)).Ensure() - duration := time.Since(start) - framework.ExpectTrue(duration.Seconds() > 7, "100Kb with 10KB limit, want > 7 seconds, but got %d seconds", duration.Seconds()) + duration := time.Since(start) + framework.Logf("request duration: %s", duration.String()) + + framework.ExpectTrue(duration.Seconds() > 8, "100Kb with 10KB limit, want > 8 seconds, but got %s", duration.String()) + }) + + ginkgo.It("Proxy Bandwidth Limit by Server", func() { + // new test plugin server + newFunc := func() *plugin.Request { + var r plugin.Request + r.Content = &plugin.NewProxyContent{} + return &r + } + pluginPort := f.AllocPort() + handler := func(req *plugin.Request) *plugin.Response { + var ret plugin.Response + content := req.Content.(*plugin.NewProxyContent) + content.BandwidthLimit = "10KB" + content.BandwidthLimitMode = "server" + ret.Content = content + return &ret + } + pluginServer := plugintest.NewHTTPPluginServer(pluginPort, newFunc, handler, nil) + + f.RunServer("", pluginServer) + + serverConf := consts.DefaultServerConfig + fmt.Sprintf(` + [plugin.test] + addr = 127.0.0.1:%d + path = /handler + ops = NewProxy + `, pluginPort) + clientConf := consts.DefaultClientConfig + + localPort := f.AllocPort() + localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(localPort)) + f.RunServer("", localServer) + + remotePort := f.AllocPort() + clientConf += fmt.Sprintf(` + [tcp] + type = tcp + local_port = %d + remote_port = %d + `, localPort, remotePort) + + f.RunProcesses([]string{serverConf}, []string{clientConf}) + + content := strings.Repeat("a", 50*1024) // 5KB + start := time.Now() + framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) { + r.Body([]byte(content)).Timeout(30 * time.Second) + }).ExpectResp([]byte(content)).Ensure() + + duration := time.Since(start) + framework.Logf("request duration: %s", duration.String()) + + framework.ExpectTrue(duration.Seconds() > 8, "100Kb with 10KB limit, want > 8 seconds, but got %s", duration.String()) }) }) diff --git a/test/e2e/framework/process.go b/test/e2e/framework/process.go index 7c328dd..6761d8f 100644 --- a/test/e2e/framework/process.go +++ b/test/e2e/framework/process.go @@ -69,7 +69,7 @@ func (f *Framework) RunFrps(args ...string) (*process.Process, string, error) { return p, p.StdOutput(), err } // sleep for a while to get std output - time.Sleep(500 * time.Millisecond) + time.Sleep(time.Second) return p, p.StdOutput(), nil } @@ -80,7 +80,7 @@ func (f *Framework) RunFrpc(args ...string) (*process.Process, string, error) { if err != nil { return p, p.StdOutput(), err } - time.Sleep(500 * time.Millisecond) + time.Sleep(time.Second) return p, p.StdOutput(), nil } From fa0593ae2c7a9257e3b6a10b4272b6a03b6156e5 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 9 Feb 2023 22:52:48 +0800 Subject: [PATCH 13/13] add release notes --- Release.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Release.md b/Release.md index e69de29..33b44d3 100644 --- a/Release.md +++ b/Release.md @@ -0,0 +1,8 @@ +### New + +* Added config `bandwidth_limit_mode` in frpc, default value is `client` which is current behavior. Optional value is `server`, to enable bandwidth limit in server. The major aim is to let server plugin has the ability to modify bandwidth limit for each proxy. + +### Improve + +* `dns_server` supports ipv6. +* frpc supports graceful shutdown for protocol `quic`.