fix: eliminate stale verdict poisoning, memory leaks, data races, and per-packet allocations in engine
This commit is contained in:
+24
-3
@@ -3,6 +3,7 @@ package engine
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.difuse.io/Difuse/Mellaris/analyzer"
|
||||
"git.difuse.io/Difuse/Mellaris/io"
|
||||
@@ -13,6 +14,8 @@ import (
|
||||
|
||||
const tcpFlowMaxBuffer = 16384
|
||||
|
||||
const tcpFlowIdleTimeout = 10 * time.Minute
|
||||
|
||||
type tcpFlowDirection uint8
|
||||
|
||||
const (
|
||||
@@ -37,6 +40,7 @@ type tcpFlow struct {
|
||||
doneEntries []*tcpFlowEntry
|
||||
lastVerdict io.Verdict
|
||||
feedCalled [2]bool
|
||||
lastSeen time.Time
|
||||
}
|
||||
|
||||
type tcpFlowEntry struct {
|
||||
@@ -67,16 +71,17 @@ func (f *tcpFlow) feed(l3 L3Info, tcp TCPInfo, payload []byte) io.Verdict {
|
||||
expected := f.dirSeq[dir]
|
||||
if !f.feedCalled[dir] || expected == 0 || tcp.Seq == expected {
|
||||
f.feedCalled[dir] = true
|
||||
f.dirBuf[dir] = append(f.dirBuf[dir], payload...)
|
||||
f.dirSeq[dir] = tcp.Seq + uint32(len(payload))
|
||||
if len(f.dirBuf[dir]) <= tcpFlowMaxBuffer {
|
||||
f.dirBuf[dir] = append(f.dirBuf[dir], payload...)
|
||||
propUpdated = f.feedAnalyzers(rev)
|
||||
}
|
||||
f.dirSeq[dir] = tcp.Seq + uint32(len(payload))
|
||||
}
|
||||
}
|
||||
|
||||
f.runMatch(rs, version, rulesetChanged, propUpdated)
|
||||
f.maybeFinalizeVerdict()
|
||||
f.lastSeen = time.Now()
|
||||
return f.lastVerdict
|
||||
}
|
||||
|
||||
@@ -218,7 +223,11 @@ func (m *tcpFlowManager) createFlow(streamID uint32, l3 L3Info, tcp TCPInfo, pay
|
||||
Props: make(analyzer.CombinedPropMap),
|
||||
}
|
||||
m.logger.TCPStreamNew(m.workerID, info)
|
||||
rs, version := m.rulesetSource()
|
||||
var rs ruleset.Ruleset
|
||||
var version uint64
|
||||
if m.rulesetSource != nil {
|
||||
rs, version = m.rulesetSource()
|
||||
}
|
||||
var ans []analyzer.TCPAnalyzer
|
||||
if rs != nil {
|
||||
baseAns := rs.Analyzers(info)
|
||||
@@ -255,6 +264,7 @@ func (m *tcpFlowManager) createFlow(streamID uint32, l3 L3Info, tcp TCPInfo, pay
|
||||
rulesetVersion: version,
|
||||
activeEntries: entries,
|
||||
lastVerdict: io.VerdictAccept,
|
||||
lastSeen: time.Now(),
|
||||
}
|
||||
flow.dirSeq[tcpDirC2S] = tcp.Seq + 1
|
||||
return flow
|
||||
@@ -266,6 +276,17 @@ func (m *tcpFlowManager) updateRuleset(r ruleset.Ruleset, version uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *tcpFlowManager) cleanupIdle(now time.Time) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for id, flow := range m.flows {
|
||||
if now.Sub(flow.lastSeen) > tcpFlowIdleTimeout {
|
||||
flow.closeActiveEntries()
|
||||
delete(m.flows, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func feedFlowEntry(entry *tcpFlowEntry, rev bool, data []byte) (update *analyzer.PropUpdate, closeUpdate *analyzer.PropUpdate, done bool) {
|
||||
if !entry.HasLimit {
|
||||
update, done = entry.Stream.Feed(rev, true, false, 0, data)
|
||||
|
||||
Reference in New Issue
Block a user