fix: incorrect "virgin" handling causing rules with only built-in keywords to fail (#61)

This commit is contained in:
Toby 2024-02-16 19:08:19 -08:00 committed by GitHub
parent 7a52228ec6
commit 4ede93ce7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 23 deletions

View File

@ -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)
} }

View File

@ -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)
} }