The Case for Stateful Firewalls

08 Feb, 2026    

Unlike stateless firewalls where each packet is individually checked, stateful firewalls maintain a table that tracks active connections. In what scenarios would we want to have such a thing?

The simplest scenario that I can think of is probably one of the usual home network, which is intended to be private - in such a case, the typical setup would be to block all inbound connections but allow all outbound connections. Without a stateful firewall, all your packets to the internet would be unable to receive a response, because of the default “block all inbound connections” policy. In such a case, the usual scenario is to give exceptions to already established connections to allow them through.

With this very basic idea in mind, there are actually quite a few interesting tricks one can do to maximise such stateful firewalls.

Let’s consider a very simple scenario. I have two PCs, A and B, which are located inside two different private networks, and I want to establish a direct UDP connection between these two PCs. How might I do that? When allowed to introduce a public proxy that can be used between them, the proxy can be used to exchange details between A and B about what each other’s IP and temporary port numbers are. In an ideal world, that would be all you need to do. However, the lack of IPV4 addresses to go around means that Network Address Translation (NAT) is a thing that needs to be resolved. I want to say that ideally this should just be an IPV4 problem, but I’ve seen that NAT exists for IPV6 as well…(groans). Anyway, there’s a well known technique called UDP hole punching that can be used to establish direct connections where NAT is involved.

To add on, this is actually the example I encountered recently when I was trying to understand, on a high level, how tailscale works under the hood. In fact, they have a very nice article on how NAT traversal works as well as some other difficult scenarios (eg. symmetric NAT) that need to be handled. When attempting to perform a ping from A to B, the first few packets (three in my tests) went through the proxy (basically a tailscale DERP server) before A could finally directly connect to B without any packet loss.