pfSense TCP retransmissions flagged as out-of-state: when does sloppy state tracking help?
0 reputation · 05 Jul 2026, 04:22 UTC
0 reputation · 05 Jul 2026, 04:22 UTC
I want pfSense to tolerate TCP retransmissions (retries) on a connection without tearing down the state entry or causing the application to re-issue writes, while still keeping stateful inspection strict enough to be meaningful.
pfSense uses the pf stateful engine: once a packet matches a pass rule, subsequent packets in the flow are matched against the state table by 5-tuple rather than re-evaluated against rules. By default, state tracking checks TCP sequence windows, so retransmitted or out-of-window segments can fail state matching. There is a documented "sloppy" state option per rule that relaxes sequence number checking, and there are state timeout settings under System > Advanced > Firewall & NAT. My concern is a path where latency or asymmetric routing may produce retries that the firewall treats as not belonging to the established state.
Assume a current pfSense Plus/CE release; exact behavior may vary by version, so I plan to verify against Diagnostics > States and Status > System Logs > Firewall.
35275 reputation · 05 Jul 2026, 06:30 UTC
By default, pf's state engine enforces TCP sequence-window checks, so a retransmitted segment that falls outside the currently accepted window is treated as out-of-state: it is dropped and, if logging is enabled on the rule, shows up as a state mismatch (messages such as "state mismatch" or "bad tcp window"). It is not silently associated with the existing state. Enabling the per-rule sloppy state option relaxes exactly that sequence-number validation, and the timeouts that matter for very late retries are the TCP state timeouts under System > Advanced > Firewall & NAT, chiefly TCP.ESTABLISHED.
Once a pass rule creates a state entry, later packets in the flow are matched against the state table by 5-tuple, not re-evaluated against rules. With strict state tracking (the default), pf also validates that TCP sequence numbers fall inside the negotiated window. A retransmission that arrives after the window has advanced past it fails that check, is dropped, and is logged as a state mismatch if the rule logs blocked traffic. The state entry itself is not torn down by a single bad packet, but the application sees a stall and may re-issue writes or time out.
The sloppy state option on a pass rule keeps 5-tuple matching and basic flag/header sanity checks, but stops enforcing the strict sequence-number window. A packet that matches an existing connection's 5-tuple is accepted even if its sequence number is outside the current window. That is precisely what you want when latency, asymmetric routing, or a middlebox produces legitimate retries that strict tracking would reject.
The trade-off is real but bounded: sloppy state does not let arbitrary traffic through — the packet must still match an existing state — but it does widen acceptance to replayed or injected segments that would otherwise be rejected by sequence validation. Scope it to the specific rule and direction where you see the problem, ideally on trusted internal paths, rather than enabling it globally.
If a retransmission arrives after the state entry has expired, the packet is evaluated as new traffic and will be dropped unless a pass rule matches it. The relevant knobs under System > Advanced > Firewall & NAT are the TCP timeouts — TCP.ESTABLISHED is the one that governs an open connection, with TCP.OPEN, TCP.CLOSING, TCP.FIN_WAIT, and TCP.TIME_WAIT covering setup and teardown. If your path delay plus retransmission back-off approaches the ESTABLISHED timeout, raising it keeps the state alive long enough for late retries to match. Do this conservatively: very large timeouts leave stale entries consuming state-table memory.
Exact log wording and timeout defaults vary between pfSense CE and Plus releases, so confirm against your version's logs before tuning. One detail that would sharpen the recommendation: whether the path is actually asymmetric (different return route) — if so, fixing the routing or using sloppy state on both legs matters more than any timeout change.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.