Skip to content

Commit

Permalink
frps: new params max_ports_per_client
Browse files Browse the repository at this point in the history
  • Loading branch information
fatedier committed Jan 26, 2018
1 parent 637ddbc commit 8e719ff
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 8 deletions.
2 changes: 1 addition & 1 deletion client/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ func (ctl *Control) worker() {
go ctl.reader()

// start all configured proxies
ctl.pm.CheckAndStartProxy([]string{ProxyStatusNew})
ctl.pm.CheckAndStartProxy([]string{ProxyStatusNew, ProxyStatusClosed})

checkProxyTicker.Stop()
checkProxyTicker = time.NewTicker(checkInterval)
Expand Down
3 changes: 3 additions & 0 deletions conf/frps_full.ini
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ privilege_allow_ports = 2000-3000,3001,3003,4000-50000
# pool_count in each proxy will change to max_pool_count if they exceed the maximum value
max_pool_count = 5

# max ports can be used for each client, default value is 0 means no limit
max_ports_per_client = 0

# authentication_timeout means the timeout interval (seconds) when the frpc connects frps
# if authentication_timeout is zero, the time is not verified, default is 900s
authentication_timeout = 900
Expand Down
26 changes: 24 additions & 2 deletions models/config/server_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type ServerCommonConf struct {

PrivilegeAllowPorts map[int]struct{}
MaxPoolCount int64
MaxPortsPerClient int64
HeartBeatTimeout int64
UserConnTimeout int64
}
Expand Down Expand Up @@ -89,6 +90,7 @@ func GetDefaultServerCommonConf() *ServerCommonConf {
TcpMux: true,
PrivilegeAllowPorts: make(map[int]struct{}),
MaxPoolCount: 5,
MaxPortsPerClient: 0,
HeartBeatTimeout: 90,
UserConnTimeout: 10,
}
Expand Down Expand Up @@ -254,12 +256,32 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {

tmpStr, ok = conf.Get("common", "max_pool_count")
if ok {
v, err = strconv.ParseInt(tmpStr, 10, 64)
if err == nil && v >= 0 {
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
err = fmt.Errorf("Parse conf error: invalid max_pool_count")
return
} else {
if v < 0 {
err = fmt.Errorf("Parse conf error: invalid max_pool_count")
return
}
cfg.MaxPoolCount = v
}
}

tmpStr, ok = conf.Get("common", "max_ports_per_client")
if ok {
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
err = fmt.Errorf("Parse conf error: invalid max_ports_per_client")
return
} else {
if v < 0 {
err = fmt.Errorf("Parse conf error: invalid max_ports_per_client")
return
}
cfg.MaxPortsPerClient = v
}
}

tmpStr, ok = conf.Get("common", "authentication_timeout")
if ok {
v, errRet := strconv.ParseInt(tmpStr, 10, 64)
Expand Down
31 changes: 30 additions & 1 deletion server/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ type Control struct {
// pool count
poolCount int

// ports used, for limitations
portsUsedNum int

// last time got the Ping message
lastPing time.Time

Expand Down Expand Up @@ -84,6 +87,7 @@ func NewControl(svr *Service, ctlConn net.Conn, loginMsg *msg.Login) *Control {
workConnCh: make(chan net.Conn, loginMsg.PoolCount+10),
proxies: make(map[string]Proxy),
poolCount: loginMsg.PoolCount,
portsUsedNum: 0,
lastPing: time.Now(),
runId: loginMsg.RunId,
status: consts.Working,
Expand Down Expand Up @@ -348,6 +352,26 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
return remoteAddr, err
}

// Check ports used number in each client
if config.ServerCommonCfg.MaxPortsPerClient > 0 {
ctl.mu.Lock()
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(config.ServerCommonCfg.MaxPortsPerClient) {
ctl.mu.Unlock()
err = fmt.Errorf("exceed the max_ports_per_client")
return
}
ctl.portsUsedNum = ctl.portsUsedNum + pxy.GetUsedPortsNum()
ctl.mu.Unlock()

defer func() {
if err != nil {
ctl.mu.Lock()
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
ctl.mu.Unlock()
}
}()
}

remoteAddr, err = pxy.Run()
if err != nil {
return
Expand All @@ -371,16 +395,21 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err

func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
ctl.mu.Lock()
defer ctl.mu.Unlock()

pxy, ok := ctl.proxies[closeMsg.ProxyName]
if !ok {
ctl.mu.Unlock()
return
}

if config.ServerCommonCfg.MaxPortsPerClient > 0 {
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
}
pxy.Close()
ctl.svr.DelProxy(pxy.GetName())
delete(ctl.proxies, closeMsg.ProxyName)
ctl.mu.Unlock()

StatsCloseProxy(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType)
return
}
17 changes: 13 additions & 4 deletions server/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ type Proxy interface {
GetName() string
GetConf() config.ProxyConf
GetWorkConnFromPool() (workConn frpNet.Conn, err error)
GetUsedPortsNum() int
Close()
log.Logger
}

type BaseProxy struct {
name string
ctl *Control
listeners []frpNet.Listener
mu sync.RWMutex
name string
ctl *Control
listeners []frpNet.Listener
usedPortsNum int

mu sync.RWMutex
log.Logger
}

Expand All @@ -60,6 +63,10 @@ func (pxy *BaseProxy) GetControl() *Control {
return pxy.ctl
}

func (pxy *BaseProxy) GetUsedPortsNum() int {
return pxy.usedPortsNum
}

func (pxy *BaseProxy) Close() {
pxy.Info("proxy closing")
for _, l := range pxy.listeners {
Expand Down Expand Up @@ -126,6 +133,7 @@ func NewProxy(ctl *Control, pxyConf config.ProxyConf) (pxy Proxy, err error) {
}
switch cfg := pxyConf.(type) {
case *config.TcpProxyConf:
basePxy.usedPortsNum = 1
pxy = &TcpProxy{
BaseProxy: basePxy,
cfg: cfg,
Expand All @@ -141,6 +149,7 @@ func NewProxy(ctl *Control, pxyConf config.ProxyConf) (pxy Proxy, err error) {
cfg: cfg,
}
case *config.UdpProxyConf:
basePxy.usedPortsNum = 1
pxy = &UdpProxy{
BaseProxy: basePxy,
cfg: cfg,
Expand Down

0 comments on commit 8e719ff

Please sign in to comment.