frps: new params max_ports_per_client

This commit is contained in:
fatedier 2018-01-26 14:56:55 +08:00
parent 637ddbce1f
commit 8e719ff0ff
5 changed files with 71 additions and 8 deletions

View File

@ -427,7 +427,7 @@ func (ctl *Control) worker() {
go ctl.reader() go ctl.reader()
// start all configured proxies // start all configured proxies
ctl.pm.CheckAndStartProxy([]string{ProxyStatusNew}) ctl.pm.CheckAndStartProxy([]string{ProxyStatusNew, ProxyStatusClosed})
checkProxyTicker.Stop() checkProxyTicker.Stop()
checkProxyTicker = time.NewTicker(checkInterval) checkProxyTicker = time.NewTicker(checkInterval)

View File

@ -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 # pool_count in each proxy will change to max_pool_count if they exceed the maximum value
max_pool_count = 5 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 # 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 # if authentication_timeout is zero, the time is not verified, default is 900s
authentication_timeout = 900 authentication_timeout = 900

View File

@ -59,6 +59,7 @@ type ServerCommonConf struct {
PrivilegeAllowPorts map[int]struct{} PrivilegeAllowPorts map[int]struct{}
MaxPoolCount int64 MaxPoolCount int64
MaxPortsPerClient int64
HeartBeatTimeout int64 HeartBeatTimeout int64
UserConnTimeout int64 UserConnTimeout int64
} }
@ -89,6 +90,7 @@ func GetDefaultServerCommonConf() *ServerCommonConf {
TcpMux: true, TcpMux: true,
PrivilegeAllowPorts: make(map[int]struct{}), PrivilegeAllowPorts: make(map[int]struct{}),
MaxPoolCount: 5, MaxPoolCount: 5,
MaxPortsPerClient: 0,
HeartBeatTimeout: 90, HeartBeatTimeout: 90,
UserConnTimeout: 10, UserConnTimeout: 10,
} }
@ -254,12 +256,32 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
tmpStr, ok = conf.Get("common", "max_pool_count") tmpStr, ok = conf.Get("common", "max_pool_count")
if ok { if ok {
v, err = strconv.ParseInt(tmpStr, 10, 64) if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
if err == nil && v >= 0 { 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 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") tmpStr, ok = conf.Get("common", "authentication_timeout")
if ok { if ok {
v, errRet := strconv.ParseInt(tmpStr, 10, 64) v, errRet := strconv.ParseInt(tmpStr, 10, 64)

View File

@ -55,6 +55,9 @@ type Control struct {
// pool count // pool count
poolCount int poolCount int
// ports used, for limitations
portsUsedNum int
// last time got the Ping message // last time got the Ping message
lastPing time.Time lastPing time.Time
@ -84,6 +87,7 @@ func NewControl(svr *Service, ctlConn net.Conn, loginMsg *msg.Login) *Control {
workConnCh: make(chan net.Conn, loginMsg.PoolCount+10), workConnCh: make(chan net.Conn, loginMsg.PoolCount+10),
proxies: make(map[string]Proxy), proxies: make(map[string]Proxy),
poolCount: loginMsg.PoolCount, poolCount: loginMsg.PoolCount,
portsUsedNum: 0,
lastPing: time.Now(), lastPing: time.Now(),
runId: loginMsg.RunId, runId: loginMsg.RunId,
status: consts.Working, status: consts.Working,
@ -348,6 +352,26 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
return remoteAddr, 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() remoteAddr, err = pxy.Run()
if err != nil { if err != nil {
return return
@ -371,16 +395,21 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) { func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
ctl.mu.Lock() ctl.mu.Lock()
defer ctl.mu.Unlock()
pxy, ok := ctl.proxies[closeMsg.ProxyName] pxy, ok := ctl.proxies[closeMsg.ProxyName]
if !ok { if !ok {
ctl.mu.Unlock()
return return
} }
if config.ServerCommonCfg.MaxPortsPerClient > 0 {
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
}
pxy.Close() pxy.Close()
ctl.svr.DelProxy(pxy.GetName()) ctl.svr.DelProxy(pxy.GetName())
delete(ctl.proxies, closeMsg.ProxyName) delete(ctl.proxies, closeMsg.ProxyName)
ctl.mu.Unlock()
StatsCloseProxy(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType) StatsCloseProxy(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType)
return return
} }

View File

@ -40,15 +40,18 @@ type Proxy interface {
GetName() string GetName() string
GetConf() config.ProxyConf GetConf() config.ProxyConf
GetWorkConnFromPool() (workConn frpNet.Conn, err error) GetWorkConnFromPool() (workConn frpNet.Conn, err error)
GetUsedPortsNum() int
Close() Close()
log.Logger log.Logger
} }
type BaseProxy struct { type BaseProxy struct {
name string name string
ctl *Control ctl *Control
listeners []frpNet.Listener listeners []frpNet.Listener
mu sync.RWMutex usedPortsNum int
mu sync.RWMutex
log.Logger log.Logger
} }
@ -60,6 +63,10 @@ func (pxy *BaseProxy) GetControl() *Control {
return pxy.ctl return pxy.ctl
} }
func (pxy *BaseProxy) GetUsedPortsNum() int {
return pxy.usedPortsNum
}
func (pxy *BaseProxy) Close() { func (pxy *BaseProxy) Close() {
pxy.Info("proxy closing") pxy.Info("proxy closing")
for _, l := range pxy.listeners { for _, l := range pxy.listeners {
@ -126,6 +133,7 @@ func NewProxy(ctl *Control, pxyConf config.ProxyConf) (pxy Proxy, err error) {
} }
switch cfg := pxyConf.(type) { switch cfg := pxyConf.(type) {
case *config.TcpProxyConf: case *config.TcpProxyConf:
basePxy.usedPortsNum = 1
pxy = &TcpProxy{ pxy = &TcpProxy{
BaseProxy: basePxy, BaseProxy: basePxy,
cfg: cfg, cfg: cfg,
@ -141,6 +149,7 @@ func NewProxy(ctl *Control, pxyConf config.ProxyConf) (pxy Proxy, err error) {
cfg: cfg, cfg: cfg,
} }
case *config.UdpProxyConf: case *config.UdpProxyConf:
basePxy.usedPortsNum = 1
pxy = &UdpProxy{ pxy = &UdpProxy{
BaseProxy: basePxy, BaseProxy: basePxy,
cfg: cfg, cfg: cfg,