diff --git a/.circleci/config.yml b/.circleci/config.yml
index 7499579a..b8dca0e9 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 c9051f38..0aa1c5dd 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 d0234d5a..484167aa 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 39c8e3f7..0fe5d726 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/Makefile b/Makefile
index d3f09bd0..4600abcb 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,9 @@ file:
fmt:
go fmt ./...
+fmt-more:
+ gofumpt -l -w .
+
vet:
go vet ./...
diff --git a/README.md b/README.md
index 57a68949..73e48c75 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.
@@ -143,7 +139,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`
@@ -717,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/README_zh.md b/README_zh.md
index e0612bbf..1cc7b4eb 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -18,10 +18,6 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP
-Silver Sponsors
-
-* Sakura Frp - 欢迎点击 "加入我们"
-
## 为什么使用 frp ?
通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:
diff --git a/Release.md b/Release.md
index 6738c32b..33b44d37 100644
--- a/Release.md
+++ b/Release.md
@@ -1,4 +1,8 @@
-### Fix
+### New
-* Server Plugin send incorrect op name for NewWorkConn.
-* QUIC stream leak.
+* 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`.
diff --git a/client/proxy/proxy.go b/client/proxy/proxy.go
index 158773bc..98a8a672 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/client/service.go b/client/service.go
index b72fea77..bac57167 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"
@@ -47,6 +47,7 @@ import (
func init() {
crypto.DefaultSalt = "frp"
+ // TODO: remove this when we drop support for go1.19
rand.Seed(time.Now().UnixNano())
}
@@ -114,8 +115,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{
diff --git a/cmd/frpc/sub/http.go b/cmd/frpc/sub/http.go
index 4e193b7e..22eeefe6 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 8a14d39d..187aa99b 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 cea8ecc6..cd39d882 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
)
@@ -216,15 +218,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
}
diff --git a/cmd/frpc/sub/stcp.go b/cmd/frpc/sub/stcp.go
index d84b23b7..ad0a57ce 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 f96a12e1..0ae8498b 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 7e867345..2c597f19 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 cef845d6..ecdd6002 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 984ad068..f9dfa3f6 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 b8426989..ea201d53 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/cmd/frps/main.go b/cmd/frps/main.go
index 56477aad..6ae5378b 100644
--- a/cmd/frps/main.go
+++ b/cmd/frps/main.go
@@ -26,6 +26,7 @@ import (
func main() {
crypto.DefaultSalt = "frp"
+ // TODO: remove this when we drop support for go1.19
rand.Seed(time.Now().UnixNano())
Execute()
diff --git a/conf/frpc_full.ini b/conf/frpc_full.ini
index 8e39de1c..29f6bcab 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 d73d2439..f4e377f4 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/dockerfiles/Dockerfile-for-frpc b/dockerfiles/Dockerfile-for-frpc
index b749be07..96a3d8b9 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 cd716123..12d52012 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 d518a612..dd631841 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
@@ -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 34712871..521f06b2 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/config/client_test.go b/pkg/config/client_test.go
index 9cf8c805..79eef5f5 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 92b499f2..3419f483 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 c603dd7f..894d6fd3 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 28a0e46d..7aefee12 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 4b2823c7..33e8fe5d 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/pkg/util/net/conn.go b/pkg/util/net/conn.go
index a09da99e..fb2ff677 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/pkg/util/util/util.go b/pkg/util/util/util.go
index b13f9a77..b72209c6 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)
}
diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go
index 849002d7..49d5643e 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
diff --git a/server/proxy/http.go b/server/proxy/http.go
index e70cb65f..0f25c8c4 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 42ecf35d..1fb579e1 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 808d9316..0681370f 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 5ac47eaa..2ece4057 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 c4dba6d6..93707f23 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 0cf9c5f9..1ba0fb1a 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 b812e601..4b413c36 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 53865540..3a136c39 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 a1b45d54..b6c7be3a 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())
diff --git a/server/service.go b/server/service.go
index fc59b39c..e2f84940 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"
diff --git a/test/e2e/features/bandwidth_limit.go b/test/e2e/features/bandwidth_limit.go
index a912b06a..238055a8 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 7c328dd4..6761d8f4 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
}