Additional Articles
Here are more interesting articles on Embedded, ZFS, and FreeBSD that you may find useful:
- Winter 2024 Roundup: Storage and Network Diagnostics
- FreeBSD 14 replaces Sendmail with DMA
- ZFS Storage Fault Management on Linux
- Fall 2024 Top Reads for Open Source Enthusiasts
- Deploying pNFS file sharing with FreeBSD
- Applying the ARC Algorithm to the ARC
- Introducing OpenZFS Fast Dedup
- DKMS vs kmod: The Essential Guide for ZFS on Linux
When it comes to choosing a firewall technology for your operating system, the options can be overwhelming. This is particularly true for Linux and FreeBSD, which offer multiple choices. In this article, we'll take a closer look at four of the most popular firewall options for both systems: iptables, nftables, ipfw, and pf, to help you make an informed decision.
So here's our contribution to the effort, this article is essentially your four-way comparison of iptables, nftables, IPFW and PF.
In the first article of this series, we covered the major differences between two types of firewalls platforms - either Linux or FreeBSD based and what the options are. We covered how pf, IPFW, iptables and nftables act when actions are applied to different packages and just in general the differences between deploying a FreeBSD-based firewall and a Linux-based firewall. In the second part, we go a bit deeper and discuss how egress filtering is done, and how tables and sets are built.
Egress Filtering
For our second example, we'll consider the case of filtering outgoing packets.
When a firewall rule determines that a particular packet should be blocked, it can either silently drop the packet or it can send an ICMP error response to the sender. If the purpose of your firewall is to protect against malevolent actors it can be better to simply drop the packet. This avoids revealing information about the structure of your network and reduces the effectiveness of denial-of-service type attacks. However, if you are filtering outgoing packets from your network, the ICMP errors can allow your software to quickly return an error message instead of waiting until a timeout has elapsed.
Let's suppose we have some software that bypasses the system DNS settings and goes directly to a public name server, and we want to prevent it from doing this.
iptables
For iptables, we now use the OUTPUT chain. The protocol and port are also included, though you might choose to leave them out and simply block all packets to the destination addresses. The -d option allows for matching on the destination address. The REJECT jump target is an extension rather than a chain and enables the --reject-with option to select the specific type of response to send.
iptables -A OUTPUT -p udp -d 8.8.8.8,8.8.4.4 --dport 53 -j REJECT \ --reject-with icmp-port-unreachable
nftables
As before, the nftables example needs an appropriately named chain and table combination. Assuming those exist, the rule would be as follows:
nft add rule inet filter output ip daddr '{ 8.8.8.8, 8.8.4.4 }' udp \ dport 53 reject with icmp port-unreachable
IPFW
IPFW has "unreach" as an action, so it comes first with the following word "port" indicating the type of ICMP error it should throw.
ipfw add unreach port udp from any to 8.8.4.4,8.8.8.8 53 out
PF
For PF, we could set the block-policy option to use ICMP returns for all block rules—but here, we use a per-rule option. For the rule itself, differences are only cosmetic and there is nothing remarkable in the PF example.
block return-icmp out proto udp to { 8.8.8.8, 8.8.4.4 } port 53
With PF, rules are defined in a configuration file named /etc/pf.conf. For iptables and IPFW, it is common to use a shell script. An advantage of using a shell script is that you can make use of shell features like variables and the sourcecommand for including other files. All four firewalls (and/or the shells they’re managed from) use a dollar symbol for variable references.
PF supports an include keyword in pf.conf to include additional configuration files. Furthermore, as a substitute for shell variables, it supports macros. It is common to use a macro when naming network interfaces so, for example, you might define:
IFACE="bge0"
Rules often allow for a list of values so you might define a macro for the TCP port numbers a mail server needs open, for example:
mail_ports={ 25 110 143 465 587 }
While nftables allows individual rules to be added from the command line with the nft command, it also supports a config file. The config file supports rules in the same form they are specified with nft along with include files and variables, for example:
define IFACE = eno1
While the pfctl command doesn't support filtering rules specified directly as arguments, it can be used to change the ruleset. To facilitate this the configuration file needs to reference an anchor. pfctl can then be used to load rules into the anchor. Aside from being useful for dynamic rule changes, this can be convenient when testing out rules.
In general, PF anchors allow a number of rules to be associated together so that they can be manipulated together much as can be done with chains on Linux. The nearest IPFW equivalent is sets which are numbered rather than named.
The consistent structure in the initial part of IPFW rules helps with clarity when viewing a large number of rules, since leading common elements align vertically. More unusual rule options come last, can be ordered flexibly, and are always preceded by an identifying word such as "dst-port" rather than being implicit.
ipfw add 420 allow tcp from any to me 25,110,143 in
PF
PF uses the word "pass" to denote packets that are accepted. Otherwise, the rule resembles that for IPFW closely enough that the explanation of individual elements need not be repeated. Because PF uses a configuration file, there is no shell quoting for the braces as in earlier examples.
pass in proto tcp from any to any port {25, 110, 143}
Tables and Sets
When matching many IP addresses in a firewall rule it would be clumsy to need to list many different addresses. Linux has a feature named IP sets for maintaining lists of network addresses and port numbers. This allows firewall rules to target just the name of the set. In addition to being more flexible in allowing for dynamic changes, sets also facilitate much more efficient implementations of address matching for lists containing many addresses. IP sets are common to both iptables and nftables. The sets can be manipulated using the ipset(8) utility.
Both IPFW and PF have their own separate concept of tables for maintaining large lists of network addresses or values of other types to be referenced from firewall rules. These serve the same purpose as IP sets and have the same benefits.
Tools such as sshguard and fail2ban, which detect brute-force attacks by watching log files, use these address tables to block offending hosts. FreeBSD includes blacklistd in base, which does likewise
—albeit using an interface for other services to report failed connections directly, instead of scanning log files.
Listing Rules and Viewing Counters
When testing rules it can be very useful to see what rules are active, and which are triggering on incoming packets. For the latter purpose, counters are maintained. The following table shows the basic commands related to this.
iptables | nftables | IPFW | PF | |
List the rules | iptables -S | nft list ruleset | ipfw list | pfctl -s rules |
Show counters | iptables -vnL | nft list counters | ipfw show | pfctl -vs rules |
Zero counters | iptables -Z | nft reset counters | ipfw zero | pfctl -z |
nftables won't keep counts of packets unless you specifically add a counter. With IPFW it is often useful to test rules with an action of "count" just to see the counts.
Aside from counters there is also the possibility to add logging.
Conclusion
By covering four separate firewalls we've only been able to scratch the surface of their capabilities. They are all highly versatile and can be adapted to a variety of needs.
Of the four, iptables has the least clear syntax but is easy to learn and use. nftables clearly improves on it but can appear overwhelming initially. It incurs some complexity from the legacy of its predecessors – both iptables and the even earlier ipchains – as many concepts were carried forward. With a grasp of nftable's basic concepts, it is not hard to use and the benefits of its design show. IPFW's documentation is easy to follow and it manages to be simple without compromising on capability, but there are areas where it shows its age. PF probably has the clearest rule syntax and feels like a clean modern design.
See Also
Nftables Wiki In particular, the page on nftables hooks has a diagram which is very helpful for understanding both the hooks and, by extension, iptables chains.
FreeBSD Handbook, Chapter 32. Firewalls
ipset(8) – https://manpages.debian.org/bullseye/ipset/ipset.8.en.html
pf.conf(5) – https://man.freebsd.org/cgi/man.cgi?query=pf.conf
pfctl(8) – https://man.freebsd.org/cgi/man.cgi?query=pfctl
ipfw(8) – https://man.freebsd.org/cgi/man.cgi?query=ipfw
Other FreeBSD vs. Linux Resources
We’ve written quite a bit in the past about making the right choice between the two operating systems. So here are some useful reads when trying to make a choice between FreeBSD and Linux:
1. FreeBSD vs Linux – Which Operating System to use for OpenZFS
In December 2020, the OpenZFS project completed unifying the OpenZFS codebase between the FreeBSD and Linux platforms. This helps ensure cross-compatibility between the two—but there are still some implementation and even a few feature differences worth paying attention to. This write-up goes over the remaining OpenZFS differences, to help anyone on the fence decide which OS to use beneath our favorite filesystem.
2. FreeBSD vs. Linux – Networking At A Glance
Network is incredibly important in every infrastructure, and network configuration differences can be pretty challenging between different OSes. This article covers several network technologies where Linux and FreeBSD have equivalent but different implementations and how to work with them.
3. FreeBSD vs. Linux – Virtualization Showdown with bhyve and KVM
Although the bhyve management ecosystem is currently quite limited in comparison to Linux’s KVM, its performance is already quite impressive. For storage-heavy workloads, the benefit of bhyve’s emulated NVMe controller is difficult to overstate—it produced massive throughput improvements that even a long-time KVM fan simply cannot ignore.
4. FreeBSD vs. Linux – Package Management
Package managers on various Unix distributions make it easy for system administrators to manage the software installed on the operating system. Packages are an easy, straightforward way to install software that avoids time-consuming configure, compile, install sequences. The popularity of package managers permeates all Unix distributions. Yet there are subtle differences in the approach that Linux vs. FreeBSD take in handling packages. How does Linux compare to FreeBSD's way of managing packages?
Are you looking to migrate from a Linux-based environment to FreeBSD? How would you go about it?
5. Easily Migrating from Linux to FreeBSD
If you are already experienced with Linux, FreeBSD should feel very familiar. The operating systems have a lot in common, due both to their Unix heritage and many shared modern components. Much of what may be unfamiliar to a Linux user adopting FreeBSD is also inconsistent between Linux distributions themselves. This article covers some of the conceptual differences between Linux and FreeBSD, and go on to contrast some aspects of the basic system utilities and the differing views of hardware given by the two systems.
6. Linux and FreeBSD Firewalls - The Ultimate Guide
If you're looking to understand security at its most basic level in FreeBSD vs. Linux there's no better way to start than with how firewalls are being implemented in the two different environments. Take a deeper dive in this two-part article series and understand how different firewalls are implemented in FreeBSD and Linux and what the advantages to them are.
officeklara
Learn About KlaraWhat makes us different, is our dedication to the FreeBSD project.
Through our commitment to the project, we ensure that you, our customers, are always on the receiving end of the best development for FreeBSD. With our values deeply tied into the community, and our developers a major part of it, we exist on the border between your infrastructure and the open source world.