Firewalls
Stateful firewall
A firewall that remembers connections, so it can allow replies while refusing new connections in.
Each packet is new, established or related. The classic policy: accept established and related, allow new connections from inside, drop new ones from outside. It is about who started the conversation, not which ports are open.
How a stateful firewall works, step by step
A stateless firewall judges each packet alone, by address and port. A stateful one
remembers connections in the kernel's conntrack table, and sorts every packet into a state: new (the first
packet of a flow), established (a packet belonging to a flow already seen), related (a new flow a helper ties
to an existing one, such as an FTP data channel or an ICMP error), or invalid. Follow the
stateful firewall lab, where firewall routes between insideNetwork 10.0.1.0/24
and outsideNetwork 10.0.2.0/24, with insideClient at 10.0.1.10 and outsideServer at 10.0.2.10:
- The inside opens a connection out.
insideClientsends a SYN tooutsideServer. It is new and comes from the inside, so the policy allows it, and conntrack records the flow. - The reply comes home. The server's SYN-ACK is established against that record, so it is accepted even though no rule names the inside host. The classic rule is "accept established and related".
- The outside is shut out. When
outsideClientsends a SYN in to the inside server, it is new from outside. No rule permits a new inbound flow, so the firewall drops it; the inside server never answers. - Direction, not host. Two machines on the same network never cross the firewall, so they talk freely. The rule is about who started the conversation, not which ports are open.
This is the whole logic of a home router's protection and of a VPN gateway: the inside reaches out, replies return, nothing new gets in.
What it looks like on a Linux machine
The lab's three rules compile to iptables on the forward path, a conntrack match carrying the state:
iptables -A NETLAB-FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A NETLAB-FORWARD -s 10.0.1.0/24 -j ACCEPT
iptables -A NETLAB-FORWARD -j DROP
On nftables the same reads ct state established,related accept. While the inside talks to the outside, the
tracked flow shows in conntrack:
$ conntrack -L -p tcp
tcp 6 431999 ESTABLISHED src=10.0.1.10 dst=10.0.2.10 sport=49231 dport=80 src=10.0.2.10 dst=10.0.1.10 sport=80 dport=49231 [ASSURED] mark=0 use=1
[ASSURED] means traffic has gone both ways. Capturing port 80 on the firewall itself shows the asymmetry: the
inside-started handshake crosses both ways, the outside-started SYN dies at the firewall.
IP 10.0.1.10.49231 > 10.0.2.10.80: Flags [S], seq 12..., length 0
IP 10.0.2.10.80 > 10.0.1.10.49231: Flags [S.], seq 98..., ack 12..., length 0
IP 10.0.2.11.51880 > 10.0.1.11.80: Flags [S], seq 44..., length 0
The first two lines are the inside-started handshake, SYN out and SYN-ACK back, both crossing the firewall. The third is the outside client's SYN reaching the firewall; no reply ever follows, because the new inbound flow is dropped.
The outside client's curl -sf --max-time 4 http://10.0.1.11/ just times out; the inside server (10.0.1.11)
sends zero packets back. The same rules underlie the home router in the
NAT and port forward lab and the layered policy of the
access control lists lab.
What goes wrong, and how you see it
Asymmetric routing breaks state. If a flow's reply returns through a different firewall that never saw
the request, conntrack marks it INVALID and drops it. conntrack -S shows the invalid counter rising, and
connections hang. Fix the routing, or the two firewalls must share state.
You forgot the established rule. With only "allow new from inside", even the inside's own replies are judged new
and dropped, so nothing works in either direction. Accept established,related first.
A helper is missing. Active FTP's data channel is a related flow a helper recognises. Without
nf_conntrack_ftp, the data connection looks new and is dropped; the control channel works but transfers stall. See
the FTP active and passive lab.
Idle flows expire. A UDP conntrack entry lives 30 seconds, an established TCP one much longer. A long-idle connection whose entry has timed out is treated as new and blocked; keepalives hold the entry open.
Questions people ask
Stateful vs stateless firewall? A stateless filter decides packet by packet on addresses and ports; a stateful one tracks the connection, so a single "accept established,related" rule lets every reply home without opening ports inbound. It is simpler and safer.
Is a stateful firewall the same as NAT? No. NAT also uses conntrack and blocks unsolicited inbound as a side effect, but a firewall's protection is the explicit policy you can read, and it works on IPv6 where NAT is not used.
What are related connections? New flows a helper ties to one already allowed: FTP data channels, SIP media, and ICMP errors about a tracked flow. They are accepted by the same established,related rule.