Skip to content

Commit

Permalink
Merge pull request #1542 from fatedier/dev
Browse files Browse the repository at this point in the history
bump version to v0.30.0
  • Loading branch information
fatedier authored Nov 28, 2019
2 parents adc3adc + df18375 commit 75f3bce
Show file tree
Hide file tree
Showing 21 changed files with 933 additions and 14 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ frp also has a P2P connect mode.
* [Get proxy status from client](#get-proxy-status-from-client)
* [Only allowing certain ports on the server](#only-allowing-certain-ports-on-the-server)
* [Port Reuse](#port-reuse)
* [Bandwidth Limit](#bandwidth-limit)
* [For Each Proxy](#for-each-proxy)
* [TCP Stream Multiplexing](#tcp-stream-multiplexing)
* [Support KCP Protocol](#support-kcp-protocol)
* [Connection Pooling](#connection-pooling)
Expand Down Expand Up @@ -495,6 +497,21 @@ allow_ports = 2000-3000,3001,3003,4000-50000

We would like to try to allow multiple proxies bind a same remote port with different protocols in the future.

### Bandwidth Limit

#### For Each Proxy

```ini
# frpc.ini
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwidth_limit = 1MB
```

Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`.

### 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.
Expand Down
19 changes: 19 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp
* [客户端查看代理状态](#客户端查看代理状态)
* [端口白名单](#端口白名单)
* [端口复用](#端口复用)
* [限速](#限速)
* [代理限速](#代理限速)
* [TCP 多路复用](#tcp-多路复用)
* [底层通信可选 kcp 协议](#底层通信可选-kcp-协议)
* [连接池](#连接池)
Expand Down Expand Up @@ -531,6 +533,23 @@ allow_ports = 2000-3000,3001,3003,4000-50000

后续会尝试允许多个 proxy 绑定同一个远端端口的不同协议。

### 限速

#### 代理限速

目前支持在客户端的代理配置中设置代理级别的限速,限制单个 proxy 可以占用的带宽。

```ini
# frpc.ini
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwith_limit = 1MB
```

在代理配置中增加 `bandwith_limit` 字段启用此功能,目前仅支持 `MB``KB` 单位。

### TCP 多路复用

从 v0.10.0 版本开始,客户端和服务器端之间的连接支持多路复用,不再需要为每一个用户请求创建一个连接,使连接建立的延迟降低,并且避免了大量文件描述符的占用,使 frp 可以承载更高的并发数。
Expand Down
2 changes: 2 additions & 0 deletions assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func ReadFile(file string) (content string, err error) {
if err != nil {
return content, err
}
defer file.Close()
buf, err := ioutil.ReadAll(file)
if err != nil {
return content, err
Expand All @@ -65,6 +66,7 @@ func ReadFile(file string) (content string, err error) {
if err != nil {
return content, err
}
defer file.Close()
buf, err := ioutil.ReadAll(file)
if err != nil {
return content, err
Expand Down
42 changes: 32 additions & 10 deletions client/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/models/plugin"
"github.com/fatedier/frp/models/proto/udp"
"github.com/fatedier/frp/utils/limit"
frpNet "github.com/fatedier/frp/utils/net"
"github.com/fatedier/frp/utils/xlog"

Expand All @@ -38,6 +39,7 @@ import (
"github.com/fatedier/golib/pool"
fmux "github.com/hashicorp/yamux"
pp "github.com/pires/go-proxyproto"
"golang.org/x/time/rate"
)

// Proxy defines how to handle work connections for different proxy type.
Expand All @@ -51,9 +53,16 @@ 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 {
limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
}

baseProxy := BaseProxy{
clientCfg: clientCfg,
serverUDPPort: serverUDPPort,
limiter: limiter,
xl: xlog.FromContextSafe(ctx),
ctx: ctx,
}
Expand Down Expand Up @@ -96,6 +105,7 @@ type BaseProxy struct {
closed bool
clientCfg config.ClientCommonConf
serverUDPPort int
limiter *rate.Limiter

mu sync.RWMutex
xl *xlog.Logger
Expand Down Expand Up @@ -127,8 +137,8 @@ func (pxy *TcpProxy) Close() {
}

func (pxy *TcpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(pxy.clientCfg.Token), m)
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, pxy.limiter,
conn, []byte(pxy.clientCfg.Token), m)
}

// HTTP
Expand Down Expand Up @@ -156,8 +166,8 @@ func (pxy *HttpProxy) Close() {
}

func (pxy *HttpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(pxy.clientCfg.Token), m)
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, pxy.limiter,
conn, []byte(pxy.clientCfg.Token), m)
}

// HTTPS
Expand Down Expand Up @@ -185,8 +195,8 @@ func (pxy *HttpsProxy) Close() {
}

func (pxy *HttpsProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(pxy.clientCfg.Token), m)
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, pxy.limiter,
conn, []byte(pxy.clientCfg.Token), m)
}

// STCP
Expand Down Expand Up @@ -214,8 +224,8 @@ func (pxy *StcpProxy) Close() {
}

func (pxy *StcpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(pxy.clientCfg.Token), m)
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, pxy.limiter,
conn, []byte(pxy.clientCfg.Token), m)
}

// XTCP
Expand Down Expand Up @@ -360,7 +370,7 @@ func (pxy *XtcpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
return
}

HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf,
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, pxy.limiter,
muxConn, []byte(pxy.cfg.Sk), m)
}

Expand Down Expand Up @@ -429,6 +439,13 @@ func (pxy *UdpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
// close resources releated with old workConn
pxy.Close()

if pxy.limiter != nil {
rwc := frpIo.WrapReadWriteCloser(limit.NewReader(conn, pxy.limiter), limit.NewWriter(conn, pxy.limiter), func() error {
return conn.Close()
})
conn = frpNet.WrapReadWriteCloserToConn(rwc, conn)
}

pxy.mu.Lock()
pxy.workConn = conn
pxy.readCh = make(chan *msg.UdpPacket, 1024)
Expand Down Expand Up @@ -491,13 +508,18 @@ func (pxy *UdpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {

// Common handler for tcp work connections.
func HandleTcpWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin,
baseInfo *config.BaseProxyConf, workConn net.Conn, encKey []byte, m *msg.StartWorkConn) {
baseInfo *config.BaseProxyConf, limiter *rate.Limiter, workConn net.Conn, encKey []byte, m *msg.StartWorkConn) {
xl := xlog.FromContextSafe(ctx)
var (
remote io.ReadWriteCloser
err error
)
remote = workConn
if limiter != nil {
remote = frpIo.WrapReadWriteCloser(limit.NewReader(workConn, limiter), limit.NewWriter(workConn, limiter), func() error {
return workConn.Close()
})
}

xl.Trace("handle tcp work connection, use_encryption: %t, use_compression: %t",
baseInfo.UseEncryption, baseInfo.UseCompression)
Expand Down
10 changes: 10 additions & 0 deletions conf/frpc_full.ini
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ tls_enable = true
type = tcp
local_ip = 127.0.0.1
local_port = 22
# limit bandwith for this proxy, unit is KB and MB
bandwith_limit = 1MB
# 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
Expand Down Expand Up @@ -205,6 +207,14 @@ plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp

[plugin_http2https]
type = http
custom_domains = test.yourdomain.com
plugin = http2https
plugin_local_addr = 127.0.0.1:443
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp

[secret_tcp]
# If the type is secret tcp, remote_port is useless
# Who want to connect local port should deploy another frpc with stcp proxy and role is visitor
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ require (
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
golang.org/x/text v0.3.2 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
17 changes: 14 additions & 3 deletions models/config/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ type BaseProxyConf struct {
// values include "v1", "v2", and "". If the value is "", a protocol
// version will be automatically selected. By default, this value is "".
ProxyProtocolVersion string `json:"proxy_protocol_version"`

// BandwidthLimit limit the proxy bandwidth
// 0 means no limit
BandwidthLimit BandwidthQuantity `json:"bandwidth_limit"`

LocalSvrConf
HealthCheckConf
}
Expand All @@ -140,7 +145,8 @@ func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool {
cfg.UseCompression != cmp.UseCompression ||
cfg.Group != cmp.Group ||
cfg.GroupKey != cmp.GroupKey ||
cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion {
cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion ||
cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) {
return false
}
if !cfg.LocalSvrConf.compare(&cmp.LocalSvrConf) {
Expand All @@ -165,6 +171,7 @@ func (cfg *BaseProxyConf) UnmarshalFromIni(prefix string, name string, section i
var (
tmpStr string
ok bool
err error
)
cfg.ProxyName = prefix + name
cfg.ProxyType = section["type"]
Expand All @@ -183,11 +190,15 @@ func (cfg *BaseProxyConf) UnmarshalFromIni(prefix string, name string, section i
cfg.GroupKey = section["group_key"]
cfg.ProxyProtocolVersion = section["proxy_protocol_version"]

if err := cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
if cfg.BandwidthLimit, err = NewBandwidthQuantity(section["bandwidth_limit"]); err != nil {
return err
}

if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
return err
}

if err := cfg.HealthCheckConf.UnmarshalFromIni(prefix, name, section); err != nil {
if err = cfg.HealthCheckConf.UnmarshalFromIni(prefix, name, section); err != nil {
return err
}

Expand Down
Loading

0 comments on commit 75f3bce

Please sign in to comment.