Skip to main content
RunBook Academy

OPNsenseXI · Firewall StatesFirewall state operations

State lifetimes and timeouts — TCP, UDP and ICMP

Intermediate⏱ ~13 minpfctlsysctl

What you'll learn

  • Explain the default timeouts for TCP, UDP and ICMP state entries
  • Describe how the TCP state machine affects timeout selection
  • Identify production scenarios where the default timeouts are too short
  • Apply per-rule timeout overrides for protocols with application-level pacing

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14

Not yet marked complete on this device.

State entries are not permanent. Every entry has a timeout, and the timeout depends on the protocol and (for TCP) the state machine position. The default timeouts are conservative — designed for typical traffic — but production environments include flows that do not match the assumptions.

This lesson covers how the timeouts are set, how they cascade through the TCP state machine, and the production tuning patterns that keep the right flows alive.

The three default timeouts

PF uses three primary timeouts, one per protocol family:

  • TCP. Variable. The default for an established TCP connection is 24 hours (86400 seconds).
  • UDP. 60 seconds. Refreshed by any matching packet in either direction.
  • ICMP. 20 seconds. Refreshed by any matching packet in either direction.

These are the defaults in the normal optimisation profile under System → Firewall → Advanced → Optimisation.

The TCP timeout cascade

PF does not use a single timeout for TCP. It uses a cascade based on the TCP state machine position. The same flow has different timeouts at different states.

The cascade:

StateDefault timeoutNotes
SYN_SENT:SYN_SENT30 secondsFirst SYN observed.
SYN_SENT:ESTABLISHED30 secondsSYN-ACK arrived, final ACK pending.
ESTABLISHED:ESTABLISHED86400 seconds (24 hours)Handshake complete.
FIN_WAIT_130 secondsFirst FIN sent.
FIN_WAIT_230 secondsFirst FIN acknowledged.
TIME_WAIT30 secondsBoth sides closed.
CLOSE_WAIT1 hourPeer sent FIN.
LAST_ACK30 secondsLocal side sent FIN.
Read-only / Safepfctl -s state -v (timeouts)
$ pfctl -s state -v | grep -E 'ESTABLISHED|TIME_WAIT|FIN_WAIT|CLOSE_WAIT' | head -10
all tcp 192.0.2.50:22 <- 203.0.113.50:51820 ESTABLISHED:ESTABLISHED
 age 12:34:56, expires in 11:25:04, packets: 245 bytes: 31200
all tcp 192.0.2.50:22 <- 203.0.113.50:51821 ESTABLISHED:ESTABLISHED
 age 00:00:12, expires in 23:59:48, packets: 5 bytes: 240
all tcp 192.0.2.50:443 <- 10.0.0.50:54321 TIME_WAIT:TIME_WAIT
 age 00:00:02, expires in 00:00:28, packets: 142 bytes: 21800
all tcp 192.0.2.50:443 <- 10.0.0.50:54322 FIN_WAIT_2:FIN_WAIT_2
 age 00:05:00, expires in 00:00:00, packets: 50 bytes: 8000

Illustrative output

Why ESTABLISHED gets the long timeout

ESTABLISHED is the steady state of a normal TCP connection. The handshake is complete, data is flowing or could flow at any moment, and the connection should survive long periods of inactivity. A short ESTABLISHED timeout would force idle connections to be re-established repeatedly.

The 24-hour default assumes that legitimate TCP connections are either actively transferring data or will be re-established by the application within 24 hours. This is not always true:

  • Legacy applications with no keepalive. A database connection that the application opens once and uses intermittently.
  • Long-running monitoring sessions. A monitoring tool that opens a TCP session and holds it open for days.
  • Backup streams. A backup client that opens a TCP session, transfers for hours, then is idle for hours.

UDP: 60 seconds, refreshed by traffic

UDP has no state machine; there is no handshake and no closing sequence. The firewall creates a state on the first datagram in one direction; matching packets in the reverse direction match the state. The state is removed when no matching packet has been seen for the timeout period (60 seconds default).

The 60-second default assumes that a UDP flow that has not exchanged any packet in 60 seconds is dead. This is not true for:

  • SIP over UDP. The default 30-second SIP keepalive is below the PF timeout, but jitter and busy CPU can push the keepalive past 60 seconds.
  • IPsec NAT-T keepalives. NAT-T keepalives are sent every 20-30 seconds.
  • Long-lived streaming. A streaming protocol that sends a packet every 90 seconds will see the state expire between packets.

ICMP: 20 seconds

ICMP state is the simplest. The first packet creates a state; the matching reply matches the state. The default timeout is 20 seconds.

For Path MTU Discovery, ICMP type 3 code 4 messages are exchanged during the initial handshake of a TCP connection. The 20-second timeout is sufficient because PMTUD messages only flow during the handshake.

Per-rule timeouts

OPNsense allows per-rule timeout overrides. In the rule edit page, set “State timeout” in seconds. The rule’s timeout overrides the global default for matching flows.

The discipline: do not raise the global timeout to fix a single protocol’s needs. The global timeout affects every flow; per-rule overrides affect only matching flows.

Read-only / Safeper-rule timeouts
$ pfctl -s rules | grep -E 'udp|state-timeout'
@200 pass in quick on igb0 inet proto udp from any to any port = 5060
[ SIP signalling — UDP state timeout 120s. Owner: NetOps. Ticket: NET-2010. ]
@210 pass in quick on igb0 inet proto udp from any to any port = 4500
[ IPsec NAT-T keepalives — UDP state timeout 60s. Owner: NetOps. Ticket: NET-2011. ]

Illustrative output

Production tuning patterns

Three patterns show up in production environments:

Long-lived TCP without application keepalive

A legacy application opens a TCP connection and uses it intermittently without keepalives. The state expires after 24 hours of inactivity. The fix options:

  • Application keepalive. Configure the application to send a TCP keepalive or an application-level ping every 30 minutes.
  • Per-rule timeout. Raise the per-rule timeout to 7 days or longer.
  • Wrapper. Wrap the application with a tool that maintains the TCP session.

UDP-based real-time protocols

VoIP (SIP, RTP), video conferencing, real-time gaming. The UDP state expires between packets. The fix:

  • Per-rule timeout. Raise the UDP timeout to cover the protocol’s worst-case packet interval.
  • Application keepalive. Some protocols send application-level keepalives on the same five-tuple.

TCP sessions that should never expire

VPN tunnels, long-lived monitoring, replication streams. The fix:

  • TCP keepalive. The application enables TCP keepalive.
  • Application-level traffic. The application sends data or pings on a regular interval.

Summary

  • TCP ESTABLISHED default: 24 hours. Other TCP states have shorter timeouts.
  • UDP default: 60 seconds, refreshed by traffic.
  • ICMP default: 20 seconds.
  • Per-rule timeout overrides are the right tool for protocols that need longer timeouts.
  • UDP refreshes only on packets matching the five-tuple, not on application-level keepalives.
  • Timeouts are set at state creation; existing states keep their original timeout.

Knowledge check · 4 questions

  1. Q1. A SIP phone sends a keepalive every 30 seconds. The SIP server is on a remote network. PF state shows the state expires every time the keepalive is delayed past 60 seconds by jitter. The next keepalive is treated as a new INVITE and the SIP server drops the call. What is the correct fix?

  2. Q2. PF refreshes a UDP state entry when the application sends an application-level keepalive packet inside the UDP payload.

  3. Q3. Which of the following are reasons to apply a per-rule timeout override in OPNsense? Select all that apply.

  4. Q4. You raise the per-rule timeout on a rule from 60 seconds to 600 seconds. Existing TCP sessions that match the rule continue to expire at 60 seconds. What is the most likely explanation?

Passing score: 75%. Answers are checked in this browser.