Refactor(constant): added rule string enums in configs as RuleConfig for better outside integrations (#2878)
This commit is contained in:
parent
cb8c732375
commit
218c3b4e89
@ -11,6 +11,7 @@ linters:
|
|||||||
- unconvert
|
- unconvert
|
||||||
- unused
|
- unused
|
||||||
- usestdlibvars
|
- usestdlibvars
|
||||||
|
- exhaustive
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
gci:
|
gci:
|
||||||
@ -21,3 +22,5 @@ linters-settings:
|
|||||||
- default
|
- default
|
||||||
staticcheck:
|
staticcheck:
|
||||||
go: '1.21'
|
go: '1.21'
|
||||||
|
exhaustive:
|
||||||
|
default-signifies-exhaustive: true
|
||||||
|
@ -52,6 +52,8 @@ func (t Type) String() string {
|
|||||||
return "Redir"
|
return "Redir"
|
||||||
case TPROXY:
|
case TPROXY:
|
||||||
return "TProxy"
|
return "TProxy"
|
||||||
|
case TUNNEL:
|
||||||
|
return "Tunnel"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,27 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
RuleConfigDomain RuleConfig = "DOMAIN"
|
||||||
|
RuleConfigDomainSuffix RuleConfig = "DOMAIN-SUFFIX"
|
||||||
|
RuleConfigDomainKeyword RuleConfig = "DOMAIN-KEYWORD"
|
||||||
|
RuleConfigGeoIP RuleConfig = "GEOIP"
|
||||||
|
RuleConfigIPCIDR RuleConfig = "IP-CIDR"
|
||||||
|
RuleConfigIPCIDR6 RuleConfig = "IP-CIDR6"
|
||||||
|
RuleConfigSrcIPCIDR RuleConfig = "SRC-IP-CIDR"
|
||||||
|
RuleConfigSrcPort RuleConfig = "SRC-PORT"
|
||||||
|
RuleConfigDstPort RuleConfig = "DST-PORT"
|
||||||
|
RuleConfigInboundPort RuleConfig = "INBOUND-PORT"
|
||||||
|
RuleConfigProcessName RuleConfig = "PROCESS-NAME"
|
||||||
|
RuleConfigProcessPath RuleConfig = "PROCESS-PATH"
|
||||||
|
RuleConfigIPSet RuleConfig = "IPSET"
|
||||||
|
RuleConfigRuleSet RuleConfig = "RULE-SET"
|
||||||
|
RuleConfigScript RuleConfig = "SCRIPT"
|
||||||
|
RuleConfigMatch RuleConfig = "MATCH"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rule Config Type String represents a rule type in configuration files.
|
||||||
|
type RuleConfig string
|
||||||
|
|
||||||
// Rule Type
|
// Rule Type
|
||||||
const (
|
const (
|
||||||
Domain RuleType = iota
|
Domain RuleType = iota
|
||||||
|
@ -88,6 +88,8 @@ func print(data Event) {
|
|||||||
log.Errorln(data.Payload)
|
log.Errorln(data.Payload)
|
||||||
case DEBUG:
|
case DEBUG:
|
||||||
log.Debugln(data.Payload)
|
log.Debugln(data.Payload)
|
||||||
|
case SILENT:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*Domain)(nil)
|
||||||
|
|
||||||
type Domain struct {
|
type Domain struct {
|
||||||
domain string
|
domain string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -6,6 +6,9 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*DomainKeyword)(nil)
|
||||||
|
|
||||||
type DomainKeyword struct {
|
type DomainKeyword struct {
|
||||||
keyword string
|
keyword string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -6,6 +6,9 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*DomainSuffix)(nil)
|
||||||
|
|
||||||
type DomainSuffix struct {
|
type DomainSuffix struct {
|
||||||
suffix string
|
suffix string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -4,6 +4,9 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*Match)(nil)
|
||||||
|
|
||||||
type Match struct {
|
type Match struct {
|
||||||
adapter string
|
adapter string
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*GEOIP)(nil)
|
||||||
|
|
||||||
type GEOIP struct {
|
type GEOIP struct {
|
||||||
country string
|
country string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -20,6 +20,9 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*IPCIDR)(nil)
|
||||||
|
|
||||||
type IPCIDR struct {
|
type IPCIDR struct {
|
||||||
ipnet *net.IPNet
|
ipnet *net.IPNet
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -6,6 +6,9 @@ import (
|
|||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*IPSet)(nil)
|
||||||
|
|
||||||
type IPSet struct {
|
type IPSet struct {
|
||||||
name string
|
name string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -12,36 +12,40 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
|||||||
parsed C.Rule
|
parsed C.Rule
|
||||||
)
|
)
|
||||||
|
|
||||||
switch tp {
|
ruleConfigType := C.RuleConfig(tp)
|
||||||
case "DOMAIN":
|
|
||||||
|
switch ruleConfigType {
|
||||||
|
case C.RuleConfigDomain:
|
||||||
parsed = NewDomain(payload, target)
|
parsed = NewDomain(payload, target)
|
||||||
case "DOMAIN-SUFFIX":
|
case C.RuleConfigDomainSuffix:
|
||||||
parsed = NewDomainSuffix(payload, target)
|
parsed = NewDomainSuffix(payload, target)
|
||||||
case "DOMAIN-KEYWORD":
|
case C.RuleConfigDomainKeyword:
|
||||||
parsed = NewDomainKeyword(payload, target)
|
parsed = NewDomainKeyword(payload, target)
|
||||||
case "GEOIP":
|
case C.RuleConfigGeoIP:
|
||||||
noResolve := HasNoResolve(params)
|
noResolve := HasNoResolve(params)
|
||||||
parsed = NewGEOIP(payload, target, noResolve)
|
parsed = NewGEOIP(payload, target, noResolve)
|
||||||
case "IP-CIDR", "IP-CIDR6":
|
case C.RuleConfigIPCIDR, C.RuleConfigIPCIDR6:
|
||||||
noResolve := HasNoResolve(params)
|
noResolve := HasNoResolve(params)
|
||||||
parsed, parseErr = NewIPCIDR(payload, target, WithIPCIDRNoResolve(noResolve))
|
parsed, parseErr = NewIPCIDR(payload, target, WithIPCIDRNoResolve(noResolve))
|
||||||
case "SRC-IP-CIDR":
|
case C.RuleConfigSrcIPCIDR:
|
||||||
parsed, parseErr = NewIPCIDR(payload, target, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))
|
parsed, parseErr = NewIPCIDR(payload, target, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))
|
||||||
case "SRC-PORT":
|
case C.RuleConfigSrcPort:
|
||||||
parsed, parseErr = NewPort(payload, target, PortTypeSrc)
|
parsed, parseErr = NewPort(payload, target, PortTypeSrc)
|
||||||
case "DST-PORT":
|
case C.RuleConfigDstPort:
|
||||||
parsed, parseErr = NewPort(payload, target, PortTypeDest)
|
parsed, parseErr = NewPort(payload, target, PortTypeDest)
|
||||||
case "INBOUND-PORT":
|
case C.RuleConfigInboundPort:
|
||||||
parsed, parseErr = NewPort(payload, target, PortTypeInbound)
|
parsed, parseErr = NewPort(payload, target, PortTypeInbound)
|
||||||
case "PROCESS-NAME":
|
case C.RuleConfigProcessName:
|
||||||
parsed, parseErr = NewProcess(payload, target, true)
|
parsed, parseErr = NewProcess(payload, target, true)
|
||||||
case "PROCESS-PATH":
|
case C.RuleConfigProcessPath:
|
||||||
parsed, parseErr = NewProcess(payload, target, false)
|
parsed, parseErr = NewProcess(payload, target, false)
|
||||||
case "IPSET":
|
case C.RuleConfigIPSet:
|
||||||
noResolve := HasNoResolve(params)
|
noResolve := HasNoResolve(params)
|
||||||
parsed, parseErr = NewIPSet(payload, target, noResolve)
|
parsed, parseErr = NewIPSet(payload, target, noResolve)
|
||||||
case "MATCH":
|
case C.RuleConfigMatch:
|
||||||
parsed = NewMatch(target)
|
parsed = NewMatch(target)
|
||||||
|
case C.RuleConfigRuleSet, C.RuleConfigScript:
|
||||||
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
default:
|
default:
|
||||||
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
}
|
}
|
||||||
|
171
rule/parser_test.go
Normal file
171
rule/parser_test.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package rules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseRule(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
tp C.RuleConfig
|
||||||
|
payload string
|
||||||
|
target string
|
||||||
|
params []string
|
||||||
|
expectedRule C.Rule
|
||||||
|
expectedError error
|
||||||
|
}
|
||||||
|
|
||||||
|
policy := "DIRECT"
|
||||||
|
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigDomain,
|
||||||
|
payload: "example.com",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: NewDomain("example.com", policy),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigDomainSuffix,
|
||||||
|
payload: "example.com",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: NewDomainSuffix("example.com", policy),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigDomainKeyword,
|
||||||
|
payload: "example.com",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: NewDomainKeyword("example.com", policy),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigGeoIP,
|
||||||
|
payload: "CN",
|
||||||
|
target: policy, params: []string{noResolve},
|
||||||
|
expectedRule: NewGEOIP("CN", policy, true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigIPCIDR,
|
||||||
|
payload: "127.0.0.0/8",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewIPCIDR("127.0.0.0/8", policy, WithIPCIDRNoResolve(false))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigIPCIDR,
|
||||||
|
payload: "127.0.0.0/8",
|
||||||
|
target: policy, params: []string{noResolve},
|
||||||
|
expectedRule: lo.Must(NewIPCIDR("127.0.0.0/8", policy, WithIPCIDRNoResolve(true))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigIPCIDR6,
|
||||||
|
payload: "2001:db8::/32",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewIPCIDR("2001:db8::/32", policy, WithIPCIDRNoResolve(false))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigIPCIDR6,
|
||||||
|
payload: "2001:db8::/32",
|
||||||
|
target: policy, params: []string{noResolve},
|
||||||
|
expectedRule: lo.Must(NewIPCIDR("2001:db8::/32", policy, WithIPCIDRNoResolve(true))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigSrcIPCIDR,
|
||||||
|
payload: "192.168.1.201/32",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewIPCIDR("192.168.1.201/32", policy, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigSrcPort,
|
||||||
|
payload: "80",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewPort("80", policy, PortTypeSrc)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigDstPort,
|
||||||
|
payload: "80",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewPort("80", policy, PortTypeDest)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigInboundPort,
|
||||||
|
payload: "80",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewPort("80", policy, PortTypeInbound)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigProcessName,
|
||||||
|
payload: "example.exe",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewProcess("example.exe", policy, true)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigProcessPath,
|
||||||
|
payload: "C:\\Program Files\\example.exe",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewProcess("C:\\Program Files\\example.exe", policy, false)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigProcessPath,
|
||||||
|
payload: "/opt/example/example",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewProcess("/opt/example/example", policy, false)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigIPSet,
|
||||||
|
payload: "example",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: lo.Must(NewIPSet("example", policy, true)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigIPSet,
|
||||||
|
payload: "example",
|
||||||
|
target: policy, params: []string{noResolve},
|
||||||
|
expectedRule: lo.Must(NewIPSet("example", policy, false)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigMatch,
|
||||||
|
payload: "example",
|
||||||
|
target: policy,
|
||||||
|
expectedRule: NewMatch(policy),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigRuleSet,
|
||||||
|
payload: "example",
|
||||||
|
target: policy,
|
||||||
|
expectedError: fmt.Errorf("unsupported rule type %s", C.RuleConfigRuleSet),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: C.RuleConfigScript,
|
||||||
|
payload: "example",
|
||||||
|
target: policy,
|
||||||
|
expectedError: fmt.Errorf("unsupported rule type %s", C.RuleConfigScript),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: "UNKNOWN",
|
||||||
|
payload: "example",
|
||||||
|
target: policy,
|
||||||
|
expectedError: errors.New("unsupported rule type UNKNOWN"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tp: "ABCD",
|
||||||
|
payload: "example",
|
||||||
|
target: policy,
|
||||||
|
expectedError: errors.New("unsupported rule type ABCD"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
_, err := ParseRule(string(tc.tp), tc.payload, tc.target, tc.params)
|
||||||
|
if tc.expectedError != nil {
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.EqualError(t, err, tc.expectedError.Error())
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,9 @@ const (
|
|||||||
PortTypeInbound
|
PortTypeInbound
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*Port)(nil)
|
||||||
|
|
||||||
type Port struct {
|
type Port struct {
|
||||||
adapter string
|
adapter string
|
||||||
port C.Port
|
port C.Port
|
||||||
|
@ -7,6 +7,9 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Implements C.Rule
|
||||||
|
var _ C.Rule = (*Process)(nil)
|
||||||
|
|
||||||
type Process struct {
|
type Process struct {
|
||||||
adapter string
|
adapter string
|
||||||
process string
|
process string
|
||||||
|
@ -165,10 +165,12 @@ func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, r
|
|||||||
proxy = proxies["DIRECT"]
|
proxy = proxies["DIRECT"]
|
||||||
case Global:
|
case Global:
|
||||||
proxy = proxies["GLOBAL"]
|
proxy = proxies["GLOBAL"]
|
||||||
// Rule
|
case Rule:
|
||||||
default:
|
|
||||||
proxy, rule, err = match(metadata)
|
proxy, rule, err = match(metadata)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown mode: %s", mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user