Skip to content

daemon: rule lists operators caching + lists matching enhancements#1567

Merged
gustavo-iniguez-goya merged 4 commits intoevilsocket:masterfrom
nvandamme:daemon-go-rule-lists-operators-caching
Apr 17, 2026
Merged

daemon: rule lists operators caching + lists matching enhancements#1567
gustavo-iniguez-goya merged 4 commits intoevilsocket:masterfrom
nvandamme:daemon-go-rule-lists-operators-caching

Conversation

@nvandamme
Copy link
Copy Markdown
Contributor

@nvandamme nvandamme commented Mar 18, 2026

This PR is a proposal to :

  • migrate rule operators lists file loader and caching that are currently using RLock to immutable cached snapshots that are reconstructed only on rules change (to avoid any mutex locking in this hot-path; especially on big hosts/domain lists)
  • new layered lists matching strategy :
    • domains: exact map -> wildcard trie -> glob fallback
    • nets: exact IP + CIDR fallback
    • ips: exact IP + CIDR fallback

New comparison benchmarks added:

  • BenchmarkOperatorDomainsRLockMixedParallel
  • BenchmarkOperatorIPRLockMixedParallel
  • BenchmarkOperatorNetRLockMixedParallel
  • BenchmarkOperatorDomainsRegexpRLockMixedParallel

10s benchmem comparison:

Domains mixed

Snapshot: 27.33 ns/op
RLock: 61.54 ns/op
Snapshot is about 2.25x faster

IP mixed

Snapshot: 24.55 ns/op
RLock: 52.79 ns/op
Snapshot is about 2.15x faster

Nets mixed

Snapshot: 24.96 ns/op
RLock: 53.57 ns/op
Snapshot is about 2.15x faster

Domains regexp mixed

Snapshot: 33.77 ns/op
RLock: 48.47 ns/op
Snapshot is about 1.44x faster

@gustavo-iniguez-goya
Copy link
Copy Markdown
Collaborator

thanks @nvandamme ,

regarding glob matching, did you try using the functions from the standard lib Glob or Match? https://pkg.go.dev/path/filepath@go1.23.0#Match

https://github.com/gobwas/glob has not been updated in 8 years and has several issues open.

@nvandamme nvandamme force-pushed the daemon-go-rule-lists-operators-caching branch from f1db396 to e2b4af5 Compare April 13, 2026 15:06
@nvandamme
Copy link
Copy Markdown
Contributor Author

nvandamme commented Apr 13, 2026

thanks @nvandamme ,

regarding glob matching, did you try using the functions from the standard lib Glob or Match? https://pkg.go.dev/path/filepath@go1.23.0#Match

https://github.com/gobwas/glob has not been updated in 8 years and has several issues open.

@gustavo-iniguez-goya

Done, dropped gobwas and relaced it with filepath.Match native go globbing.

Some edge cases tough :

  • No brace expansion
  • {www,api}.example.org is not supported.
    This is not POSIX core globbing, but many tools support it; here it will not work.
  • Special handling of *.suffix and .suffix
    These are routed to the trie, not the generic glob matcher.
    They match any subdomain depth under the suffix (for example both a.example.org and a.b.example.org).
    That is broader than one-label glob semantics.
  • Component count is fixed for non-trie glob patterns
    For generic glob patterns, pattern and host must have the same number of labels.
    Example: api-??.example.org matches api-12.example.org, but not api-12.sub.example.org.
  • Invalid bracket patterns are rejected at load time
  • Malformed classes like [abc are dropped (with warning), never matched later.
    Matching is domain-operand case handling
    In non-sensitive mode, host matching is effectively case-insensitive via normalization.
    In sensitive mode, pattern/host case must match exactly.

@nvandamme nvandamme force-pushed the daemon-go-rule-lists-operators-caching branch from 5013342 to 483b038 Compare April 13, 2026 15:23
@gustavo-iniguez-goya
Copy link
Copy Markdown
Collaborator

can you share your benchmarks @nvandamme ? I'm obtaining different results. RLock wins in all cases except for Regexp operations.

opensnitch/rule $ go test -v -bench=. -benchmem -benchtime=10s -run=^$ 
goos: linux
goarch: amd64
pkg: github.com/evilsocket/opensnitch/daemon/rule
cpu: Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz
BenchmarkOperatorDomainsSnapshotMatchParallel
BenchmarkOperatorDomainsSnapshotMatchParallel-4         	51280838	       254.8 ns/op	     112 B/op	       4 allocs/op
BenchmarkOperatorDomainsSnapshotMixedParallel
BenchmarkOperatorDomainsSnapshotMixedParallel-4         	58007008	       224.7 ns/op	     100 B/op	       3 allocs/op

BenchmarkOperatorDomainsRLockMixedParallel
BenchmarkOperatorDomainsRLockMixedParallel-4            	83306914	       159.3 ns/op	      49 B/op	       1 allocs/op

BenchmarkOperatorIPSnapshotMixedParallel
BenchmarkOperatorIPSnapshotMixedParallel-4              	53569580	       222.5 ns/op	      73 B/op	       4 allocs/op

BenchmarkOperatorIPRLockMixedParallel
BenchmarkOperatorIPRLockMixedParallel-4                 	100000000	       133.9 ns/op	      14 B/op	       1 allocs/op

BenchmarkOperatorNetSnapshotMixedParallel
BenchmarkOperatorNetSnapshotMixedParallel-4             	50968135	       230.9 ns/op	      70 B/op	       4 allocs/op

BenchmarkOperatorNetRLockMixedParallel
BenchmarkOperatorNetRLockMixedParallel-4                	100000000	       123.2 ns/op	      14 B/op	       1 allocs/op

BenchmarkOperatorDomainsRegexpSnapshotMixedParallel
BenchmarkOperatorDomainsRegexpSnapshotMixedParallel-4   	22433817	       574.1 ns/op	       0 B/op	       0 allocs/op
BenchmarkOperatorDomainsRegexpRLockMixedParallel
BenchmarkOperatorDomainsRegexpRLockMixedParallel-4      	20802310	       758.4 ns/op	       0 B/op	       0 allocs/op

BenchmarkLoaderFindFirstMatchSnapshotParallel
BenchmarkLoaderFindFirstMatchSnapshotParallel-4         	23578188	       445.3 ns/op	       0 B/op	       0 allocs/op

@nvandamme
Copy link
Copy Markdown
Contributor Author

nvandamme commented Apr 15, 2026

Sure @gustavo-iniguez-goya, here you go:

❯ go test -v -bench=. -benchmem -benchtime=10s -run=^\$
goos: linux
goarch: amd64
pkg: github.com/evilsocket/opensnitch/daemon/rule
cpu: AMD Ryzen 9 7950X 16-Core Processor            
BenchmarkOperatorDomainsSnapshotMatchParallel
BenchmarkOperatorDomainsSnapshotMatchParallel-32                332221792               36.34 ns/op          112 B/op          4 allocs/op
BenchmarkOperatorDomainsSnapshotMixedParallel
BenchmarkOperatorDomainsSnapshotMixedParallel-32                399545389               30.17 ns/op          100 B/op          3 allocs/op
BenchmarkOperatorDomainsRLockMixedParallel
BenchmarkOperatorDomainsRLockMixedParallel-32                   192454665               62.64 ns/op           49 B/op          1 allocs/op
BenchmarkOperatorIPSnapshotMixedParallel
BenchmarkOperatorIPSnapshotMixedParallel-32                     473218155               25.37 ns/op           73 B/op          4 allocs/op
BenchmarkOperatorIPRLockMixedParallel
BenchmarkOperatorIPRLockMixedParallel-32                        225327198               53.10 ns/op           14 B/op          1 allocs/op
BenchmarkOperatorNetSnapshotMixedParallel
BenchmarkOperatorNetSnapshotMixedParallel-32                    486666794               24.85 ns/op           70 B/op          4 allocs/op
BenchmarkOperatorNetRLockMixedParallel
BenchmarkOperatorNetRLockMixedParallel-32                       224404614               53.47 ns/op           14 B/op          1 allocs/op
BenchmarkOperatorDomainsRegexpSnapshotMixedParallel
BenchmarkOperatorDomainsRegexpSnapshotMixedParallel-32          352684196               34.28 ns/op            0 B/op          0 allocs/op
BenchmarkOperatorDomainsRegexpRLockMixedParallel
BenchmarkOperatorDomainsRegexpRLockMixedParallel-32             250972416               48.00 ns/op            0 B/op          0 allocs/op
BenchmarkLoaderFindFirstMatchSnapshotParallel
BenchmarkLoaderFindFirstMatchSnapshotParallel-32                511107836               23.44 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/evilsocket/opensnitch/daemon/rule    159.880s

And on a laptop :

❯ go test -v -bench=. -benchmem -benchtime=10s -run=^\$
goos: linux
goarch: amd64
pkg: github.com/evilsocket/opensnitch/daemon/rule
cpu: 13th Gen Intel(R) Core(TM) i9-13950HX
BenchmarkOperatorDomainsSnapshotMatchParallel
BenchmarkOperatorDomainsSnapshotMatchParallel-32                126053014               94.68 ns/op          112 B/op          4 allocs/op
BenchmarkOperatorDomainsSnapshotMixedParallel
BenchmarkOperatorDomainsSnapshotMixedParallel-32                154115217               77.79 ns/op          100 B/op          3 allocs/op
BenchmarkOperatorDomainsRLockMixedParallel
BenchmarkOperatorDomainsRLockMixedParallel-32                   68527828               172.8 ns/op            49 B/op          1 allocs/op
BenchmarkOperatorIPSnapshotMixedParallel
BenchmarkOperatorIPSnapshotMixedParallel-32                     180973765               66.12 ns/op           73 B/op          4 allocs/op
BenchmarkOperatorIPRLockMixedParallel
BenchmarkOperatorIPRLockMixedParallel-32                        91440632               134.9 ns/op            14 B/op          1 allocs/op
BenchmarkOperatorNetSnapshotMixedParallel
BenchmarkOperatorNetSnapshotMixedParallel-32                    185183985               64.88 ns/op           70 B/op          4 allocs/op
BenchmarkOperatorNetRLockMixedParallel
BenchmarkOperatorNetRLockMixedParallel-32                       90939967               136.2 ns/op            14 B/op          1 allocs/op
BenchmarkOperatorDomainsRegexpSnapshotMixedParallel
BenchmarkOperatorDomainsRegexpSnapshotMixedParallel-32          165498808               69.46 ns/op            0 B/op          0 allocs/op
BenchmarkOperatorDomainsRegexpRLockMixedParallel
BenchmarkOperatorDomainsRegexpRLockMixedParallel-32             93872804               119.1 ns/op             0 B/op          0 allocs/op
BenchmarkLoaderFindFirstMatchSnapshotParallel
BenchmarkLoaderFindFirstMatchSnapshotParallel-32                274168850               43.79 ns/op            0 B/op          0 allocs/op
PASS
ok      github.com/evilsocket/opensnitch/daemon/rule    162.350s

@gustavo-iniguez-goya gustavo-iniguez-goya merged commit f78177d into evilsocket:master Apr 17, 2026
1 check failed
@gustavo-iniguez-goya
Copy link
Copy Markdown
Collaborator

Despite of my benchmark results, measuring reject rules matching using simple domain lists in FindFirstMatch() , there's a 3x improvement, from about ~450µs down to ~150µs.

I'll update the wiki with the new features. Thanks @nvandamme !

@nvandamme nvandamme deleted the daemon-go-rule-lists-operators-caching branch April 18, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants