Simple methods for complex firewalls
An easy diagram for visualizing firewalls with multiple interfaces across multiple different networks, and some useful firewalling tips!
I wanted to share a simple visual aid I found useful when it comes to trying to disentangle firewall rules involving many interfaces.
With basic SoHo gateways, firewall rules are fairly easy to visualize. They're entirely designed around blocking unwanted traffic from the WAN interface, and statefully allow traffic from the LAN to go out as needed. There is only one direction to keep in mind, and only a single internal network to worry about.
Things get quite a bit more complicated when operating a more complicated firewall that has influence over multiple internal networks through multiple interfaces. When I first switched over to using a pfSense running quite a few VLANs in my home lab, I had a bit of experimenting to do to figure out which direction the firewall was enforcing for each network interface. Was every rule set on every interface acting bi-direcitonally? Was it only blocking downstream? Were some upstream and some downstream? What is the best way for me to be thinking about this?
I came across a very nice illustration somewhere in my searches. Unfortunately, I wasn't able to dig up the link to be able to share the original diagram. But the visualization stuck with me and has proven to greatly simplify the way I think about my firewall when I need to create new rules.
Let's start with a single interface. The blue is the traffic coming from that network. The red is a unidirectional firewall. Unless specifically told to allow certain traffic types through, it will block all traffic coming from that network (implicit default deny).
If this is a WAN interface, it should be blocking everything by default.
If this is a LAN interface, there should be an allow rule to let the traffic out unless there is a good reason for the network to be isolated.
Let's put a bunch of different interfaces together, now.
The new feature in the middle can be thought of as a "trusted circle".
If traffic from one of the interfaces passes one of its firewall's rules, it is allowed to join the trusted circle. From there, it can be passed along to anywhere else. Because from the direction of the trusted circle, the unidirectional firewalls are not enforcing any rules from that direction.
This shift in perspective answered my internal dialogue about which directions firewalls were facing on which interfaces. It wasn't a matter of upstream to downstream, or from the external to the internal. It was a matter of thinking of each interface as being outside the firewall's trust, and whether or not it would let the traffic in to pass through.
Some other helpful things to keep in mind
That's it for the visualization. That's mainly what I wanted to share. But while you're here, I may as well list out a few other things that I've helpful to keep in mind about firewall rules. [Should be noted that I haven't, by any means, worked with all varieties of firewalls. Thare general rules, but there may be exceptions. When in doubt, RTFM for your specific hardware.]
If nothing else, there is always implicit deny
It's an unwritten (or at least undisplayed) law of firewalls that if no rules apply to the traffic, it will be denied trust.
Rule order is top to bottom
Pretty straightforward. It goes down the list and checks the traffic against each rule until it finds one that applies. If none of the rules apply, it's saved from the spiraling descent into oblivion by the good grace of implicit deny, which banishes it from this plane of existence.
The first rule that applies is the rule that sticks
Whether it's a deny or a pass, if it fits, it sits. So when going down the list from top to bottom, if the first rule that applies to the traffic is a deny rule, the traffic is denied even if there is another rule further down that would also pass it. This makes the order of rules important to keep in mind.
Once traffic is trusted, there isn't a second chance
Unless there's a second firewall somewhere down the pipeline, of course. But speaking in terms of a single firewall handling traffic from multiple networks, the rules for each network interface must be designed around whatever traffic is expected from that network. If traffic from Network A to Network B must be blocked, it needs to be blocked on Network A's interface. Network B's unidirectional rules won't apply to that traffic. (Other means of disabling inter-network traffic can be utilized as well, but I'm referring to the firewall-specific methodology of limiting network access here.)
Setting a source port is rarely ever necessary
If you find yourself setting a source port for something, odds are that you're attempting to do something unnecessary. Source ports are often randomly chosen by an application. The destination ports are the ones that stay static, but the source ports are not usually required to be the same. If you find yourself saying, "But this port is always the same and I want to allow traffic to it," it's more than likely because the visualization of the flow of traffic through the firewall's interfaces got a bit muddled.
To explain a bit further, let's bring up an embarrassingly incorrect thing I tried to do before I realized what was going on. I set an allow rule for traffic on an internal network for a port on local computer running a server. I set the source address for the computer and the source port for the service. Doing this didn't break anything. But it was entirely useless because there was an allow rule immediately below it that would have also applied. But I thought that it might fix a problem I was having with connecting to that service because I was explicitly stating it.
So this hint is not so much about keeping anyone from breaking something. It's more of a bellwether. If you find yourself doing it, odds are good that it's because of an underlying misconception. (Most of the misconceptions that led me to making these types of errors were resolved by the visualization in this article.)
Allowing traffic for a port is not the same as port forwarding
On SoHo gateways, port forwarding is generally a one-step deal. By creating a port forward, the gateway usually creates a firewall and a Network Address Translation (NAT) rule without the end user having to worry too much about the specifics. With more advanced features comes more requirements. Firewall rules and NAT are often handled separately on more capable network equipment.
Creating a firewall rule to allow traffic targeting a certain port doesn't necessarily do the trick for getting the traffic to its destination. That's because computers external to your network are not and should not be allowed to address computers in your local network directly (at least not with IPv4). The device that's connecting to WAN, usually your firewall, is the one that receives the traffic. For that device to know how to direct external traffic to an internal address, it needs to be told how. And that happens in the form of a NAT rule. NAT will actually change the information in the Frame and Packet layers to adjust destination accordingly. (Read here for more information on network layers and TCP/IP.)
It's not just NAT that does the trick, either. First a packet must pass a firewall rule and be considered trusted. Then it needs to be told where to go with NAT.
For local traffic, NAT is not as much of a concern (although it can still be relevant in some configurations). Most of the time, you're able to address another local computer even if it's on a different subnet.
More information about the differences between local and external addressing can be found in RFC 1918, which details the exhaustion of the IPv4 addressing scheme and designates reserved ranges for private use.
NAT is not usually needed for IPv6, but since most current internet traffic still involved IPv4, NAT is a necessary step in directing external traffic to internal resources.
When in doubt, test it and log it
For most of your rules, you probably aren't going to want to log the traffic. Enabling logs for allowed connections can rapidly fill up your logs, and even edge case deny rules can spam a surprising amount if there's an unruly device on your network that insists upon sending out that one annoying packet every thirty seconds.
But for troubleshooting purposes, the enabling logging can give you immediate x-ray vision to see how far through the network a given packet is getting before spiraling into oblivion. Simply set up a rule you want to test, enable logging, send the packet, and check the logs. If the rule generates a log entry, you'll have immediate verification that it's working as intended. If it fails to generate an entry, a different rule is applying to the traffic before meeting the rule you're logging. Check all the things listed above such as rule order and interface direction, change things around, and test again until you're able to generate a log entry.
Once you've got it set up in a way that's working, you can disable logging so it's not clogging up the works with unnecessary verbosity.
That's about it! If I come across more useful things, I might add them on. But I wanted to keep this one fairly short and sweet. Have a good one!