Skip to content

Commit

Permalink
Refactor(constant): added rule string enums in configs as RuleConfig …
Browse files Browse the repository at this point in the history
…for better outside integrations (#2878)
  • Loading branch information
nekomeowww authored Aug 16, 2023
1 parent cb8c732 commit 218c3b4
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 16 deletions.
3 changes: 3 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ linters:
- unconvert
- unused
- usestdlibvars
- exhaustive

linters-settings:
gci:
Expand All @@ -21,3 +22,5 @@ linters-settings:
- default
staticcheck:
go: '1.21'
exhaustive:
default-signifies-exhaustive: true
2 changes: 2 additions & 0 deletions constant/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ func (t Type) String() string {
return "Redir"
case TPROXY:
return "TProxy"
case TUNNEL:
return "Tunnel"
default:
return "Unknown"
}
Expand Down
22 changes: 22 additions & 0 deletions constant/rule.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
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
const (
Domain RuleType = iota
Expand Down
2 changes: 2 additions & 0 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ func print(data Event) {
log.Errorln(data.Payload)
case DEBUG:
log.Debugln(data.Payload)
case SILENT:
return
}
}

Expand Down
3 changes: 3 additions & 0 deletions rule/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
C "github.com/Dreamacro/clash/constant"
)

// Implements C.Rule
var _ C.Rule = (*Domain)(nil)

type Domain struct {
domain string
adapter string
Expand Down
3 changes: 3 additions & 0 deletions rule/domain_keyword.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
C "github.com/Dreamacro/clash/constant"
)

// Implements C.Rule
var _ C.Rule = (*DomainKeyword)(nil)

type DomainKeyword struct {
keyword string
adapter string
Expand Down
3 changes: 3 additions & 0 deletions rule/domain_suffix.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
C "github.com/Dreamacro/clash/constant"
)

// Implements C.Rule
var _ C.Rule = (*DomainSuffix)(nil)

type DomainSuffix struct {
suffix string
adapter string
Expand Down
3 changes: 3 additions & 0 deletions rule/final.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
C "github.com/Dreamacro/clash/constant"
)

// Implements C.Rule
var _ C.Rule = (*Match)(nil)

type Match struct {
adapter string
}
Expand Down
3 changes: 3 additions & 0 deletions rule/geoip.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
C "github.com/Dreamacro/clash/constant"
)

// Implements C.Rule
var _ C.Rule = (*GEOIP)(nil)

type GEOIP struct {
country string
adapter string
Expand Down
3 changes: 3 additions & 0 deletions rule/ipcidr.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption {
}
}

// Implements C.Rule
var _ C.Rule = (*IPCIDR)(nil)

type IPCIDR struct {
ipnet *net.IPNet
adapter string
Expand Down
3 changes: 3 additions & 0 deletions rule/ipset.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
"github.com/Dreamacro/clash/log"
)

// Implements C.Rule
var _ C.Rule = (*IPSet)(nil)

type IPSet struct {
name string
adapter string
Expand Down
32 changes: 18 additions & 14 deletions rule/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,40 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
parsed C.Rule
)

switch tp {
case "DOMAIN":
ruleConfigType := C.RuleConfig(tp)

switch ruleConfigType {
case C.RuleConfigDomain:
parsed = NewDomain(payload, target)
case "DOMAIN-SUFFIX":
case C.RuleConfigDomainSuffix:
parsed = NewDomainSuffix(payload, target)
case "DOMAIN-KEYWORD":
case C.RuleConfigDomainKeyword:
parsed = NewDomainKeyword(payload, target)
case "GEOIP":
case C.RuleConfigGeoIP:
noResolve := HasNoResolve(params)
parsed = NewGEOIP(payload, target, noResolve)
case "IP-CIDR", "IP-CIDR6":
case C.RuleConfigIPCIDR, C.RuleConfigIPCIDR6:
noResolve := HasNoResolve(params)
parsed, parseErr = NewIPCIDR(payload, target, WithIPCIDRNoResolve(noResolve))
case "SRC-IP-CIDR":
case C.RuleConfigSrcIPCIDR:
parsed, parseErr = NewIPCIDR(payload, target, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))
case "SRC-PORT":
case C.RuleConfigSrcPort:
parsed, parseErr = NewPort(payload, target, PortTypeSrc)
case "DST-PORT":
case C.RuleConfigDstPort:
parsed, parseErr = NewPort(payload, target, PortTypeDest)
case "INBOUND-PORT":
case C.RuleConfigInboundPort:
parsed, parseErr = NewPort(payload, target, PortTypeInbound)
case "PROCESS-NAME":
case C.RuleConfigProcessName:
parsed, parseErr = NewProcess(payload, target, true)
case "PROCESS-PATH":
case C.RuleConfigProcessPath:
parsed, parseErr = NewProcess(payload, target, false)
case "IPSET":
case C.RuleConfigIPSet:
noResolve := HasNoResolve(params)
parsed, parseErr = NewIPSet(payload, target, noResolve)
case "MATCH":
case C.RuleConfigMatch:
parsed = NewMatch(target)
case C.RuleConfigRuleSet, C.RuleConfigScript:
parseErr = fmt.Errorf("unsupported rule type %s", tp)
default:
parseErr = fmt.Errorf("unsupported rule type %s", tp)
}
Expand Down
171 changes: 171 additions & 0 deletions rule/parser_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
3 changes: 3 additions & 0 deletions rule/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const (
PortTypeInbound
)

// Implements C.Rule
var _ C.Rule = (*Port)(nil)

type Port struct {
adapter string
port C.Port
Expand Down
3 changes: 3 additions & 0 deletions rule/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
C "github.com/Dreamacro/clash/constant"
)

// Implements C.Rule
var _ C.Rule = (*Process)(nil)

type Process struct {
adapter string
process string
Expand Down
6 changes: 4 additions & 2 deletions tunnel/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,12 @@ func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, r
proxy = proxies["DIRECT"]
case Global:
proxy = proxies["GLOBAL"]
// Rule
default:
case Rule:
proxy, rule, err = match(metadata)
default:
panic(fmt.Sprintf("unknown mode: %s", mode))
}

return
}

Expand Down

0 comments on commit 218c3b4

Please sign in to comment.