conntrack: fix SynRecv→Established transition direction
The TCP three-way handshake completion (initiator's ACK after SYN-ACK) arrives on the ORIGINAL direction, not the reply direction. Previously the SynRecv→Established transition was gated on is_orig==false, which meant it would never fire after the initial SYN-ACK reply. Connections would stay in SynRecv state forever with ConnState::New. Fix: move SynRecv→Established from reply to orig direction, per Linux nf_conntrack_proto_tcp.c (TCP_CONNTRACK_SYN_RECV fires on IP_CT_DIR_ORIGINAL packets). Reply direction now only handles: - SYN-ACK from responder (SynSent→SynRecv) - FIN from responder (Established→FinWait) - Second FIN from responder (FinWait→TimeWait) - TimeWait timeout extension Orig direction now handles: - ACK from initiator (SynRecv→Established) - FIN from initiator (Established→FinWait) - Second FIN from initiator (FinWait→TimeWait) RST still closes from either direction. All 31 tests pass.
This commit is contained in:
@@ -184,8 +184,14 @@ fn advance_entry_state(entry: &mut ConnEntry, is_orig: bool, ctx: &PacketContext
|
||||
let res_fin = is_fin(flags);
|
||||
|
||||
if is_orig {
|
||||
// Original direction: track FIN as connection teardown.
|
||||
// Original direction: handshake completion and FIN teardown.
|
||||
match entry.tcp_state {
|
||||
TcpTracking::SynRecv => {
|
||||
entry.tcp_state = TcpTracking::Established;
|
||||
entry.state = ConnState::Established;
|
||||
entry.timeout = now + Duration::from_secs(432000);
|
||||
return true;
|
||||
}
|
||||
TcpTracking::Established if res_fin => {
|
||||
entry.tcp_state = TcpTracking::FinWait;
|
||||
entry.timeout = now + Duration::from_secs(120);
|
||||
@@ -199,7 +205,7 @@ fn advance_entry_state(entry: &mut ConnEntry, is_orig: bool, ctx: &PacketContext
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
// Reply direction: handshake establishment and close.
|
||||
// Reply direction: handshake initiation and close.
|
||||
match entry.tcp_state {
|
||||
TcpTracking::None if (flags & 0x12) == 0x12 => {
|
||||
entry.tcp_state = TcpTracking::SynRecv;
|
||||
@@ -211,12 +217,6 @@ fn advance_entry_state(entry: &mut ConnEntry, is_orig: bool, ctx: &PacketContext
|
||||
entry.timeout = now + Duration::from_secs(60);
|
||||
return true;
|
||||
}
|
||||
TcpTracking::SynRecv => {
|
||||
entry.tcp_state = TcpTracking::Established;
|
||||
entry.state = ConnState::Established;
|
||||
entry.timeout = now + Duration::from_secs(432000);
|
||||
return true;
|
||||
}
|
||||
TcpTracking::Established if res_fin => {
|
||||
entry.tcp_state = TcpTracking::FinWait;
|
||||
entry.timeout = now + Duration::from_secs(120);
|
||||
|
||||
Reference in New Issue
Block a user