diff --git a/conf/frps.ini b/conf/frps.ini index f4752b4..95a1010 100644 --- a/conf/frps.ini +++ b/conf/frps.ini @@ -15,6 +15,7 @@ log_max_days = 3 # if you enable privilege mode, frpc can create a proxy without pre-configure in frps when privilege_token is correct privilege_mode = true privilege_token = 12345678 +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 = 100 diff --git a/src/frp/cmd/frps/control.go b/src/frp/cmd/frps/control.go index 5fc0dbf..74325f7 100644 --- a/src/frp/cmd/frps/control.go +++ b/src/frp/cmd/frps/control.go @@ -194,6 +194,7 @@ func msgSender(s *server.ProxyServer, c *conn.Conn, msgSendChan chan interface{} // if success, ret equals 0, otherwise greater than 0 func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { ret = 1 + // check if PrivilegeMode is enabled if req.PrivilegeMode && !server.PrivilegeMode { info = fmt.Sprintf("ProxyName [%s], PrivilegeMode is disabled in frps", req.ProxyName) log.Warn("info") @@ -247,6 +248,16 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { if req.Type == consts.NewCtlConn { if req.PrivilegeMode { s = server.NewProxyServerFromCtlMsg(req) + // we check listen_port if privilege_allow_ports are set + // and PrivilegeMode is enabled + if s.Type == "tcp" { + _, ok := server.PrivilegeAllowPorts[s.ListenPort] + if !ok { + info = fmt.Sprintf("ProxyName [%s], remote_port [%d] isn't allowed", req.ProxyName, s.ListenPort) + log.Warn(info) + return + } + } err := server.CreateProxy(s) if err != nil { info = fmt.Sprintf("ProxyName [%s], %v", req.ProxyName, err) @@ -255,12 +266,6 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { } } - if s.Status == consts.Working { - info = fmt.Sprintf("ProxyName [%s], already in use", req.ProxyName) - log.Warn(info) - return - } - // check if vhost_port is set if s.Type == "http" && server.VhostHttpMuxer == nil { info = fmt.Sprintf("ProxyName [%s], type [http] not support when vhost_http_port is not set", req.ProxyName) @@ -285,6 +290,12 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string) { s.PoolCount = req.PoolCount } + if s.Status == consts.Working { + info = fmt.Sprintf("ProxyName [%s], already in use", req.ProxyName) + log.Warn(info) + return + } + // start proxy and listen for user connections, no block err := s.Start(c) if err != nil { diff --git a/src/frp/models/server/config.go b/src/frp/models/server/config.go index 67f6488..7de55bc 100644 --- a/src/frp/models/server/config.go +++ b/src/frp/models/server/config.go @@ -30,21 +30,24 @@ import ( // common config var ( - ConfigFile string = "./frps.ini" - BindAddr string = "0.0.0.0" - BindPort int64 = 7000 - VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol - VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol - DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available - LogFile string = "console" - LogWay string = "console" // console or file - LogLevel string = "info" - LogMaxDays int64 = 3 - PrivilegeMode bool = false - PrivilegeToken string = "" - MaxPoolCount int64 = 100 - HeartBeatTimeout int64 = 90 - UserConnTimeout int64 = 10 + ConfigFile string = "./frps.ini" + BindAddr string = "0.0.0.0" + BindPort int64 = 7000 + VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol + VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol + DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available + LogFile string = "console" + LogWay string = "console" // console or file + LogLevel string = "info" + LogMaxDays int64 = 3 + PrivilegeMode bool = false + PrivilegeToken string = "" + + // if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected + PrivilegeAllowPorts map[int64]struct{} + MaxPoolCount int64 = 100 + HeartBeatTimeout int64 = 90 + UserConnTimeout int64 = 10 VhostHttpMuxer *vhost.HttpMuxer VhostHttpsMuxer *vhost.HttpsMuxer @@ -155,6 +158,43 @@ func loadCommonConf(confFile string) error { } else { return fmt.Errorf("Parse conf error: privilege_token must be set if privilege_mode is enabled") } + + PrivilegeAllowPorts = make(map[int64]struct{}) + tmpStr, ok = conf.Get("common", "privilege_allow_ports") + if ok { + // for example: 1000-2000,2001,2002,3000-4000 + portRanges := strings.Split(tmpStr, ",") + for _, portRangeStr := range portRanges { + // 1000-2000 or 2001 + portArray := strings.Split(portRangeStr, "-") + // lenght: only 1 or 2 is correct + rangeType := len(portArray) + if rangeType == 1 { + singlePort, err := strconv.ParseInt(portArray[0], 10, 64) + if err != nil { + return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", err) + } + PrivilegeAllowPorts[singlePort] = struct{}{} + } else if rangeType == 2 { + min, err := strconv.ParseInt(portArray[0], 10, 64) + if err != nil { + return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", err) + } + max, err := strconv.ParseInt(portArray[1], 10, 64) + if err != nil { + return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", err) + } + if max < min { + return fmt.Errorf("Parse conf error: privilege_allow_ports range incorrect") + } + for i := min; i <= max; i++ { + PrivilegeAllowPorts[i] = struct{}{} + } + } else { + return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect") + } + } + } } tmpStr, ok = conf.Get("common", "max_pool_count")