mirror of https://github.com/fatedier/frp
new feature: range section for mapping range ports
parent
eede31c064
commit
ce8fde793c
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"github.com/fatedier/frp/models/consts"
|
||||
"github.com/fatedier/frp/models/msg"
|
||||
"github.com/fatedier/frp/utils/util"
|
||||
|
||||
ini "github.com/vaughan0/go-ini"
|
||||
)
|
||||
|
@ -770,6 +771,38 @@ func (cfg *XtcpProxyConf) Check() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func ParseRangeSection(name string, section ini.Section) (sections map[string]ini.Section, err error) {
|
||||
localPorts, errRet := util.ParseRangeNumbers(section["local_port"])
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("Parse conf error: range section [%s] local_port invalid, %v", name, errRet)
|
||||
return
|
||||
}
|
||||
|
||||
remotePorts, errRet := util.ParseRangeNumbers(section["remote_port"])
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("Parse conf error: range section [%s] remote_port invalid, %v", name, errRet)
|
||||
return
|
||||
}
|
||||
if len(localPorts) != len(remotePorts) {
|
||||
err = fmt.Errorf("Parse conf error: range section [%s] local ports number should be same with remote ports number", name)
|
||||
return
|
||||
}
|
||||
if len(localPorts) == 0 {
|
||||
err = fmt.Errorf("Parse conf error: range section [%s] local_port and remote_port is necessary")
|
||||
return
|
||||
}
|
||||
|
||||
sections = make(map[string]ini.Section)
|
||||
for i, port := range localPorts {
|
||||
subName := fmt.Sprintf("%s_%d", name, i)
|
||||
subSection := copySection(section)
|
||||
subSection["local_port"] = fmt.Sprintf("%d", port)
|
||||
subSection["remote_port"] = fmt.Sprintf("%d", remotePorts[i])
|
||||
sections[subName] = subSection
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if len(startProxy) is 0, start all
|
||||
// otherwise just start proxies in startProxy map
|
||||
func LoadProxyConfFromFile(prefix string, conf ini.File, startProxy map[string]struct{}) (
|
||||
|
@ -786,22 +819,51 @@ func LoadProxyConfFromFile(prefix string, conf ini.File, startProxy map[string]s
|
|||
proxyConfs = make(map[string]ProxyConf)
|
||||
visitorConfs = make(map[string]ProxyConf)
|
||||
for name, section := range conf {
|
||||
if name == "common" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, shouldStart := startProxy[name]
|
||||
if name != "common" && (startAll || shouldStart) {
|
||||
if !startAll && !shouldStart {
|
||||
continue
|
||||
}
|
||||
|
||||
subSections := make(map[string]ini.Section)
|
||||
|
||||
if strings.HasPrefix(name, "range:") {
|
||||
// range section
|
||||
rangePrefix := strings.TrimSpace(strings.TrimPrefix(name, "range:"))
|
||||
subSections, err = ParseRangeSection(rangePrefix, section)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
subSections[name] = section
|
||||
}
|
||||
|
||||
for subName, subSection := range subSections {
|
||||
// some proxy or visotr configure may be used this prefix
|
||||
section["prefix"] = prefix
|
||||
cfg, err := NewProxyConfFromFile(name, section)
|
||||
subSection["prefix"] = prefix
|
||||
cfg, err := NewProxyConfFromFile(subName, subSection)
|
||||
if err != nil {
|
||||
return proxyConfs, visitorConfs, err
|
||||
}
|
||||
|
||||
role := section["role"]
|
||||
role := subSection["role"]
|
||||
if role == "visitor" {
|
||||
visitorConfs[prefix+name] = cfg
|
||||
visitorConfs[prefix+subName] = cfg
|
||||
} else {
|
||||
proxyConfs[prefix+name] = cfg
|
||||
proxyConfs[prefix+subName] = cfg
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func copySection(section ini.Section) (out ini.Section) {
|
||||
out = make(ini.Section)
|
||||
for k, v := range section {
|
||||
out[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"strings"
|
||||
|
||||
ini "github.com/vaughan0/go-ini"
|
||||
|
||||
"github.com/fatedier/frp/utils/util"
|
||||
)
|
||||
|
||||
var ServerCommonCfg *ServerCommonConf
|
||||
|
@ -238,43 +240,14 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||
allowPortsStr, ok := conf.Get("common", "privilege_allow_ports")
|
||||
if ok {
|
||||
// e.g. 1000-2000,2001,2002,3000-4000
|
||||
portRanges := strings.Split(allowPortsStr, ",")
|
||||
for _, portRangeStr := range portRanges {
|
||||
// 1000-2000 or 2001
|
||||
portArray := strings.Split(portRangeStr, "-")
|
||||
// length: only 1 or 2 is correct
|
||||
rangeType := len(portArray)
|
||||
if rangeType == 1 {
|
||||
// single port
|
||||
singlePort, errRet := strconv.ParseInt(portArray[0], 10, 64)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", errRet)
|
||||
return
|
||||
}
|
||||
cfg.PrivilegeAllowPorts[int(singlePort)] = struct{}{}
|
||||
} else if rangeType == 2 {
|
||||
// range ports
|
||||
min, errRet := strconv.ParseInt(portArray[0], 10, 64)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", errRet)
|
||||
return
|
||||
}
|
||||
max, errRet := strconv.ParseInt(portArray[1], 10, 64)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", errRet)
|
||||
return
|
||||
}
|
||||
if max < min {
|
||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports range incorrect")
|
||||
return
|
||||
}
|
||||
for i := min; i <= max; i++ {
|
||||
cfg.PrivilegeAllowPorts[int(i)] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect")
|
||||
return
|
||||
}
|
||||
ports, errRet := util.ParseRangeNumbers(allowPortsStr)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports: %v", errRet)
|
||||
return
|
||||
}
|
||||
|
||||
for _, port := range ports {
|
||||
cfg.PrivilegeAllowPorts[int(port)] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ import (
|
|||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RandId return a rand string used in frp.
|
||||
|
@ -54,3 +56,48 @@ func CanonicalAddr(host string, port int) (addr string) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParseRangeNumbers(rangeStr string) (numbers []int64, err error) {
|
||||
rangeStr = strings.TrimSpace(rangeStr)
|
||||
numbers = make([]int64, 0)
|
||||
// e.g. 1000-2000,2001,2002,3000-4000
|
||||
numRanges := strings.Split(rangeStr, ",")
|
||||
for _, numRangeStr := range numRanges {
|
||||
// 1000-2000 or 2001
|
||||
numArray := strings.Split(numRangeStr, "-")
|
||||
// length: only 1 or 2 is correct
|
||||
rangeType := len(numArray)
|
||||
if rangeType == 1 {
|
||||
// single number
|
||||
singleNum, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("range number is invalid, %v", errRet)
|
||||
return
|
||||
}
|
||||
numbers = append(numbers, singleNum)
|
||||
} else if rangeType == 2 {
|
||||
// range numbers
|
||||
min, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("range number is invalid, %v", errRet)
|
||||
return
|
||||
}
|
||||
max, errRet := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
|
||||
if errRet != nil {
|
||||
err = fmt.Errorf("range number is invalid, %v", errRet)
|
||||
return
|
||||
}
|
||||
if max < min {
|
||||
err = fmt.Errorf("range number is invalid")
|
||||
return
|
||||
}
|
||||
for i := min; i <= max; i++ {
|
||||
numbers = append(numbers, i)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("range number is invalid")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -20,3 +20,29 @@ func TestGetAuthKey(t *testing.T) {
|
|||
t.Log(key)
|
||||
assert.Equal("6df41a43725f0c770fd56379e12acf8c", key)
|
||||
}
|
||||
|
||||
func TestParseRangeNumbers(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
numbers, err := ParseRangeNumbers("2-5")
|
||||
if assert.NoError(err) {
|
||||
assert.Equal([]int64{2, 3, 4, 5}, numbers)
|
||||
}
|
||||
|
||||
numbers, err = ParseRangeNumbers("1")
|
||||
if assert.NoError(err) {
|
||||
assert.Equal([]int64{1}, numbers)
|
||||
}
|
||||
|
||||
numbers, err = ParseRangeNumbers("3-5,8")
|
||||
if assert.NoError(err) {
|
||||
assert.Equal([]int64{3, 4, 5, 8}, numbers)
|
||||
}
|
||||
|
||||
numbers, err = ParseRangeNumbers(" 3-5,8, 10-12 ")
|
||||
if assert.NoError(err) {
|
||||
assert.Equal([]int64{3, 4, 5, 8, 10, 11, 12}, numbers)
|
||||
}
|
||||
|
||||
_, err = ParseRangeNumbers("3-a")
|
||||
assert.Error(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue