feat(tcp, udp): implement stream state release after verdict and adjust flush interval logic
This commit is contained in:
+30
-5
@@ -124,8 +124,8 @@ type tcpStream struct {
|
||||
logger Logger
|
||||
ruleset ruleset.Ruleset
|
||||
activeEntries []*tcpStreamEntry
|
||||
doneEntries []*tcpStreamEntry
|
||||
lastVerdict tcpVerdict
|
||||
released bool // 最终判定已发出,分析器和属性表已经释放
|
||||
firstSegSeen bool // true once the client's first data segment was measured
|
||||
synAckWindow int // window of the observed SYN-ACK, -1 if none seen yet
|
||||
synAckWscale int // its window scale factor, -1 if the option was absent
|
||||
@@ -139,6 +139,11 @@ 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 {
|
||||
if s.released {
|
||||
// 最终判定已发出,后续报文一律沿用;Props 已经释放,不能再碰
|
||||
ac.(*tcpContext).Verdict = s.lastVerdict
|
||||
return false
|
||||
}
|
||||
if tcp.SYN && tcp.ACK && s.synAckWindow < 0 {
|
||||
s.synAckWindow, s.synAckWscale = int(tcp.Window), tcpWindowScale(tcp)
|
||||
if s.synAckWindow <= tcpSynAckWindowMax {
|
||||
@@ -210,6 +215,10 @@ func (s *tcpStream) recordFirstSegLen(n int) bool {
|
||||
}
|
||||
|
||||
func (s *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) {
|
||||
if s.released {
|
||||
// 判定已发出。还会走到这里只可能是超时 flush 补送的乱序页,没有东西可处理
|
||||
return
|
||||
}
|
||||
dir, start, end, skip := sg.Info()
|
||||
rev := dir == reassembly.TCPDirServerToClient
|
||||
avail, _ := sg.Lengths()
|
||||
@@ -229,7 +238,6 @@ func (s *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
|
||||
updated = updated || up1 || up2
|
||||
if done {
|
||||
s.activeEntries = append(s.activeEntries[:i], s.activeEntries[i+1:]...)
|
||||
s.doneEntries = append(s.doneEntries, entry)
|
||||
}
|
||||
}
|
||||
ctx := ac.(*tcpContext)
|
||||
@@ -254,15 +262,20 @@ func (s *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
|
||||
ctx.Verdict = tcpVerdictAcceptStream
|
||||
s.logger.TCPStreamAction(s.info, ruleset.ActionAllow, true)
|
||||
}
|
||||
if len(s.activeEntries) == 0 {
|
||||
// 不会再有分析器读数据,也不会再匹配规则:从这一刻起 Accept 只看 lastVerdict
|
||||
s.release()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
|
||||
s.closeActiveEntries()
|
||||
s.release()
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *tcpStream) closeActiveEntries() {
|
||||
// Signal close to all active entries & move them to doneEntries
|
||||
// Signal close to all active entries
|
||||
updated := false
|
||||
for _, entry := range s.activeEntries {
|
||||
update := entry.Stream.Close(false)
|
||||
@@ -272,10 +285,22 @@ func (s *tcpStream) closeActiveEntries() {
|
||||
if updated {
|
||||
s.logger.TCPStreamPropUpdate(s.info, true)
|
||||
}
|
||||
s.doneEntries = append(s.doneEntries, s.activeEntries...)
|
||||
s.activeEntries = nil
|
||||
}
|
||||
|
||||
// release 在最终判定发出后丢掉不会再用到的状态。
|
||||
//
|
||||
// 判定之后 Accept 只看 lastVerdict,分析器和属性表都不会再被读。但这条流本身还要在
|
||||
// 连接池里挂到超时被 flush,而 gopacket 回收连接槽位时并不清掉 stream 指针,
|
||||
// 要等下一条连接复用那个槽位才会覆盖。不主动放手的话,每条判定完的流会带着
|
||||
// 全部分析器对象一直活到那时候;节点上的 heap profile 里这部分占到了八成。
|
||||
func (s *tcpStream) release() {
|
||||
s.released = true
|
||||
s.activeEntries = nil
|
||||
s.info.Props = nil
|
||||
s.ruleset = nil
|
||||
}
|
||||
|
||||
func (s *tcpStream) feedEntry(entry *tcpStreamEntry, rev, start, end bool, skip int, data []byte) (update *analyzer.PropUpdate, closeUpdate *analyzer.PropUpdate, done bool) {
|
||||
if !entry.HasLimit {
|
||||
update, done = entry.Stream.Feed(rev, start, end, skip, data)
|
||||
@@ -287,7 +312,7 @@ func (s *tcpStream) feedEntry(entry *tcpStreamEntry, rev, start, end bool, skip
|
||||
update, done = entry.Stream.Feed(rev, start, end, skip, qData)
|
||||
entry.Quota -= len(qData)
|
||||
if entry.Quota <= 0 {
|
||||
// Quota exhausted, signal close & move to doneEntries
|
||||
// Quota exhausted, signal close & drop the entry
|
||||
closeUpdate = entry.Stream.Close(true)
|
||||
done = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user