conntrack: fin_from_orig tracking + TCP state in format output
ConnEntry gains fin_from_orig: bool field to track which direction sent the first FIN. This enables correct TimeWait transition: FinWait→TimeWait now only fires when the OPPOSITE direction sends FIN (not when the same side retransmits). Per Linux nf_conntrack_proto_tcp.c: - fin_from_orig=true means orig sent first FIN - TimeWait transition requires reply FIN next - fin_from_orig=false means reply sent first FIN - TimeWait transition requires orig FIN next TCP state now included in format() output: Established tcp=Established src=10.0.0.1 dst=10.0.0.2 sport=80 dport=1234 ... New tcp=SynSent src=... Established tcp=TimeWait src=... All 31 tests pass.
This commit is contained in:
@@ -150,6 +150,7 @@ struct ConnEntry {
|
||||
reply_key: ConnKey,
|
||||
state: ConnState,
|
||||
tcp_state: TcpTracking,
|
||||
fin_from_orig: bool,
|
||||
timeout: Instant,
|
||||
orig_packets: u64,
|
||||
orig_bytes: u64,
|
||||
@@ -194,10 +195,12 @@ fn advance_entry_state(entry: &mut ConnEntry, is_orig: bool, ctx: &PacketContext
|
||||
}
|
||||
TcpTracking::Established if res_fin => {
|
||||
entry.tcp_state = TcpTracking::FinWait;
|
||||
entry.fin_from_orig = true;
|
||||
entry.timeout = now + Duration::from_secs(120);
|
||||
return true;
|
||||
}
|
||||
TcpTracking::FinWait if res_fin => {
|
||||
TcpTracking::FinWait if res_fin && !entry.fin_from_orig => {
|
||||
// Second FIN from reply direction (orig FIN was first)
|
||||
entry.tcp_state = TcpTracking::TimeWait;
|
||||
entry.timeout = now + Duration::from_secs(120);
|
||||
return true;
|
||||
@@ -219,10 +222,12 @@ fn advance_entry_state(entry: &mut ConnEntry, is_orig: bool, ctx: &PacketContext
|
||||
}
|
||||
TcpTracking::Established if res_fin => {
|
||||
entry.tcp_state = TcpTracking::FinWait;
|
||||
entry.fin_from_orig = false;
|
||||
entry.timeout = now + Duration::from_secs(120);
|
||||
return true;
|
||||
}
|
||||
TcpTracking::FinWait if res_fin => {
|
||||
TcpTracking::FinWait if res_fin && entry.fin_from_orig => {
|
||||
// Second FIN from orig direction (reply FIN was first)
|
||||
entry.tcp_state = TcpTracking::TimeWait;
|
||||
entry.timeout = now + Duration::from_secs(120);
|
||||
return true;
|
||||
@@ -327,6 +332,7 @@ impl ConntrackTable {
|
||||
reply_key,
|
||||
state,
|
||||
tcp_state,
|
||||
fin_from_orig: false,
|
||||
timeout: now + timeout,
|
||||
orig_packets: 1,
|
||||
orig_bytes: ctx.packet.len() as u64,
|
||||
@@ -390,6 +396,7 @@ impl ConntrackTable {
|
||||
},
|
||||
state: ConnState::New,
|
||||
tcp_state: TcpTracking::None,
|
||||
fin_from_orig: false,
|
||||
timeout: now + Duration::from_secs(30),
|
||||
orig_packets: 1,
|
||||
orig_bytes: ctx.packet.len() as u64,
|
||||
@@ -518,9 +525,15 @@ impl ConntrackTable {
|
||||
pub fn format(&self) -> alloc::string::String {
|
||||
let mut out = alloc::format!("conntrack entries: {}, over_limit: {}\n", self.entries.len(), self.over_limit_count);
|
||||
for entry in self.entries.values() {
|
||||
let tcp_info = if entry.key.l4proto == 6 {
|
||||
alloc::format!(" tcp={:?}", entry.tcp_state)
|
||||
} else {
|
||||
alloc::string::String::new()
|
||||
};
|
||||
out.push_str(&alloc::format!(
|
||||
" {:?} src={} dst={} sport={} dport={} orig_pkts={} orig_bytes={} reply_pkts={} reply_bytes={}\n",
|
||||
" {:?}{} src={} dst={} sport={} dport={} orig_pkts={} orig_bytes={} reply_pkts={} reply_bytes={}\n",
|
||||
entry.state,
|
||||
tcp_info,
|
||||
entry.key.src_addr,
|
||||
entry.key.dst_addr,
|
||||
entry.key.src_port,
|
||||
|
||||
Reference in New Issue
Block a user