diff --git a/README.md b/README.md index a02d0a5a..86ba3020 100644 --- a/README.md +++ b/README.md @@ -717,10 +717,13 @@ type = tcp local_port = 22 remote_port = 6000 bandwidth_limit = 1MB +bandwidth_limit_mode = server ``` Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`. +Set `bandwidth_limit_mode` to `client` or `server` to limit bandwidth on the client or server side. Default is `client`. + ### TCP Stream Multiplexing frp supports tcp stream multiplexing since v0.10.0 like HTTP2 Multiplexing, in which case all logic connections to the same frpc are multiplexed into the same TCP connection. diff --git a/client/proxy/proxy.go b/client/proxy/proxy.go index 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/conf/frpc_full.ini b/conf/frpc_full.ini index 8e39de1c..99ac0780 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 = server # 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/pkg/config/client_test.go b/pkg/config/client_test.go index 9cf8c805..8f189207 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", diff --git a/pkg/config/proxy.go b/pkg/config/proxy.go index 1c9d2ad4..359eda81 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 BandwidthLimitMode `ini:"bandwidth_limit_mode" json:"bandwidth_limit_mode"` // meta info for each proxy Metas map[string]string `ini:"-" json:"metas"` @@ -335,6 +339,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 } @@ -365,6 +370,15 @@ func (cfg *BaseProxyConf) decorate(prefix string, name string, section *ini.Sect } } + if bandwidthMode, err := section.GetKey("bandwidth_limit_mode"); err == nil { + cfg.BandwidthLimitMode, err = NewBandwidthLimitMode(bandwidthMode.String()) + if err != nil { + return err + } + } else { + cfg.BandwidthLimitMode = BandwidthLimitModeClient + } + // plugin_xxx cfg.LocalSvrConf.PluginParams = GetMapByPrefix(section.KeysHash(), "plugin_") @@ -390,6 +404,7 @@ func (cfg *BaseProxyConf) marshalToMsg(pMsg *msg.NewProxy) { pMsg.UseEncryption = cfg.UseEncryption pMsg.UseCompression = cfg.UseCompression pMsg.BandwidthLimit = cfg.BandwidthLimit.String() + pMsg.BandwidthLimitMode = cfg.BandwidthLimitMode.String() pMsg.Group = cfg.Group pMsg.GroupKey = cfg.GroupKey pMsg.Metas = cfg.Metas @@ -401,6 +416,7 @@ func (cfg *BaseProxyConf) unmarshalFromMsg(pMsg *msg.NewProxy) { cfg.UseEncryption = pMsg.UseEncryption cfg.UseCompression = pMsg.UseCompression cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit) + cfg.BandwidthLimitMode, _ = NewBandwidthLimitMode(pMsg.BandwidthLimitMode) cfg.Group = pMsg.Group cfg.GroupKey = pMsg.GroupKey cfg.Metas = pMsg.Metas diff --git a/pkg/config/proxy_test.go b/pkg/config/proxy_test.go index c603dd7f..7a3b4155 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", diff --git a/pkg/config/types.go b/pkg/config/types.go index 28a0e46d..93ef9302 100644 --- a/pkg/config/types.go +++ b/pkg/config/types.go @@ -120,3 +120,24 @@ func (q *BandwidthQuantity) MarshalJSON() ([]byte, error) { func (q *BandwidthQuantity) Bytes() int64 { return q.i } + +type BandwidthLimitMode string + +const ( + BandwidthLimitModeClient BandwidthLimitMode = "client" + BandwidthLimitModeServer BandwidthLimitMode = "server" +) + +// Create a new BandwidthLimitMode from a string. Default to "client". +func NewBandwidthLimitMode(s string) (BandwidthLimitMode, error) { + switch BandwidthLimitMode(s) { + case BandwidthLimitModeClient, BandwidthLimitModeServer: + return BandwidthLimitMode(s), nil + default: + return BandwidthLimitModeClient, errors.New("invalid bandwidth_limit_mode") + } +} + +func (m BandwidthLimitMode) String() string { + return string(m) +} diff --git a/pkg/msg/msg.go b/pkg/msg/msg.go index 194f0423..33e8fe5d 100644 --- a/pkg/msg/msg.go +++ b/pkg/msg/msg.go @@ -85,14 +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"` - BandwidthLimit string `json:"bandwidth_limit,omitempty"` - Group string `json:"group,omitempty"` - GroupKey string `json:"group_key,omitempty"` - Metas map[string]string `json:"metas,omitempty"` + ProxyName string `json:"proxy_name,omitempty"` + ProxyType string `json:"proxy_type,omitempty"` + UseEncryption bool `json:"use_encryption,omitempty"` + UseCompression bool `json:"use_compression,omitempty"` + BandwidthLimit string `json:"bandwidth_limit,omitempty"` + BandwidthLimitMode string `json:"bandwidth_limit_mode,omitempty"` + Group string `json:"group,omitempty"` + GroupKey string `json:"group_key,omitempty"` + Metas map[string]string `json:"metas,omitempty"` // tcp and udp only RemotePort int `json:"remote_port,omitempty"` diff --git a/server/proxy/proxy.go b/server/proxy/proxy.go index 9d46b96e..0681370f 100644 --- a/server/proxy/proxy.go +++ b/server/proxy/proxy.go @@ -194,7 +194,7 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso var limiter *rate.Limiter limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() - if limitBytes > 0 { + if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeServer { limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes)) }