Merge pull request #3299 from fatedier/dev

sync
This commit is contained in:
fatedier 2023-02-09 23:06:14 +08:00 committed by GitHub
commit 534dc99d55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 409 additions and 99 deletions

View File

@ -2,7 +2,7 @@ version: 2
jobs: jobs:
go-version-latest: go-version-latest:
docker: docker:
- image: cimg/go:1.19-node - image: cimg/go:1.20-node
resource_class: large resource_class: large
steps: steps:
- checkout - checkout
@ -10,7 +10,7 @@ jobs:
- run: make alltest - run: make alltest
go-version-last: go-version-last:
docker: docker:
- image: cimg/go:1.18-node - image: cimg/go:1.19-node
resource_class: large resource_class: large
steps: steps:
- checkout - checkout

View File

@ -16,13 +16,13 @@ jobs:
steps: steps:
- uses: actions/setup-go@v3 - uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v3
with: with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version # 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. # Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0 # args: --issues-exit-code=0

View File

@ -15,7 +15,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- name: Make All - name: Make All
run: | run: |

View File

@ -1,6 +1,5 @@
service: service:
# When updating this, also update the version stored in docker/build-tools/Dockerfile in the istio/tools repo. golangci-lint-version: 1.51.x # use the fixed version to not introduce new linters unexpectedly
golangci-lint-version: 1.49.x # use the fixed version to not introduce new linters unexpectedly
run: run:
concurrency: 4 concurrency: 4
@ -127,6 +126,11 @@ issues:
- errcheck - errcheck
- maligned - 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, # Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all # it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`. # excluded by default patterns execute `golangci-lint run --help`.

View File

@ -16,6 +16,9 @@ file:
fmt: fmt:
go fmt ./... go fmt ./...
fmt-more:
gofumpt -l -w .
vet: vet:
go vet ./... go vet ./...

View File

@ -17,10 +17,6 @@
<!--gold sponsors end--> <!--gold sponsors end-->
<h3 align="center">Silver Sponsors</h3>
* Sakura Frp - 欢迎点击 "加入我们"
## What is 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. 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` `./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` `ssh -oPort=6000 test@x.x.x.x`
@ -717,10 +713,13 @@ type = tcp
local_port = 22 local_port = 22
remote_port = 6000 remote_port = 6000
bandwidth_limit = 1MB 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` 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 ### 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. 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.

View File

@ -18,10 +18,6 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP
<!--gold sponsors end--> <!--gold sponsors end-->
<h3 align="center">Silver Sponsors</h3>
* Sakura Frp - 欢迎点击 "加入我们"
## 为什么使用 frp ## 为什么使用 frp
通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括: 通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:

View File

@ -1,4 +1,8 @@
### Fix ### New
* Server Plugin send incorrect op name for NewWorkConn. * 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.
* QUIC stream leak.
### Improve
* `dns_server` supports ipv6.
* frpc supports graceful shutdown for protocol `quic`.

View File

@ -54,7 +54,7 @@ type Proxy interface {
func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) { func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
var limiter *rate.Limiter var limiter *rate.Limiter
limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() 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)) limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
} }

View File

@ -31,7 +31,7 @@ import (
"github.com/fatedier/golib/crypto" "github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial" libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux" 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/assets"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
@ -47,6 +47,7 @@ import (
func init() { func init() {
crypto.DefaultSalt = "frp" crypto.DefaultSalt = "frp"
// TODO: remove this when we drop support for go1.19
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
} }
@ -114,8 +115,8 @@ func (svr *Service) Run() error {
// set custom DNSServer // set custom DNSServer
if svr.cfg.DNSServer != "" { if svr.cfg.DNSServer != "" {
dnsAddr := svr.cfg.DNSServer dnsAddr := svr.cfg.DNSServer
if !strings.Contains(dnsAddr, ":") { if _, _, err := net.SplitHostPort(dnsAddr); err != nil {
dnsAddr += ":53" dnsAddr = net.JoinHostPort(dnsAddr, "53")
} }
// Change default dns server for frpc // Change default dns server for frpc
net.DefaultResolver = &net.Resolver{ net.DefaultResolver = &net.Resolver{

View File

@ -39,6 +39,8 @@ func init() {
httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite") httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite")
httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
httpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(httpCmd)
} }
@ -70,6 +72,12 @@ var httpCmd = &cobra.Command{
cfg.HostHeaderRewrite = hostHeaderRewrite cfg.HostHeaderRewrite = hostHeaderRewrite
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@ -35,6 +35,8 @@ func init() {
httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain") httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
httpsCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(httpsCmd)
} }
@ -62,6 +64,12 @@ var httpsCmd = &cobra.Command{
cfg.SubDomain = subDomain cfg.SubDomain = subDomain
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@ -54,24 +54,26 @@ var (
logMaxDays int logMaxDays int
disableLogColor bool disableLogColor bool
proxyName string proxyName string
localIP string localIP string
localPort int localPort int
remotePort int remotePort int
useEncryption bool useEncryption bool
useCompression bool useCompression bool
customDomains string bandwidthLimit string
subDomain string bandwidthLimitMode string
httpUser string customDomains string
httpPwd string subDomain string
locations string httpUser string
hostHeaderRewrite string httpPwd string
role string locations string
sk string hostHeaderRewrite string
multiplexer string role string
serverName string sk string
bindAddr string multiplexer string
bindPort int serverName string
bindAddr string
bindPort int
tlsEnable bool tlsEnable bool
) )
@ -216,15 +218,16 @@ func startService(
return return
} }
kcpDoneCh := make(chan struct{}) closedDoneCh := make(chan struct{})
// Capture the exit signal if we use kcp. shouldGracefulClose := cfg.Protocol == "kcp" || cfg.Protocol == "quic"
if cfg.Protocol == "kcp" { // Capture the exit signal if we use kcp or quic.
go handleSignal(svr, kcpDoneCh) if shouldGracefulClose {
go handleSignal(svr, closedDoneCh)
} }
err = svr.Run() err = svr.Run()
if err == nil && cfg.Protocol == "kcp" { if err == nil && shouldGracefulClose {
<-kcpDoneCh <-closedDoneCh
} }
return return
} }

View File

@ -37,6 +37,8 @@ func init() {
stcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") stcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
stcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(stcpCmd)
} }
@ -70,6 +72,12 @@ var stcpCmd = &cobra.Command{
cfg.Sk = sk cfg.Sk = sk
cfg.LocalIP = localIP cfg.LocalIP = localIP
cfg.LocalPort = localPort cfg.LocalPort = localPort
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

View File

@ -37,6 +37,8 @@ func init() {
sudpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") sudpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
sudpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") sudpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
sudpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(sudpCmd)
} }
@ -70,6 +72,12 @@ var sudpCmd = &cobra.Command{
cfg.Sk = sk cfg.Sk = sk
cfg.LocalIP = localIP cfg.LocalIP = localIP
cfg.LocalPort = localPort cfg.LocalPort = localPort
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

View File

@ -33,6 +33,8 @@ func init() {
tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port") tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
tcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(tcpCmd)
} }
@ -59,6 +61,12 @@ var tcpCmd = &cobra.Command{
cfg.RemotePort = remotePort cfg.RemotePort = remotePort
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@ -36,6 +36,8 @@ func init() {
tcpMuxCmd.PersistentFlags().StringVarP(&multiplexer, "mux", "", "", "multiplexer") tcpMuxCmd.PersistentFlags().StringVarP(&multiplexer, "mux", "", "", "multiplexer")
tcpMuxCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") tcpMuxCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
tcpMuxCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(tcpMuxCmd)
} }
@ -64,6 +66,12 @@ var tcpMuxCmd = &cobra.Command{
cfg.Multiplexer = multiplexer cfg.Multiplexer = multiplexer
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@ -33,6 +33,8 @@ func init() {
udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port") udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
udpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(udpCmd)
} }
@ -59,6 +61,12 @@ var udpCmd = &cobra.Command{
cfg.RemotePort = remotePort cfg.RemotePort = remotePort
cfg.UseEncryption = useEncryption cfg.UseEncryption = useEncryption
cfg.UseCompression = useCompression cfg.UseCompression = useCompression
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {

View File

@ -37,6 +37,8 @@ func init() {
xtcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port") xtcpCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "", 0, "bind port")
xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption") xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
xtcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression") 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) rootCmd.AddCommand(xtcpCmd)
} }
@ -70,6 +72,12 @@ var xtcpCmd = &cobra.Command{
cfg.Sk = sk cfg.Sk = sk
cfg.LocalIP = localIP cfg.LocalIP = localIP
cfg.LocalPort = localPort cfg.LocalPort = localPort
cfg.BandwidthLimit, err = config.NewBandwidthQuantity(bandwidthLimit)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cfg.BandwidthLimitMode = bandwidthLimitMode
err = cfg.CheckForCli() err = cfg.CheckForCli()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

View File

@ -26,6 +26,7 @@ import (
func main() { func main() {
crypto.DefaultSalt = "frp" crypto.DefaultSalt = "frp"
// TODO: remove this when we drop support for go1.19
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
Execute() Execute()

View File

@ -154,6 +154,8 @@ local_ip = 127.0.0.1
local_port = 22 local_port = 22
# limit bandwidth for this proxy, unit is KB and MB # limit bandwidth for this proxy, unit is KB and MB
bandwidth_limit = 1MB 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 # true or false, if true, messages between frps and frpc will be encrypted, default is false
use_encryption = false use_encryption = false
# if true, message will be compressed # if true, message will be compressed

View File

@ -110,6 +110,8 @@ Create new proxy
"proxy_type": <string>, "proxy_type": <string>,
"use_encryption": <bool>, "use_encryption": <bool>,
"use_compression": <bool>, "use_compression": <bool>,
"bandwidth_limit": <string>,
"bandwidth_limit_mode": <string>,
"group": <string>, "group": <string>,
"group_key": <string>, "group_key": <string>,

View File

@ -1,4 +1,4 @@
FROM golang:1.19 AS building FROM golang:1.20 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building

View File

@ -1,4 +1,4 @@
FROM golang:1.19 AS building FROM golang:1.20 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building

15
go.mod
View File

@ -1,6 +1,6 @@
module github.com/fatedier/frp module github.com/fatedier/frp
go 1.19 go 1.20
require ( require (
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 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/mux v1.8.0
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/hashicorp/yamux v0.1.1 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/ginkgo v1.16.4
github.com/onsi/gomega v1.20.2 github.com/onsi/gomega v1.20.2
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.6.2
github.com/prometheus/client_golang v1.13.0 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/rodaine/table v1.0.1
github.com/spf13/cobra v1.1.3 github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
@ -47,8 +47,6 @@ require (
github.com/klauspost/cpuid/v2 v2.0.6 // indirect github.com/klauspost/cpuid/v2 v2.0.6 // indirect
github.com/klauspost/reedsolomon v1.9.15 // indirect github.com/klauspost/reedsolomon v1.9.15 // indirect
github.com/leodido/go-urn v1.2.1 // 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/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // 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/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.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/spf13/pflag v1.0.5 // indirect
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect
golang.org/x/crypto v0.4.0 // indirect golang.org/x/crypto v0.4.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0 // indirect
golang.org/x/sys v0.3.0 // indirect golang.org/x/sys v0.3.0 // indirect
golang.org/x/text v0.5.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/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect

26
go.sum
View File

@ -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/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 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 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/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-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-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 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 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= 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/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 h1:U/VwCnUxlVYxw8+NJiLIuCxA/xa6jL38MY3FYysVWWQ=
github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4= github.com/rodaine/table v1.0.1/go.mod h1:UVEtfBsflpeEcD56nF4F5AocNFta0ZuolpSVdPtlmP4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 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-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-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-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-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= 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-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/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= 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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/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.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 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/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.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -74,6 +74,7 @@ var testClientBytesWithFull = []byte(`
local_ip = 127.0.0.9 local_ip = 127.0.0.9
local_port = 29 local_port = 29
bandwidth_limit = 19MB bandwidth_limit = 19MB
bandwidth_limit_mode = server
use_encryption use_encryption
use_compression use_compression
remote_port = 6009 remote_port = 6009
@ -309,13 +310,14 @@ func Test_LoadClientBasicConf(t *testing.T) {
proxyExpected := map[string]ProxyConf{ proxyExpected := map[string]ProxyConf{
testUser + ".ssh": &TCPProxyConf{ testUser + ".ssh": &TCPProxyConf{
BaseProxyConf: BaseProxyConf{ BaseProxyConf: BaseProxyConf{
ProxyName: testUser + ".ssh", ProxyName: testUser + ".ssh",
ProxyType: consts.TCPProxy, ProxyType: consts.TCPProxy,
UseCompression: true, UseCompression: true,
UseEncryption: true, UseEncryption: true,
Group: "test_group", Group: "test_group",
GroupKey: "123456", GroupKey: "123456",
BandwidthLimit: MustBandwidthQuantity("19MB"), BandwidthLimit: MustBandwidthQuantity("19MB"),
BandwidthLimitMode: BandwidthLimitModeServer,
Metas: map[string]string{ Metas: map[string]string{
"var1": "123", "var1": "123",
"var2": "234", "var2": "234",
@ -342,6 +344,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 29, LocalPort: 29,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 9, RemotePort: 9,
}, },
@ -353,6 +356,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@ -364,6 +368,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },
@ -375,6 +380,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6019, LocalPort: 6019,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6019, RemotePort: 6019,
}, },
@ -388,6 +394,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 59, LocalPort: 59,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6009, RemotePort: 6009,
}, },
@ -401,6 +408,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6000, LocalPort: 6000,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6000, RemotePort: 6000,
}, },
@ -414,6 +422,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@ -427,6 +436,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },
@ -447,6 +457,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
HealthCheckIntervalS: 19, HealthCheckIntervalS: 19,
HealthCheckURL: "http://127.0.0.9:89/status", HealthCheckURL: "http://127.0.0.9:89/status",
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@ -471,6 +482,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalPort: 8009, LocalPort: 8009,
}, },
ProxyProtocolVersion: "v2", ProxyProtocolVersion: "v2",
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@ -485,6 +497,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@ -497,6 +510,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@ -509,6 +523,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 10701, LocalPort: 10701,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"tunnel1"}, CustomDomains: []string{"tunnel1"},
@ -527,6 +542,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_unix_path": "/var/run/docker.sock", "plugin_unix_path": "/var/run/docker.sock",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6003, RemotePort: 6003,
}, },
@ -542,6 +558,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_http_passwd": "abc", "plugin_http_passwd": "abc",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6004, RemotePort: 6004,
}, },
@ -557,6 +574,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_passwd": "abc", "plugin_passwd": "abc",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6005, RemotePort: 6005,
}, },
@ -574,6 +592,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_http_passwd": "abc", "plugin_http_passwd": "abc",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6006, RemotePort: 6006,
}, },
@ -592,6 +611,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_header_X-From-Where": "frp", "plugin_header_X-From-Where": "frp",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"test.yourdomain.com"}, CustomDomains: []string{"test.yourdomain.com"},
@ -610,6 +630,7 @@ func Test_LoadClientBasicConf(t *testing.T) {
"plugin_header_X-From-Where": "frp", "plugin_header_X-From-Where": "frp",
}, },
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"test.yourdomain.com"}, CustomDomains: []string{"test.yourdomain.com"},

View File

@ -141,6 +141,10 @@ type BaseProxyConf struct {
// BandwidthLimit limit the bandwidth // BandwidthLimit limit the bandwidth
// 0 means no limit // 0 means no limit
BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_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 // meta info for each proxy
Metas map[string]string `ini:"-" json:"metas"` Metas map[string]string `ini:"-" json:"metas"`
@ -319,6 +323,7 @@ func defaultBaseProxyConf(proxyType string) BaseProxyConf {
LocalSvrConf: LocalSvrConf{ LocalSvrConf: LocalSvrConf{
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
} }
} }
@ -335,6 +340,7 @@ func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool {
cfg.GroupKey != cmp.GroupKey || cfg.GroupKey != cmp.GroupKey ||
cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion || cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion ||
!cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) || !cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) ||
cfg.BandwidthLimitMode != cmp.BandwidthLimitMode ||
!reflect.DeepEqual(cfg.Metas, cmp.Metas) { !reflect.DeepEqual(cfg.Metas, cmp.Metas) {
return false return false
} }
@ -389,6 +395,8 @@ func (cfg *BaseProxyConf) marshalToMsg(pMsg *msg.NewProxy) {
pMsg.ProxyType = cfg.ProxyType pMsg.ProxyType = cfg.ProxyType
pMsg.UseEncryption = cfg.UseEncryption pMsg.UseEncryption = cfg.UseEncryption
pMsg.UseCompression = cfg.UseCompression pMsg.UseCompression = cfg.UseCompression
pMsg.BandwidthLimit = cfg.BandwidthLimit.String()
pMsg.BandwidthLimitMode = cfg.BandwidthLimitMode
pMsg.Group = cfg.Group pMsg.Group = cfg.Group
pMsg.GroupKey = cfg.GroupKey pMsg.GroupKey = cfg.GroupKey
pMsg.Metas = cfg.Metas pMsg.Metas = cfg.Metas
@ -399,6 +407,8 @@ func (cfg *BaseProxyConf) unmarshalFromMsg(pMsg *msg.NewProxy) {
cfg.ProxyType = pMsg.ProxyType cfg.ProxyType = pMsg.ProxyType
cfg.UseEncryption = pMsg.UseEncryption cfg.UseEncryption = pMsg.UseEncryption
cfg.UseCompression = pMsg.UseCompression cfg.UseCompression = pMsg.UseCompression
cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit)
cfg.BandwidthLimitMode = pMsg.BandwidthLimitMode
cfg.Group = pMsg.Group cfg.Group = pMsg.Group
cfg.GroupKey = pMsg.GroupKey cfg.GroupKey = pMsg.GroupKey
cfg.Metas = pMsg.Metas 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 { if err = cfg.LocalSvrConf.checkForCli(); err != nil {
return return
} }
@ -420,6 +434,13 @@ func (cfg *BaseProxyConf) checkForCli() (err error) {
return nil 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 // DomainConf
func (cfg *DomainConf) check() (err error) { func (cfg *DomainConf) check() (err error) {
if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" { if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" {
@ -557,6 +578,9 @@ func (cfg *TCPProxyConf) CheckForCli() (err error) {
} }
func (cfg *TCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *TCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@ -632,6 +656,10 @@ func (cfg *TCPMuxProxyConf) CheckForCli() (err error) {
} }
func (cfg *TCPMuxProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { func (cfg *TCPMuxProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer { if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer {
return fmt.Errorf("proxy [%s] incorrect multiplexer [%s]", cfg.ProxyName, cfg.Multiplexer) 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 { func (cfg *UDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@ -788,6 +819,10 @@ func (cfg *HTTPProxyConf) CheckForCli() (err error) {
} }
func (cfg *HTTPProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { func (cfg *HTTPProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
if serverCfg.VhostHTTPPort == 0 { if serverCfg.VhostHTTPPort == 0 {
return fmt.Errorf("type [http] not support when vhost_http_port is not set") 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) { func (cfg *HTTPSProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
if serverCfg.VhostHTTPSPort == 0 { if serverCfg.VhostHTTPSPort == 0 {
return fmt.Errorf("type [https] not support when vhost_https_port is not set") 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 { func (cfg *SUDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@ -998,6 +1040,9 @@ func (cfg *STCPProxyConf) CheckForCli() (err error) {
} }
func (cfg *STCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *STCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }
@ -1064,5 +1109,8 @@ func (cfg *XTCPProxyConf) CheckForCli() (err error) {
} }
func (cfg *XTCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { func (cfg *XTCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error {
if err := cfg.BaseProxyConf.checkForSvr(); err != nil {
return err
}
return nil return nil
} }

View File

@ -58,6 +58,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
local_ip = 127.0.0.9 local_ip = 127.0.0.9
local_port = 29 local_port = 29
bandwidth_limit = 19MB bandwidth_limit = 19MB
bandwidth_limit_mode = server
use_encryption use_encryption
use_compression use_compression
remote_port = 6009 remote_port = 6009
@ -71,13 +72,14 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
meta_var2 = 234`), meta_var2 = 234`),
expected: &TCPProxyConf{ expected: &TCPProxyConf{
BaseProxyConf: BaseProxyConf{ BaseProxyConf: BaseProxyConf{
ProxyName: testProxyPrefix + "ssh", ProxyName: testProxyPrefix + "ssh",
ProxyType: consts.TCPProxy, ProxyType: consts.TCPProxy,
UseCompression: true, UseCompression: true,
UseEncryption: true, UseEncryption: true,
Group: "test_group", Group: "test_group",
GroupKey: "123456", GroupKey: "123456",
BandwidthLimit: MustBandwidthQuantity("19MB"), BandwidthLimit: MustBandwidthQuantity("19MB"),
BandwidthLimitMode: BandwidthLimitModeServer,
Metas: map[string]string{ Metas: map[string]string{
"var1": "123", "var1": "123",
"var2": "234", "var2": "234",
@ -114,6 +116,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 29, LocalPort: 29,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 9, RemotePort: 9,
}, },
@ -139,6 +142,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 59, LocalPort: 59,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6009, RemotePort: 6009,
}, },
@ -182,6 +186,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
HealthCheckIntervalS: 19, HealthCheckIntervalS: 19,
HealthCheckURL: "http://127.0.0.9:89/status", HealthCheckURL: "http://127.0.0.9:89/status",
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@ -220,6 +225,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalPort: 8009, LocalPort: 8009,
}, },
ProxyProtocolVersion: "v2", ProxyProtocolVersion: "v2",
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"web02.yourdomain.com"}, CustomDomains: []string{"web02.yourdomain.com"},
@ -246,6 +252,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@ -270,6 +277,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 22, LocalPort: 22,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
Role: "server", Role: "server",
Sk: "abcdefg", Sk: "abcdefg",
@ -293,6 +301,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.1", LocalIP: "127.0.0.1",
LocalPort: 10701, LocalPort: 10701,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
DomainConf: DomainConf{ DomainConf: DomainConf{
CustomDomains: []string{"tunnel1"}, CustomDomains: []string{"tunnel1"},
@ -347,6 +356,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@ -358,6 +368,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },
@ -369,6 +380,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "127.0.0.9", LocalIP: "127.0.0.9",
LocalPort: 6019, LocalPort: 6019,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6019, RemotePort: 6019,
}, },
@ -396,6 +408,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6000, LocalPort: 6000,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6000, RemotePort: 6000,
}, },
@ -409,6 +422,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6010, LocalPort: 6010,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6010, RemotePort: 6010,
}, },
@ -422,6 +436,7 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
LocalIP: "114.114.114.114", LocalIP: "114.114.114.114",
LocalPort: 6011, LocalPort: 6011,
}, },
BandwidthLimitMode: BandwidthLimitModeClient,
}, },
RemotePort: 6011, RemotePort: 6011,
}, },

View File

@ -24,6 +24,9 @@ import (
const ( const (
MB = 1024 * 1024 MB = 1024 * 1024
KB = 1024 KB = 1024
BandwidthLimitModeClient = "client"
BandwidthLimitModeServer = "server"
) )
type BandwidthQuantity struct { type BandwidthQuantity struct {

View File

@ -14,7 +14,9 @@
package msg package msg
import "net" import (
"net"
)
const ( const (
TypeLogin = 'o' TypeLogin = 'o'
@ -83,13 +85,15 @@ type LoginResp struct {
// When frpc login success, send this message to frps for running a new proxy. // When frpc login success, send this message to frps for running a new proxy.
type NewProxy struct { type NewProxy struct {
ProxyName string `json:"proxy_name,omitempty"` ProxyName string `json:"proxy_name,omitempty"`
ProxyType string `json:"proxy_type,omitempty"` ProxyType string `json:"proxy_type,omitempty"`
UseEncryption bool `json:"use_encryption,omitempty"` UseEncryption bool `json:"use_encryption,omitempty"`
UseCompression bool `json:"use_compression,omitempty"` UseCompression bool `json:"use_compression,omitempty"`
Group string `json:"group,omitempty"` BandwidthLimit string `json:"bandwidth_limit,omitempty"`
GroupKey string `json:"group_key,omitempty"` BandwidthLimitMode string `json:"bandwidth_limit_mode,omitempty"`
Metas map[string]string `json:"metas,omitempty"` Group string `json:"group,omitempty"`
GroupKey string `json:"group_key,omitempty"`
Metas map[string]string `json:"metas,omitempty"`
// tcp and udp only // tcp and udp only
RemotePort int `json:"remote_port,omitempty"` RemotePort int `json:"remote_port,omitempty"`

View File

@ -22,7 +22,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
quic "github.com/lucas-clemente/quic-go" quic "github.com/quic-go/quic-go"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
) )

View File

@ -44,9 +44,9 @@ func RandIDWithLen(idLen int) (id string, err error) {
} }
func GetAuthKey(token string, timestamp int64) (key string) { func GetAuthKey(token string, timestamp int64) (key string) {
token += fmt.Sprintf("%d", timestamp)
md5Ctx := md5.New() md5Ctx := md5.New()
md5Ctx.Write([]byte(token)) md5Ctx.Write([]byte(token))
md5Ctx.Write([]byte(strconv.FormatInt(timestamp, 10)))
data := md5Ctx.Sum(nil) data := md5Ctx.Sum(nil)
return hex.EncodeToString(data) return hex.EncodeToString(data)
} }

View File

@ -19,7 +19,7 @@ import (
"strings" "strings"
) )
var version = "0.46.1" var version = "0.47.0"
func Full() string { func Full() string {
return version return version

View File

@ -20,8 +20,10 @@ import (
"strings" "strings"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
@ -135,6 +137,10 @@ func (pxy *HTTPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *HTTPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) { func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) {
xl := pxy.xl xl := pxy.xl
rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr) 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 { if pxy.cfg.UseCompression {
rwc = frpIo.WithCompression(rwc) 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.WrapReadWriteCloserToConn(rwc, tmpConn)
workConn = frpNet.WrapStatsConn(workConn, pxy.updateStatsAfterClosedConn) workConn = frpNet.WrapStatsConn(workConn, pxy.updateStatsAfterClosedConn)
metrics.Server.OpenConnection(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType) metrics.Server.OpenConnection(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType)

View File

@ -17,6 +17,8 @@ package proxy
import ( import (
"strings" "strings"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
@ -74,6 +76,10 @@ func (pxy *HTTPSProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *HTTPSProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *HTTPSProxy) Close() { func (pxy *HTTPSProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
} }

View File

@ -24,10 +24,12 @@ import (
"time" "time"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
plugin "github.com/fatedier/frp/pkg/plugin/server" plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/frp/server/controller" "github.com/fatedier/frp/server/controller"
@ -45,6 +47,7 @@ type Proxy interface {
GetUsedPortsNum() int GetUsedPortsNum() int
GetResourceController() *controller.ResourceController GetResourceController() *controller.ResourceController
GetUserInfo() plugin.UserInfo GetUserInfo() plugin.UserInfo
GetLimiter() *rate.Limiter
Close() Close()
} }
@ -56,6 +59,7 @@ type BaseProxy struct {
poolCount int poolCount int
getWorkConnFn GetWorkConnFn getWorkConnFn GetWorkConnFn
serverCfg config.ServerCommonConf serverCfg config.ServerCommonConf
limiter *rate.Limiter
userInfo plugin.UserInfo userInfo plugin.UserInfo
mu sync.RWMutex 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, getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf,
) (pxy Proxy, err error) { ) (pxy Proxy, err error) {
xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName) 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{ basePxy := BaseProxy{
name: pxyConf.GetBaseInfo().ProxyName, name: pxyConf.GetBaseInfo().ProxyName,
rc: rc, rc: rc,
@ -194,6 +205,7 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso
poolCount: poolCount, poolCount: poolCount,
getWorkConnFn: getWorkConnFn, getWorkConnFn: getWorkConnFn,
serverCfg: serverCfg, serverCfg: serverCfg,
limiter: limiter,
xl: xl, xl: xl,
ctx: xlog.NewContext(ctx, xl), ctx: xlog.NewContext(ctx, xl),
userInfo: userInfo, userInfo: userInfo,
@ -287,6 +299,13 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv
if cfg.UseCompression { if cfg.UseCompression {
local = frpIo.WithCompression(local) 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(), 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()) workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())

View File

@ -15,6 +15,8 @@
package proxy package proxy
import ( import (
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
@ -41,6 +43,10 @@ func (pxy *STCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *STCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *STCPProxy) Close() { func (pxy *STCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.VisitorManager.CloseListener(pxy.GetName()) pxy.rc.VisitorManager.CloseListener(pxy.GetName())

View File

@ -15,6 +15,8 @@
package proxy package proxy
import ( import (
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
@ -42,6 +44,10 @@ func (pxy *SUDPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *SUDPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *SUDPProxy) Close() { func (pxy *SUDPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.VisitorManager.CloseListener(pxy.GetName()) pxy.rc.VisitorManager.CloseListener(pxy.GetName())

View File

@ -19,6 +19,8 @@ import (
"net" "net"
"strconv" "strconv"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
@ -74,6 +76,10 @@ func (pxy *TCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *TCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *TCPProxy) Close() { func (pxy *TCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
if pxy.cfg.Group == "" { if pxy.cfg.Group == "" {

View File

@ -19,6 +19,8 @@ import (
"net" "net"
"strings" "strings"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
@ -94,6 +96,10 @@ func (pxy *TCPMuxProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *TCPMuxProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *TCPMuxProxy) Close() { func (pxy *TCPMuxProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
} }

View File

@ -24,10 +24,12 @@ import (
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/proto/udp" "github.com/fatedier/frp/pkg/proto/udp"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
) )
@ -198,6 +200,12 @@ func (pxy *UDPProxy) Run() (remoteAddr string, err error) {
rwc = frpIo.WithCompression(rwc) 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) pxy.workConn = frpNet.WrapReadWriteCloserToConn(rwc, workConn)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go workConnReaderFn(pxy.workConn) go workConnReaderFn(pxy.workConn)
@ -225,6 +233,10 @@ func (pxy *UDPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *UDPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *UDPProxy) Close() { func (pxy *UDPProxy) Close() {
pxy.mu.Lock() pxy.mu.Lock()
defer pxy.mu.Unlock() defer pxy.mu.Unlock()

View File

@ -18,6 +18,7 @@ import (
"fmt" "fmt"
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
@ -88,6 +89,10 @@ func (pxy *XTCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *XTCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *XTCPProxy) Close() { func (pxy *XTCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.NatHoleController.CloseClient(pxy.GetName()) pxy.rc.NatHoleController.CloseClient(pxy.GetName())

View File

@ -28,7 +28,7 @@ import (
"github.com/fatedier/golib/net/mux" "github.com/fatedier/golib/net/mux"
fmux "github.com/hashicorp/yamux" 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/assets"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"

View File

@ -7,16 +7,18 @@ import (
"github.com/onsi/ginkgo" "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"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
plugintest "github.com/fatedier/frp/test/e2e/plugin"
) )
var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() { var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
ginkgo.It("Proxy Bandwidth Limit", func() { ginkgo.It("Proxy Bandwidth Limit by Client", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@ -40,8 +42,64 @@ var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) { framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) {
r.Body([]byte(content)).Timeout(30 * time.Second) r.Body([]byte(content)).Timeout(30 * time.Second)
}).ExpectResp([]byte(content)).Ensure() }).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())
}) })
}) })

View File

@ -69,7 +69,7 @@ func (f *Framework) RunFrps(args ...string) (*process.Process, string, error) {
return p, p.StdOutput(), err return p, p.StdOutput(), err
} }
// sleep for a while to get std output // sleep for a while to get std output
time.Sleep(500 * time.Millisecond) time.Sleep(time.Second)
return p, p.StdOutput(), nil return p, p.StdOutput(), nil
} }
@ -80,7 +80,7 @@ func (f *Framework) RunFrpc(args ...string) (*process.Process, string, error) {
if err != nil { if err != nil {
return p, p.StdOutput(), err return p, p.StdOutput(), err
} }
time.Sleep(500 * time.Millisecond) time.Sleep(time.Second)
return p, p.StdOutput(), nil return p, p.StdOutput(), nil
} }