mirror of
https://github.com/apernet/OpenGFW.git
synced 2024-12-23 01:19:21 +08:00
Merge branch 'master' into wip-quic
This commit is contained in:
commit
e177837301
10
README.ja.md
10
README.ja.md
@ -75,6 +75,12 @@ workers:
|
|||||||
tcpMaxBufferedPagesTotal: 4096
|
tcpMaxBufferedPagesTotal: 4096
|
||||||
tcpMaxBufferedPagesPerConn: 64
|
tcpMaxBufferedPagesPerConn: 64
|
||||||
udpMaxStreams: 4096
|
udpMaxStreams: 4096
|
||||||
|
|
||||||
|
# 特定のローカルGeoIP / GeoSiteデータベースファイルを読み込むためのパス。
|
||||||
|
# 設定されていない場合は、https://github.com/LoyalSoldier/v2ray-rules-dat から自動的にダウンロードされます。
|
||||||
|
# geo:
|
||||||
|
# geoip: geoip.dat
|
||||||
|
# geosite: geosite.dat
|
||||||
```
|
```
|
||||||
|
|
||||||
### ルール例
|
### ルール例
|
||||||
@ -128,6 +134,10 @@ workers:
|
|||||||
- name: block CN geoip
|
- name: block CN geoip
|
||||||
action: block
|
action: block
|
||||||
expr: geoip(string(ip.dst), "cn")
|
expr: geoip(string(ip.dst), "cn")
|
||||||
|
|
||||||
|
- name: block cidr
|
||||||
|
action: block
|
||||||
|
expr: cidr(string(ip.dst), "192.168.0.0/16")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### サポートされるアクション
|
#### サポートされるアクション
|
||||||
|
10
README.md
10
README.md
@ -80,6 +80,12 @@ workers:
|
|||||||
tcpMaxBufferedPagesTotal: 4096
|
tcpMaxBufferedPagesTotal: 4096
|
||||||
tcpMaxBufferedPagesPerConn: 64
|
tcpMaxBufferedPagesPerConn: 64
|
||||||
udpMaxStreams: 4096
|
udpMaxStreams: 4096
|
||||||
|
|
||||||
|
# The path to load specific local geoip/geosite db files.
|
||||||
|
# If not set, they will be automatically downloaded from https://github.com/Loyalsoldier/v2ray-rules-dat
|
||||||
|
# geo:
|
||||||
|
# geoip: geoip.dat
|
||||||
|
# geosite: geosite.dat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example rules
|
### Example rules
|
||||||
@ -134,6 +140,10 @@ to [Expr Language Definition](https://expr-lang.org/docs/language-definition).
|
|||||||
- name: block CN geoip
|
- name: block CN geoip
|
||||||
action: block
|
action: block
|
||||||
expr: geoip(string(ip.dst), "cn")
|
expr: geoip(string(ip.dst), "cn")
|
||||||
|
|
||||||
|
- name: block cidr
|
||||||
|
action: block
|
||||||
|
expr: cidr(string(ip.dst), "192.168.0.0/16")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Supported actions
|
#### Supported actions
|
||||||
|
10
README.zh.md
10
README.zh.md
@ -76,6 +76,12 @@ workers:
|
|||||||
tcpMaxBufferedPagesTotal: 4096
|
tcpMaxBufferedPagesTotal: 4096
|
||||||
tcpMaxBufferedPagesPerConn: 64
|
tcpMaxBufferedPagesPerConn: 64
|
||||||
udpMaxStreams: 4096
|
udpMaxStreams: 4096
|
||||||
|
|
||||||
|
# 指定的 geoip/geosite 档案路径
|
||||||
|
# 如果未设置,将自动从 https://github.com/Loyalsoldier/v2ray-rules-dat 下载
|
||||||
|
# geo:
|
||||||
|
# geoip: geoip.dat
|
||||||
|
# geosite: geosite.dat
|
||||||
```
|
```
|
||||||
|
|
||||||
### 样例规则
|
### 样例规则
|
||||||
@ -129,6 +135,10 @@ workers:
|
|||||||
- name: block CN geoip
|
- name: block CN geoip
|
||||||
action: block
|
action: block
|
||||||
expr: geoip(string(ip.dst), "cn")
|
expr: geoip(string(ip.dst), "cn")
|
||||||
|
|
||||||
|
- name: block cidr
|
||||||
|
action: block
|
||||||
|
expr: cidr(string(ip.dst), "192.168.0.0/16")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 支持的 action
|
#### 支持的 action
|
||||||
|
@ -60,13 +60,6 @@ func (f *tcpStreamFactory) New(ipFlow, tcpFlow gopacket.Flow, tcp *layers.TCP, a
|
|||||||
rs := f.Ruleset
|
rs := f.Ruleset
|
||||||
f.RulesetMutex.RUnlock()
|
f.RulesetMutex.RUnlock()
|
||||||
ans := analyzersToTCPAnalyzers(rs.Analyzers(info))
|
ans := analyzersToTCPAnalyzers(rs.Analyzers(info))
|
||||||
if len(ans) == 0 {
|
|
||||||
ctx := ac.(*tcpContext)
|
|
||||||
ctx.Verdict = tcpVerdictAcceptStream
|
|
||||||
f.Logger.TCPStreamAction(info, ruleset.ActionAllow, true)
|
|
||||||
// a tcpStream with no activeEntries is a no-op
|
|
||||||
return &tcpStream{finalVerdict: tcpVerdictAcceptStream}
|
|
||||||
}
|
|
||||||
// Create entries for each analyzer
|
// Create entries for each analyzer
|
||||||
entries := make([]*tcpStreamEntry, 0, len(ans))
|
entries := make([]*tcpStreamEntry, 0, len(ans))
|
||||||
for _, a := range ans {
|
for _, a := range ans {
|
||||||
@ -109,7 +102,7 @@ type tcpStream struct {
|
|||||||
ruleset ruleset.Ruleset
|
ruleset ruleset.Ruleset
|
||||||
activeEntries []*tcpStreamEntry
|
activeEntries []*tcpStreamEntry
|
||||||
doneEntries []*tcpStreamEntry
|
doneEntries []*tcpStreamEntry
|
||||||
finalVerdict tcpVerdict
|
lastVerdict tcpVerdict
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpStreamEntry struct {
|
type tcpStreamEntry struct {
|
||||||
@ -120,11 +113,14 @@ type tcpStreamEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool {
|
func (s *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool {
|
||||||
if len(s.activeEntries) > 0 {
|
if len(s.activeEntries) > 0 || s.virgin {
|
||||||
|
// Make sure every stream matches against the ruleset at least once,
|
||||||
|
// even if there are no activeEntries, as the ruleset may have built-in
|
||||||
|
// properties that need to be matched.
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
ctx := ac.(*tcpContext)
|
ctx := ac.(*tcpContext)
|
||||||
ctx.Verdict = s.finalVerdict
|
ctx.Verdict = s.lastVerdict
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +155,7 @@ func (s *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
|
|||||||
action := result.Action
|
action := result.Action
|
||||||
if action != ruleset.ActionMaybe && action != ruleset.ActionModify {
|
if action != ruleset.ActionMaybe && action != ruleset.ActionModify {
|
||||||
verdict := actionToTCPVerdict(action)
|
verdict := actionToTCPVerdict(action)
|
||||||
s.finalVerdict = verdict
|
s.lastVerdict = verdict
|
||||||
ctx.Verdict = verdict
|
ctx.Verdict = verdict
|
||||||
s.logger.TCPStreamAction(s.info, action, false)
|
s.logger.TCPStreamAction(s.info, action, false)
|
||||||
// Verdict issued, no need to process any more packets
|
// Verdict issued, no need to process any more packets
|
||||||
@ -168,7 +164,7 @@ func (s *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
|
|||||||
}
|
}
|
||||||
if len(s.activeEntries) == 0 && ctx.Verdict == tcpVerdictAccept {
|
if len(s.activeEntries) == 0 && ctx.Verdict == tcpVerdictAccept {
|
||||||
// All entries are done but no verdict issued, accept stream
|
// All entries are done but no verdict issued, accept stream
|
||||||
s.finalVerdict = tcpVerdictAcceptStream
|
s.lastVerdict = tcpVerdictAcceptStream
|
||||||
ctx.Verdict = tcpVerdictAcceptStream
|
ctx.Verdict = tcpVerdictAcceptStream
|
||||||
s.logger.TCPStreamAction(s.info, ruleset.ActionAllow, true)
|
s.logger.TCPStreamAction(s.info, ruleset.ActionAllow, true)
|
||||||
}
|
}
|
||||||
|
@ -61,12 +61,6 @@ func (f *udpStreamFactory) New(ipFlow, udpFlow gopacket.Flow, udp *layers.UDP, u
|
|||||||
rs := f.Ruleset
|
rs := f.Ruleset
|
||||||
f.RulesetMutex.RUnlock()
|
f.RulesetMutex.RUnlock()
|
||||||
ans := analyzersToUDPAnalyzers(rs.Analyzers(info))
|
ans := analyzersToUDPAnalyzers(rs.Analyzers(info))
|
||||||
if len(ans) == 0 {
|
|
||||||
uc.Verdict = udpVerdictAcceptStream
|
|
||||||
f.Logger.UDPStreamAction(info, ruleset.ActionAllow, true)
|
|
||||||
// a udpStream with no activeEntries is a no-op
|
|
||||||
return &udpStream{finalVerdict: udpVerdictAcceptStream}
|
|
||||||
}
|
|
||||||
// Create entries for each analyzer
|
// Create entries for each analyzer
|
||||||
entries := make([]*udpStreamEntry, 0, len(ans))
|
entries := make([]*udpStreamEntry, 0, len(ans))
|
||||||
for _, a := range ans {
|
for _, a := range ans {
|
||||||
@ -167,7 +161,7 @@ type udpStream struct {
|
|||||||
ruleset ruleset.Ruleset
|
ruleset ruleset.Ruleset
|
||||||
activeEntries []*udpStreamEntry
|
activeEntries []*udpStreamEntry
|
||||||
doneEntries []*udpStreamEntry
|
doneEntries []*udpStreamEntry
|
||||||
finalVerdict udpVerdict
|
lastVerdict udpVerdict
|
||||||
}
|
}
|
||||||
|
|
||||||
type udpStreamEntry struct {
|
type udpStreamEntry struct {
|
||||||
@ -178,10 +172,13 @@ type udpStreamEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *udpStream) Accept(udp *layers.UDP, rev bool, uc *udpContext) bool {
|
func (s *udpStream) Accept(udp *layers.UDP, rev bool, uc *udpContext) bool {
|
||||||
if len(s.activeEntries) > 0 {
|
if len(s.activeEntries) > 0 || s.virgin {
|
||||||
|
// Make sure every stream matches against the ruleset at least once,
|
||||||
|
// even if there are no activeEntries, as the ruleset may have built-in
|
||||||
|
// properties that need to be matched.
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
uc.Verdict = s.finalVerdict
|
uc.Verdict = s.lastVerdict
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,17 +224,17 @@ func (s *udpStream) Feed(udp *layers.UDP, rev bool, uc *udpContext) {
|
|||||||
}
|
}
|
||||||
if action != ruleset.ActionMaybe {
|
if action != ruleset.ActionMaybe {
|
||||||
verdict, final := actionToUDPVerdict(action)
|
verdict, final := actionToUDPVerdict(action)
|
||||||
|
s.lastVerdict = verdict
|
||||||
uc.Verdict = verdict
|
uc.Verdict = verdict
|
||||||
s.logger.UDPStreamAction(s.info, action, false)
|
s.logger.UDPStreamAction(s.info, action, false)
|
||||||
if final {
|
if final {
|
||||||
s.finalVerdict = verdict
|
|
||||||
s.closeActiveEntries()
|
s.closeActiveEntries()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(s.activeEntries) == 0 && uc.Verdict == udpVerdictAccept {
|
if len(s.activeEntries) == 0 && uc.Verdict == udpVerdictAccept {
|
||||||
// All entries are done but no verdict issued, accept stream
|
// All entries are done but no verdict issued, accept stream
|
||||||
s.finalVerdict = udpVerdictAcceptStream
|
s.lastVerdict = udpVerdictAcceptStream
|
||||||
uc.Verdict = udpVerdictAcceptStream
|
uc.Verdict = udpVerdictAcceptStream
|
||||||
s.logger.UDPStreamAction(s.info, ruleset.ActionAllow, true)
|
s.logger.UDPStreamAction(s.info, ruleset.ActionAllow, true)
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/coreos/go-iptables v0.7.0
|
github.com/coreos/go-iptables v0.7.0
|
||||||
github.com/expr-lang/expr v1.15.7
|
github.com/expr-lang/expr v1.15.7
|
||||||
github.com/florianl/go-nfqueue v1.3.2-0.20231218173729-f2bdeb033acf
|
github.com/florianl/go-nfqueue v1.3.2-0.20231218173729-f2bdeb033acf
|
||||||
github.com/google/gopacket v1.1.19
|
github.com/google/gopacket v1.1.20-0.20220810144506-32ee38206866
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||||
github.com/mdlayher/netlink v1.6.0
|
github.com/mdlayher/netlink v1.6.0
|
||||||
github.com/quic-go/quic-go v0.41.0
|
github.com/quic-go/quic-go v0.41.0
|
||||||
|
11
go.sum
11
go.sum
@ -25,10 +25,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
github.com/google/gopacket v1.1.20-0.20220810144506-32ee38206866 h1:NaJi58bCZZh0jjPw78EqDZekPEfhlzYE01C5R+zh1tE=
|
||||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
github.com/google/gopacket v1.1.20-0.20220810144506-32ee38206866/go.mod h1:riddUzxTSBpJXk3qBHtYr4qOhFhT6k/1c0E3qkQjQpA=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
@ -88,6 +86,9 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||||
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||||
|
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
@ -114,6 +115,8 @@ golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
|||||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
18
ruleset/builtins/cidr.go
Normal file
18
ruleset/builtins/cidr.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MatchCIDR(ip string, cidr *net.IPNet) bool {
|
||||||
|
ipAddr := net.ParseIP(ip)
|
||||||
|
if ipAddr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return cidr.Contains(ipAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompileCIDR(cidr string) (*net.IPNet, error) {
|
||||||
|
_, ipNet, err := net.ParseCIDR(cidr)
|
||||||
|
return ipNet, err
|
||||||
|
}
|
@ -2,6 +2,7 @@ package ruleset
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -14,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/apernet/OpenGFW/analyzer"
|
"github.com/apernet/OpenGFW/analyzer"
|
||||||
"github.com/apernet/OpenGFW/modifier"
|
"github.com/apernet/OpenGFW/modifier"
|
||||||
|
"github.com/apernet/OpenGFW/ruleset/builtins"
|
||||||
"github.com/apernet/OpenGFW/ruleset/builtins/geo"
|
"github.com/apernet/OpenGFW/ruleset/builtins/geo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -100,17 +102,21 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier
|
|||||||
return nil, fmt.Errorf("rule %q has invalid action %q", rule.Name, rule.Action)
|
return nil, fmt.Errorf("rule %q has invalid action %q", rule.Name, rule.Action)
|
||||||
}
|
}
|
||||||
visitor := &idVisitor{Identifiers: make(map[string]bool)}
|
visitor := &idVisitor{Identifiers: make(map[string]bool)}
|
||||||
|
patcher := &idPatcher{}
|
||||||
program, err := expr.Compile(rule.Expr,
|
program, err := expr.Compile(rule.Expr,
|
||||||
func(c *conf.Config) {
|
func(c *conf.Config) {
|
||||||
c.Strict = false
|
c.Strict = false
|
||||||
c.Expect = reflect.Bool
|
c.Expect = reflect.Bool
|
||||||
c.Visitors = append(c.Visitors, visitor)
|
c.Visitors = append(c.Visitors, visitor, patcher)
|
||||||
registerBuiltinFunctions(c.Functions, geoMatcher)
|
registerBuiltinFunctions(c.Functions, geoMatcher)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("rule %q has invalid expression: %w", rule.Name, err)
|
return nil, fmt.Errorf("rule %q has invalid expression: %w", rule.Name, err)
|
||||||
}
|
}
|
||||||
|
if patcher.Err != nil {
|
||||||
|
return nil, fmt.Errorf("rule %q failed to patch expression: %w", rule.Name, patcher.Err)
|
||||||
|
}
|
||||||
for name := range visitor.Identifiers {
|
for name := range visitor.Identifiers {
|
||||||
if isBuiltInAnalyzer(name) {
|
if isBuiltInAnalyzer(name) {
|
||||||
continue
|
continue
|
||||||
@ -126,6 +132,8 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier
|
|||||||
if err := geoMatcher.LoadGeoSite(); err != nil {
|
if err := geoMatcher.LoadGeoSite(); err != nil {
|
||||||
return nil, fmt.Errorf("rule %q failed to load geosite: %w", rule.Name, err)
|
return nil, fmt.Errorf("rule %q failed to load geosite: %w", rule.Name, err)
|
||||||
}
|
}
|
||||||
|
case "cidr":
|
||||||
|
// No initialization needed for CIDR.
|
||||||
default:
|
default:
|
||||||
a, ok := fullAnMap[name]
|
a, ok := fullAnMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -179,6 +187,13 @@ func registerBuiltinFunctions(funcMap map[string]*ast.Function, geoMatcher *geo.
|
|||||||
},
|
},
|
||||||
Types: []reflect.Type{reflect.TypeOf(geoMatcher.MatchGeoSite)},
|
Types: []reflect.Type{reflect.TypeOf(geoMatcher.MatchGeoSite)},
|
||||||
}
|
}
|
||||||
|
funcMap["cidr"] = &ast.Function{
|
||||||
|
Name: "cidr",
|
||||||
|
Func: func(params ...any) (any, error) {
|
||||||
|
return builtins.MatchCIDR(params[0].(string), params[1].(*net.IPNet)), nil
|
||||||
|
},
|
||||||
|
Types: []reflect.Type{reflect.TypeOf((func(string, string) bool)(nil)), reflect.TypeOf(builtins.MatchCIDR)},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func streamInfoToExprEnv(info StreamInfo) map[string]interface{} {
|
func streamInfoToExprEnv(info StreamInfo) map[string]interface{} {
|
||||||
@ -247,6 +262,8 @@ func modifiersToMap(mods []modifier.Modifier) map[string]modifier.Modifier {
|
|||||||
return modMap
|
return modMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// idVisitor is a visitor that collects all identifiers in an expression.
|
||||||
|
// This is for determining which analyzers are used by the expression.
|
||||||
type idVisitor struct {
|
type idVisitor struct {
|
||||||
Identifiers map[string]bool
|
Identifiers map[string]bool
|
||||||
}
|
}
|
||||||
@ -256,3 +273,29 @@ func (v *idVisitor) Visit(node *ast.Node) {
|
|||||||
v.Identifiers[idNode.Value] = true
|
v.Identifiers[idNode.Value] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// idPatcher patches the AST during expr compilation, replacing certain values with
|
||||||
|
// their internal representations for better runtime performance.
|
||||||
|
type idPatcher struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *idPatcher) Visit(node *ast.Node) {
|
||||||
|
switch (*node).(type) {
|
||||||
|
case *ast.CallNode:
|
||||||
|
callNode := (*node).(*ast.CallNode)
|
||||||
|
switch callNode.Func.Name {
|
||||||
|
case "cidr":
|
||||||
|
cidrStringNode, ok := callNode.Arguments[1].(*ast.StringNode)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cidr, err := builtins.CompileCIDR(cidrStringNode.Value)
|
||||||
|
if err != nil {
|
||||||
|
p.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callNode.Arguments[1] = &ast.ConstantNode{Value: cidr}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user