diff --git a/rule/logic/common.go b/rule/logic/common.go index c15591e3..001447a4 100644 --- a/rule/logic/common.go +++ b/rule/logic/common.go @@ -5,7 +5,7 @@ import ( "github.com/Dreamacro/clash/common/collections" C "github.com/Dreamacro/clash/constant" RC "github.com/Dreamacro/clash/rule/common" - "github.com/Dreamacro/clash/rule/provider" + "github.com/Dreamacro/clash/rule/ruleparser" "regexp" "strings" ) @@ -60,59 +60,19 @@ func payloadToRule(subPayload string) (C.Rule, error) { return parseRule(tp, param[0], param[1:]) } -func parseRule(tp, payload string, params []string) (C.Rule, error) { - var ( - parseErr error - parsed C.Rule - ) - - switch tp { - case "DOMAIN": - parsed = RC.NewDomain(payload, "") - case "DOMAIN-SUFFIX": - parsed = RC.NewDomainSuffix(payload, "") - case "DOMAIN-KEYWORD": - parsed = RC.NewDomainKeyword(payload, "") - case "GEOSITE": - parsed, parseErr = RC.NewGEOSITE(payload, "") - case "GEOIP": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewGEOIP(payload, "", noResolve) - case "IP-CIDR", "IP-CIDR6": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPCIDR(payload, "", RC.WithIPCIDRNoResolve(noResolve)) - case "SRC-IP-CIDR": - parsed, parseErr = RC.NewIPCIDR(payload, "", RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) - case "IP-SUFFIX": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPSuffix(payload, "", false, noResolve) - case "SRC-IP-SUFFIX": - parsed, parseErr = RC.NewIPSuffix(payload, "", true, true) - case "SRC-PORT": - parsed, parseErr = RC.NewPort(payload, "", true) - case "DST-PORT": - parsed, parseErr = RC.NewPort(payload, "", false) - case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, "", true) - case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, "", false) - case "RULE-SET": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = provider.NewRuleSet(payload, "", noResolve) - case "UID": - parsed, parseErr = RC.NewUid(payload, "") - case "IN-TYPE": - parsed, parseErr = RC.NewInType(payload, "") - case "NOT": - parsed, parseErr = NewNOT(payload, "") - case "AND": - parsed, parseErr = NewAND(payload, "") - case "OR": - parsed, parseErr = NewOR(payload, "") - case "NETWORK": - parsed, parseErr = RC.NewNetworkType(payload, "") - default: - parsed, parseErr = nil, fmt.Errorf("unsupported rule type %s", tp) +func parseRule(tp, payload string, params []string) (parsed C.Rule, parseErr error) { + parsed, parseErr = ruleparser.ParseSameRule(tp, payload, "", params) + if ruleparser.IsUnsupported(parseErr) { + switch tp { + case "AND": + parsed, parseErr = NewAND(payload, "") + case "OR": + parsed, parseErr = NewOR(payload, "") + case "NOT": + parsed, parseErr = NewNOT(payload, "") + default: + parseErr = ruleparser.NewUnsupportedError(tp) + } } if parseErr != nil { diff --git a/rule/parser.go b/rule/parser.go index 42855f1b..cc76219c 100644 --- a/rule/parser.go +++ b/rule/parser.go @@ -1,68 +1,32 @@ package rules import ( - "fmt" C "github.com/Dreamacro/clash/constant" RC "github.com/Dreamacro/clash/rule/common" "github.com/Dreamacro/clash/rule/logic" RP "github.com/Dreamacro/clash/rule/provider" + "github.com/Dreamacro/clash/rule/ruleparser" ) -func ParseRule(tp, payload, target string, params []string) (C.Rule, error) { - var ( - parseErr error - parsed C.Rule - ) - - switch tp { - case "DOMAIN": - parsed = RC.NewDomain(payload, target) - case "DOMAIN-SUFFIX": - parsed = RC.NewDomainSuffix(payload, target) - case "DOMAIN-KEYWORD": - parsed = RC.NewDomainKeyword(payload, target) - case "GEOSITE": - parsed, parseErr = RC.NewGEOSITE(payload, target) - case "GEOIP": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewGEOIP(payload, target, noResolve) - case "IP-CIDR", "IP-CIDR6": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRNoResolve(noResolve)) - case "SRC-IP-CIDR": - parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) - case "IP-SUFFIX": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPSuffix(payload, target, false, noResolve) - case "SRC-IP-SUFFIX": - parsed, parseErr = RC.NewIPSuffix(payload, target, true, true) - case "SRC-PORT": - parsed, parseErr = RC.NewPort(payload, target, true) - case "DST-PORT": - parsed, parseErr = RC.NewPort(payload, target, false) - case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, target, true) - case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, target, false) - case "NETWORK": - parsed, parseErr = RC.NewNetworkType(payload, target) - case "UID": - parsed, parseErr = RC.NewUid(payload, target) - case "IN-TYPE": - parsed, parseErr = RC.NewInType(payload, target) - case "AND": - parsed, parseErr = logic.NewAND(payload, target) - case "OR": - parsed, parseErr = logic.NewOR(payload, target) - case "NOT": - parsed, parseErr = logic.NewNOT(payload, target) - case "RULE-SET": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RP.NewRuleSet(payload, target, noResolve) - case "MATCH": - parsed = RC.NewMatch(target) - default: - parseErr = fmt.Errorf("unsupported rule type %s", tp) +func ParseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) { + parsed, parseErr = ruleparser.ParseSameRule(tp, payload, target, params) + if ruleparser.IsUnsupported(parseErr) { + switch tp { + case "AND": + parsed, parseErr = logic.NewAND(payload, target) + case "OR": + parsed, parseErr = logic.NewOR(payload, target) + case "NOT": + parsed, parseErr = logic.NewNOT(payload, target) + case "RULE-SET": + noResolve := RC.HasNoResolve(params) + parsed, parseErr = RP.NewRuleSet(payload, target, noResolve) + case "MATCH": + parsed = RC.NewMatch(target) + parseErr = nil + default: + parseErr = ruleparser.NewUnsupportedError(tp) + } } if parseErr != nil { @@ -77,5 +41,5 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) { parsed.SetRuleExtra(ruleExtra) - return parsed, nil + return } diff --git a/rule/provider/parse.go b/rule/provider/parse.go index bcf0d0e4..1cbe79c2 100644 --- a/rule/provider/parse.go +++ b/rule/provider/parse.go @@ -7,6 +7,7 @@ import ( C "github.com/Dreamacro/clash/constant" P "github.com/Dreamacro/clash/constant/provider" RC "github.com/Dreamacro/clash/rule/common" + "github.com/Dreamacro/clash/rule/ruleparser" "time" ) @@ -51,51 +52,9 @@ func ParseRuleProvider(name string, mapping map[string]interface{}) (P.RuleProvi return NewRuleSetProvider(name, behavior, time.Duration(uint(schema.Interval))*time.Second, vehicle), nil } -func parseRule(tp, payload, target string, params []string) (C.Rule, error) { - var ( - parseErr error - parsed C.Rule - ) +func parseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) { + parsed, parseErr = ruleparser.ParseSameRule(tp, payload, target, params) - switch tp { - case "DOMAIN": - parsed = RC.NewDomain(payload, target) - case "DOMAIN-SUFFIX": - parsed = RC.NewDomainSuffix(payload, target) - case "DOMAIN-KEYWORD": - parsed = RC.NewDomainKeyword(payload, target) - case "GEOIP": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewGEOIP(payload, target, noResolve) - case "GEOSITE": - parsed, parseErr = RC.NewGEOSITE(payload, target) - case "IP-CIDR", "IP-CIDR6": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRNoResolve(noResolve)) - case "SRC-IP-CIDR": - parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) - case "IP-SUFFIX": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPSuffix(payload, target, false, noResolve) - case "SRC-IP-SUFFIX": - parsed, parseErr = RC.NewIPSuffix(payload, target, true, true) - case "SRC-PORT": - parsed, parseErr = RC.NewPort(payload, target, true) - case "DST-PORT": - parsed, parseErr = RC.NewPort(payload, target, false) - case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, target, true) - case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, target, false) - case "NETWORK": - parsed, parseErr = RC.NewNetworkType(payload, target) - case "UID": - parsed, parseErr = RC.NewUid(payload, target) - case "IN-TYPE": - parsed, parseErr = RC.NewInType(payload, target) - default: - parseErr = fmt.Errorf("unsupported rule type %s", tp) - } if parseErr != nil { return nil, parseErr } diff --git a/rule/ruleparser/ruleparser.go b/rule/ruleparser/ruleparser.go new file mode 100644 index 00000000..aafa1e13 --- /dev/null +++ b/rule/ruleparser/ruleparser.go @@ -0,0 +1,67 @@ +package ruleparser + +import ( + "fmt" + C "github.com/Dreamacro/clash/constant" + RC "github.com/Dreamacro/clash/rule/common" +) + +func ParseSameRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) { + switch tp { + case "DOMAIN": + parsed = RC.NewDomain(payload, target) + case "DOMAIN-SUFFIX": + parsed = RC.NewDomainSuffix(payload, target) + case "DOMAIN-KEYWORD": + parsed = RC.NewDomainKeyword(payload, target) + case "GEOSITE": + parsed, parseErr = RC.NewGEOSITE(payload, target) + case "GEOIP": + noResolve := RC.HasNoResolve(params) + parsed, parseErr = RC.NewGEOIP(payload, target, noResolve) + case "IP-CIDR", "IP-CIDR6": + noResolve := RC.HasNoResolve(params) + parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRNoResolve(noResolve)) + case "SRC-IP-CIDR": + parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) + case "IP-SUFFIX": + noResolve := RC.HasNoResolve(params) + parsed, parseErr = RC.NewIPSuffix(payload, target, false, noResolve) + case "SRC-IP-SUFFIX": + parsed, parseErr = RC.NewIPSuffix(payload, target, true, true) + case "SRC-PORT": + parsed, parseErr = RC.NewPort(payload, target, true) + case "DST-PORT": + parsed, parseErr = RC.NewPort(payload, target, false) + case "PROCESS-NAME": + parsed, parseErr = RC.NewProcess(payload, target, true) + case "PROCESS-PATH": + parsed, parseErr = RC.NewProcess(payload, target, false) + case "NETWORK": + parsed, parseErr = RC.NewNetworkType(payload, target) + case "UID": + parsed, parseErr = RC.NewUid(payload, target) + case "IN-TYPE": + parsed, parseErr = RC.NewInType(payload, target) + default: + parseErr = NewUnsupportedError(tp) + } + return +} + +type UnsupportedError struct { + err string +} + +func (ue UnsupportedError) Error() string { + return ue.err +} + +func NewUnsupportedError(tp any) *UnsupportedError { + return &UnsupportedError{err: fmt.Sprintf("unsupported rule type %s", tp)} +} + +func IsUnsupported(err error) bool { + _, ok := err.(UnsupportedError) + return ok +}