88 "strconv"
99 "strings"
1010 "sync"
11+ "sync/atomic"
1112
1213 "github.com/evilsocket/opensnitch/daemon/conman"
1314 "github.com/evilsocket/opensnitch/daemon/core"
@@ -75,13 +76,32 @@ const (
7576type opCallback func (value string ) bool
7677type opGenericCallback func (value interface {}) bool
7778
79+ type listRegexEntry struct {
80+ file string
81+ re * regexp.Regexp
82+ }
83+
84+ type listCacheSnapshot struct {
85+ lists map [string ]interface {}
86+ domainWildcards domainWildcardTrie
87+ domainGlobs []string
88+ listExact map [string ]struct {}
89+ listNets []* net.IPNet
90+ regexEntries []listRegexEntry
91+ }
92+
7893// Operator represents what we want to filter of a connection, and how.
7994type Operator struct {
8095 cb opCallback
8196 cbGeneric opGenericCallback
8297 re * regexp.Regexp
8398 netMask * net.IPNet
8499 lists map [string ]interface {}
100+ domainWildcards domainWildcardTrie
101+ domainGlobs []string
102+ listExact map [string ]struct {}
103+ listNets []* net.IPNet
104+ listSnapshot atomic.Pointer [listCacheSnapshot ]
85105 exitMonitorChan chan (struct {})
86106 rangeMin uint64
87107 rangeMax uint64
@@ -178,10 +198,10 @@ func (o *Operator) Compile() error {
178198 o .cb = o .reListCmp
179199 } else if o .Operand == OpIPLists {
180200 o .loadLists ()
181- o .cb = o .simpleListsCmp
201+ o .cbGeneric = o .ipListsCmp
182202 } else if o .Operand == OpNetLists {
183203 o .loadLists ()
184- o .cbGeneric = o .ipNetCmp
204+ o .cbGeneric = o .netListsCmp
185205 } else if o .Operand == OpHashMD5Lists {
186206 o .loadLists ()
187207 o .cb = o .simpleListsCmp
@@ -290,9 +310,12 @@ func (o *Operator) cmpNetwork(destIP interface{}) bool {
290310}
291311
292312func (o * Operator ) matchListsCmp (msg , what string ) bool {
293- o .RLock ()
294- item , found := o .lists [what ]
295- o .RUnlock ()
313+ snapshot := o .listSnapshot .Load ()
314+ if snapshot == nil {
315+ return false
316+ }
317+
318+ item , found := snapshot .lists [what ]
296319
297320 if found {
298321 log .Debug ("%s: %s, %s" , log .Red (msg ), what , item )
@@ -309,7 +332,29 @@ func (o *Operator) domainsListsCmp(data string) bool {
309332 data = strings .ToLower (data )
310333 }
311334
312- return o .matchListsCmp ("domains list match" , data )
335+ snapshot := o .listSnapshot .Load ()
336+ if snapshot == nil {
337+ return false
338+ }
339+
340+ _ , exactFound := snapshot .lists [data ]
341+
342+ if exactFound {
343+ log .Debug ("%s: %s" , log .Red ("domains list match" ), data )
344+ return true
345+ }
346+ if snapshot .domainWildcards .matchesHost (data ) {
347+ log .Debug ("%s: %s" , log .Red ("domains wildcard match" ), data )
348+ return true
349+ }
350+ for _ , g := range snapshot .domainGlobs {
351+ if matchDomainGlob (g , data ) {
352+ log .Debug ("%s: %s" , log .Red ("domains glob match" ), data )
353+ return true
354+ }
355+ }
356+
357+ return false
313358}
314359
315360func (o * Operator ) simpleListsCmp (what string ) bool {
@@ -320,17 +365,52 @@ func (o *Operator) simpleListsCmp(what string) bool {
320365 return o .matchListsCmp ("simple list match" , what )
321366}
322367
323- func (o * Operator ) ipNetCmp (dstIP interface {}) bool {
324- o .RLock ()
325- defer o .RUnlock ()
368+ func (o * Operator ) netListsCmp (dstIP interface {}) bool {
369+ ip := dstIP .(net.IP )
370+ ipText := ip .String ()
371+ snapshot := o .listSnapshot .Load ()
372+ if snapshot == nil {
373+ return false
374+ }
375+
376+ _ , exactFound := snapshot .listExact [ipText ]
377+
378+ if exactFound {
379+ log .Debug ("%s: %s" , log .Red ("Net exact list match" ), ipText )
380+ return true
381+ }
382+
383+ for _ , netMask := range snapshot .listNets {
384+ if netMask .Contains (ip ) {
385+ log .Debug ("%s: %s, %s" , log .Red ("Net list match" ), ipText , netMask .String ())
386+ return true
387+ }
388+ }
389+ return false
390+ }
391+
392+ func (o * Operator ) ipListsCmp (dstIP interface {}) bool {
393+ ip := dstIP .(net.IP )
394+ ipText := ip .String ()
395+ snapshot := o .listSnapshot .Load ()
396+ if snapshot == nil {
397+ return false
398+ }
399+
400+ _ , exactFound := snapshot .listExact [ipText ]
401+
402+ if exactFound {
403+ log .Debug ("%s: %s" , log .Red ("IP list exact match" ), ipText )
404+ return true
405+ }
326406
327- for host , netMask := range o .lists {
328- n := netMask .(* net.IPNet )
329- if n .Contains (dstIP .(net.IP )) {
330- log .Debug ("%s: %s, %s" , log .Red ("Net list match" ), dstIP , host )
407+ for _ , netMask := range snapshot .listNets {
408+ if netMask .Contains (ip ) {
409+ log .Debug ("%s: %s, %s" , log .Red ("IP list cidr match" ), ipText , netMask .String ())
331410 return true
332411 }
333412 }
413+
334414 return false
335415}
336416
@@ -341,13 +421,14 @@ func (o *Operator) reListCmp(data string) bool {
341421 if o .Sensitive == false {
342422 data = strings .ToLower (data )
343423 }
344- o .RLock ()
345- defer o .RUnlock ()
424+ snapshot := o .listSnapshot .Load ()
425+ if snapshot == nil {
426+ return false
427+ }
346428
347- for file , re := range o .lists {
348- r := re .(* regexp.Regexp )
349- if r .MatchString (data ) {
350- log .Debug ("%s: %s, %s" , log .Red ("Regexp list match" ), data , file )
429+ for _ , entry := range snapshot .regexEntries {
430+ if entry .re .MatchString (data ) {
431+ log .Debug ("%s: %s, %s" , log .Red ("Regexp list match" ), data , entry .file )
351432 return true
352433 }
353434 }
@@ -389,7 +470,7 @@ func (o *Operator) Match(con *conman.Connection, hasChecksums bool) bool {
389470 } else if o .Operand == OpDomainsLists {
390471 return o .cb (con .DstHost )
391472 } else if o .Operand == OpIPLists {
392- return o .cb (con .DstIP . String () )
473+ return o .cbGeneric (con .DstIP )
393474 } else if o .Operand == OpHashMD5Lists {
394475 return o .cb (con .Process .Checksums [procmon .HashMD5 ])
395476 } else if o .Operand == OpUserID || o .Operand == OpUserName {
0 commit comments