support range format ProtoPort

This commit is contained in:
HynoR 2024-03-11 15:35:12 +08:00
parent 02baab148a
commit ee056deaad
2 changed files with 115 additions and 0 deletions

View file

@ -107,6 +107,11 @@ type GeoLoader interface {
func Compile[O Outbound](rules []TextRule, outbounds map[string]O,
cacheSize int, geoLoader GeoLoader,
) (CompiledRuleSet[O], error) {
for _, rule := range rules {
if extra, rangeLen := splitPortRangeRules(&rule); rangeLen > 0 {
rules = append(rules, extra...)
}
}
compiledRules := make([]compiledRule[O], len(rules))
for i, rule := range rules {
outbound, ok := outbounds[strings.ToLower(rule.Outbound)]
@ -282,3 +287,40 @@ func parseGeoSiteName(s string) (string, []string) {
}
return base, attrs
}
func splitPortRangeRules(rule *TextRule) ([]TextRule, int) {
protoPort := strings.ToLower(rule.ProtoPort)
if protoPort == "" || protoPort == "*" || protoPort == "*/*" {
return nil, 0
}
parts := strings.SplitN(protoPort, "/", 2)
if len(parts) != 2 {
return nil, 0
}
ports := strings.SplitN(strings.TrimSpace(parts[1]), "-", 2)
if len(ports) != 2 {
return nil, 0
}
minPorts, err := strconv.Atoi(ports[0])
if err != nil {
return nil, 0
}
maxPorts, err := strconv.Atoi(ports[1])
if err != nil {
return nil, 0
}
portLength := maxPorts - minPorts
if portLength <= 0 || minPorts == 0 {
return nil, 0
}
// port range: minPort < port <= MaxPort
extraRules := make([]TextRule, portLength)
for i := range extraRules {
extraRules[i] = *rule
extraRules[i].ProtoPort = fmt.Sprintf("%s/%d", parts[0], minPorts+i+1)
}
rule.ProtoPort = fmt.Sprintf("%s/%d", parts[0], minPorts)
return extraRules, portLength
}

View file

@ -303,3 +303,76 @@ func Test_parseGeoSiteName(t *testing.T) {
})
}
}
func Test_splitPortRangeRules(t *testing.T) {
rules := []TextRule{
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "tcp/1-1024",
HijackAddress: "",
},
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "udp/1-1024",
HijackAddress: "",
},
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "*/1-1024",
HijackAddress: "",
},
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "tcp/0-222",
HijackAddress: "",
},
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "tcp/1024",
HijackAddress: "",
},
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "tcp/-1-9",
HijackAddress: "",
},
{
Outbound: "ob1",
Address: "1.2.3.4",
ProtoPort: "tcp/6881-6889",
HijackAddress: "",
},
}
_, rangeLen0 := splitPortRangeRules(&rules[0])
assert.Equal(t, 1023, rangeLen0)
_, rangeLen1 := splitPortRangeRules(&rules[1])
assert.Equal(t, 1023, rangeLen1)
_, rangeLen2 := splitPortRangeRules(&rules[2])
assert.Equal(t, 1023, rangeLen2)
_, rangeLen3 := splitPortRangeRules(&rules[3])
assert.Equal(t, 0, rangeLen3)
_, rangeLen4 := splitPortRangeRules(&rules[4])
assert.Equal(t, 0, rangeLen4)
_, rangeLen5 := splitPortRangeRules(&rules[5])
assert.Equal(t, 0, rangeLen5)
rangeRule, _ := splitPortRangeRules(&rules[6])
for _, rule := range rangeRule {
assert.Equal(t, "ob1", rule.Outbound)
assert.Equal(t, "1.2.3.4", rule.Address)
t.Log(rule.ProtoPort)
assert.Equal(t, "", rule.HijackAddress)
}
assert.Equal(t, "tcp/6881", rules[6].ProtoPort)
}