Skip to content

Commit a5acd3a

Browse files
author
Skyxim
committed
refactor: clear linkname,reduce cycle dependencies,transport init geosite function
1 parent eea9a12 commit a5acd3a

File tree

15 files changed

+203
-149
lines changed

15 files changed

+203
-149
lines changed

component/geodata/init.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package geodata
2+
3+
import (
4+
"fmt"
5+
C "github.com/Dreamacro/clash/constant"
6+
"github.com/Dreamacro/clash/log"
7+
"io"
8+
"net/http"
9+
"os"
10+
)
11+
12+
var initFlag bool
13+
14+
func InitGeoSite() error {
15+
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
16+
log.Infoln("Can't find GeoSite.dat, start download")
17+
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
18+
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
19+
}
20+
log.Infoln("Download GeoSite.dat finish")
21+
}
22+
if !initFlag {
23+
if err := Verify(C.GeositeName); err != nil {
24+
log.Warnln("GeoSite.dat invalid, remove and download: %s", err)
25+
if err := os.Remove(C.Path.GeoSite()); err != nil {
26+
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
27+
}
28+
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
29+
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
30+
}
31+
}
32+
initFlag = true
33+
}
34+
return nil
35+
}
36+
37+
func downloadGeoSite(path string) (err error) {
38+
resp, err := http.Get(C.GeoSiteUrl)
39+
if err != nil {
40+
return
41+
}
42+
defer resp.Body.Close()
43+
44+
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
45+
if err != nil {
46+
return err
47+
}
48+
defer f.Close()
49+
_, err = io.Copy(f, resp.Body)
50+
51+
return err
52+
}

config/config.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
533533
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
534534
// parse rule provider
535535
for name, mapping := range cfg.RuleProvider {
536-
rp, err := RP.ParseRuleProvider(name, mapping)
536+
rp, err := RP.ParseRuleProvider(name, mapping, R.ParseRule)
537537
if err != nil {
538538
return nil, nil, err
539539
}
@@ -723,7 +723,7 @@ func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) {
723723
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
724724
var sites []*router.DomainMatcher
725725
if len(countries) > 0 {
726-
if err := initGeoSite(); err != nil {
726+
if err := geodata.InitGeoSite(); err != nil {
727727
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
728728
}
729729
}

config/initial.go

-42
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"github.com/Dreamacro/clash/log"
1313
)
1414

15-
var initFlag bool
16-
1715
func downloadMMDB(path string) (err error) {
1816
resp, err := http.Get(C.MmdbUrl)
1917
if err != nil {
@@ -48,46 +46,6 @@ func downloadGeoIP(path string) (err error) {
4846
return err
4947
}
5048

51-
func downloadGeoSite(path string) (err error) {
52-
resp, err := http.Get(C.GeoSiteUrl)
53-
if err != nil {
54-
return
55-
}
56-
defer resp.Body.Close()
57-
58-
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
59-
if err != nil {
60-
return err
61-
}
62-
defer f.Close()
63-
_, err = io.Copy(f, resp.Body)
64-
65-
return err
66-
}
67-
68-
func initGeoSite() error {
69-
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
70-
log.Infoln("Can't find GeoSite.dat, start download")
71-
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
72-
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
73-
}
74-
log.Infoln("Download GeoSite.dat finish")
75-
}
76-
if !initFlag {
77-
if err := geodata.Verify(C.GeositeName); err != nil {
78-
log.Warnln("GeoSite.dat invalid, remove and download: %s", err)
79-
if err := os.Remove(C.Path.GeoSite()); err != nil {
80-
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
81-
}
82-
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
83-
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
84-
}
85-
}
86-
initFlag = true
87-
}
88-
return nil
89-
}
90-
9149
func initGeoIP() error {
9250
if C.GeodataMode {
9351
if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {

rules/common/geosite.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ import (
1111
_ "unsafe"
1212
)
1313

14-
//go:linkname initGeoSite github.com/Dreamacro/clash/config.initGeoSite
15-
func initGeoSite() error
16-
1714
type GEOSITE struct {
1815
*Base
1916
country string
@@ -53,7 +50,7 @@ func (gs *GEOSITE) GetRecodeSize() int {
5350

5451
func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
5552
if !initFlag {
56-
if err := initGeoSite(); err != nil {
53+
if err := geodata.InitGeoSite(); err != nil {
5754
log.Errorln("can't initial GeoSite: %s", err)
5855
return nil, err
5956
}

rules/logic/and.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ func (A *AND) ShouldFindProcess() bool {
1919
return false
2020
}
2121

22-
func NewAND(payload string, adapter string) (*AND, error) {
22+
func NewAND(payload string, adapter string,
23+
parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*AND, error) {
2324
and := &AND{Base: &common.Base{}, payload: payload, adapter: adapter}
24-
rules, err := parseRuleByPayload(payload)
25+
rules, err := parseRuleByPayload(payload, parse)
2526
if err != nil {
2627
return nil, err
2728
}

rules/logic/common.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ import (
99
_ "unsafe"
1010
)
1111

12-
//go:linkname parseRule github.com/Dreamacro/clash/rules.ParseRule
13-
func parseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)
14-
15-
func parseRuleByPayload(payload string) ([]C.Rule, error) {
12+
func parseRuleByPayload(payload string, parseRule func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) ([]C.Rule, error) {
1613
regex, err := regexp.Compile("\\(.*\\)")
1714
if err != nil {
1815
return nil, err
@@ -29,7 +26,7 @@ func parseRuleByPayload(payload string) ([]C.Rule, error) {
2926
for _, subRange := range subRanges {
3027
subPayload := payload[subRange.start+1 : subRange.end]
3128

32-
rule, err := payloadToRule(subPayload)
29+
rule, err := payloadToRule(subPayload, parseLogicSubRule(parseRule))
3330
if err != nil {
3431
return nil, err
3532
}
@@ -47,7 +44,7 @@ func containRange(r Range, preStart, preEnd int) bool {
4744
return preStart < r.start && preEnd > r.end
4845
}
4946

50-
func payloadToRule(subPayload string) (C.Rule, error) {
47+
func payloadToRule(subPayload string, parseRule func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (C.Rule, error) {
5148
splitStr := strings.SplitN(subPayload, ",", 2)
5249
if len(splitStr) < 2 {
5350
return nil, fmt.Errorf("[%s] format is error", subPayload)
@@ -62,6 +59,17 @@ func payloadToRule(subPayload string) (C.Rule, error) {
6259
return parseRule(tp, param[0], "", param[1:])
6360
}
6461

62+
func parseLogicSubRule(parseRule func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
63+
return func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
64+
switch tp {
65+
case "MATCH":
66+
return nil, fmt.Errorf("unsupported rule type on logic rule")
67+
default:
68+
return parseRule(tp, payload, target, params)
69+
}
70+
}
71+
}
72+
6573
type Range struct {
6674
start int
6775
end int

rules/logic/logic_test.go

+66-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,72 @@
11
package logic
22

33
import (
4+
"fmt"
45
"github.com/Dreamacro/clash/constant"
6+
RC "github.com/Dreamacro/clash/rules/common"
7+
RP "github.com/Dreamacro/clash/rules/provider"
58
"github.com/stretchr/testify/assert"
69
"testing"
710
)
811

12+
func ParseRule(tp, payload, target string, params []string) (parsed constant.Rule, parseErr error) {
13+
switch tp {
14+
case "DOMAIN":
15+
parsed = RC.NewDomain(payload, target)
16+
case "DOMAIN-SUFFIX":
17+
parsed = RC.NewDomainSuffix(payload, target)
18+
case "DOMAIN-KEYWORD":
19+
parsed = RC.NewDomainKeyword(payload, target)
20+
case "GEOSITE":
21+
parsed, parseErr = RC.NewGEOSITE(payload, target)
22+
case "GEOIP":
23+
noResolve := RC.HasNoResolve(params)
24+
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve)
25+
case "IP-CIDR", "IP-CIDR6":
26+
noResolve := RC.HasNoResolve(params)
27+
parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRNoResolve(noResolve))
28+
case "SRC-IP-CIDR":
29+
parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
30+
case "IP-SUFFIX":
31+
noResolve := RC.HasNoResolve(params)
32+
parsed, parseErr = RC.NewIPSuffix(payload, target, false, noResolve)
33+
case "SRC-IP-SUFFIX":
34+
parsed, parseErr = RC.NewIPSuffix(payload, target, true, true)
35+
case "SRC-PORT":
36+
parsed, parseErr = RC.NewPort(payload, target, true)
37+
case "DST-PORT":
38+
parsed, parseErr = RC.NewPort(payload, target, false)
39+
case "PROCESS-NAME":
40+
parsed, parseErr = RC.NewProcess(payload, target, true)
41+
case "PROCESS-PATH":
42+
parsed, parseErr = RC.NewProcess(payload, target, false)
43+
case "NETWORK":
44+
parsed, parseErr = RC.NewNetworkType(payload, target)
45+
case "UID":
46+
parsed, parseErr = RC.NewUid(payload, target)
47+
case "IN-TYPE":
48+
parsed, parseErr = RC.NewInType(payload, target)
49+
case "AND":
50+
parsed, parseErr = NewAND(payload, target, ParseRule)
51+
case "OR":
52+
parsed, parseErr = NewOR(payload, target, ParseRule)
53+
case "NOT":
54+
parsed, parseErr = NewNOT(payload, target, ParseRule)
55+
case "RULE-SET":
56+
noResolve := RC.HasNoResolve(params)
57+
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve, ParseRule)
58+
case "MATCH":
59+
parsed = RC.NewMatch(target)
60+
parseErr = nil
61+
default:
62+
parseErr = fmt.Errorf("unsupported rule type %s", tp)
63+
}
64+
65+
return
66+
}
67+
968
func TestAND(t *testing.T) {
10-
and, err := NewAND("((DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT")
69+
and, err := NewAND("((DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
1170
assert.Equal(t, nil, err)
1271
assert.Equal(t, "DIRECT", and.adapter)
1372
assert.Equal(t, false, and.ShouldResolveIP())
@@ -18,29 +77,29 @@ func TestAND(t *testing.T) {
1877
DstPort: "20000",
1978
}))
2079

21-
and, err = NewAND("(DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT")
80+
and, err = NewAND("(DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
2281
assert.NotEqual(t, nil, err)
2382

24-
and, err = NewAND("((AND,(DOMAIN,baidu.com),(NETWORK,TCP)),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT")
83+
and, err = NewAND("((AND,(DOMAIN,baidu.com),(NETWORK,TCP)),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
2584
assert.Equal(t, nil, err)
2685
}
2786

2887
func TestNOT(t *testing.T) {
29-
not, err := NewNOT("((DST-PORT,6000-6500))", "REJECT")
88+
not, err := NewNOT("((DST-PORT,6000-6500))", "REJECT", ParseRule)
3089
assert.Equal(t, nil, err)
3190
assert.Equal(t, false, not.Match(&constant.Metadata{
3291
DstPort: "6100",
3392
}))
3493

35-
_, err = NewNOT("((DST-PORT,5600-6666),(DOMAIN,baidu.com))", "DIRECT")
94+
_, err = NewNOT("((DST-PORT,5600-6666),(DOMAIN,baidu.com))", "DIRECT", ParseRule)
3695
assert.NotEqual(t, nil, err)
3796

38-
_, err = NewNOT("(())", "DIRECT")
97+
_, err = NewNOT("(())", "DIRECT", ParseRule)
3998
assert.NotEqual(t, nil, err)
4099
}
41100

42101
func TestOR(t *testing.T) {
43-
or, err := NewOR("((DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT")
102+
or, err := NewOR("((DOMAIN,baidu.com),(NETWORK,TCP),(DST-PORT,10001-65535))", "DIRECT", ParseRule)
44103
assert.Equal(t, nil, err)
45104
assert.Equal(t, true, or.Match(&constant.Metadata{
46105
NetWork: constant.TCP,

rules/logic/not.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ func (not *NOT) ShouldFindProcess() bool {
1717
return false
1818
}
1919

20-
func NewNOT(payload string, adapter string) (*NOT, error) {
20+
func NewNOT(payload string, adapter string, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*NOT, error) {
2121
not := &NOT{Base: &common.Base{}, adapter: adapter}
22-
rule, err := parseRuleByPayload(payload)
22+
rule, err := parseRuleByPayload(payload, parse)
2323
if err != nil {
2424
return nil, err
2525
}

rules/logic/or.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ func (or *OR) ShouldResolveIP() bool {
4545
return or.needIP
4646
}
4747

48-
func NewOR(payload string, adapter string) (*OR, error) {
48+
func NewOR(payload string, adapter string, parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (*OR, error) {
4949
or := &OR{Base: &common.Base{}, payload: payload, adapter: adapter}
50-
rules, err := parseRuleByPayload(payload)
50+
rules, err := parseRuleByPayload(payload, parse)
5151
if err != nil {
5252
return nil, err
5353
}

0 commit comments

Comments
 (0)