Back to Blog

pfSense, FreeBSD

Updates to the pf packet filter in FreeBSD and pfSense software

Updates to the pf packet filter in FreeBSD and pfSense software

Overview

The pf firewall, integral to pfSense and FreeBSD, originated on OpenBSD in 2001 and was ported to FreeBSD in 2004. In fact, using the then new pf instead of ipf was one of the primary reasons driving the 2004 fork of pfSense from m0n0wall and even the resulting name of pfSense. While the two versions of pf share significant code due to their common origin, they diverged starting in 2013, with only a few selective patches exchanged since. 

Over the years this difference between OpenBSD and FreeBSD was a common point of discussion, often in overly generalised (and as a result, deeply inaccurate) terms. Thanks to recent efforts by Kristof Provost and Kajetan Staszkiewicz focused on aligning FreeBSD’s pf with the one in OpenBSD, that discussion can be put to rest.

This work has been largely sponsored by Netgate, and most updates are slated for inclusion in FreeBSD 15.0, expected in December 2025, with potential inclusion in a release of pfSense software around that time.

Technical Differences

FreeBSD and OpenBSD, as distinct operating systems, employ different internal APIs and priorities, leading to accumulated differences in their pf implementations. For instance, OpenBSD uses pool_get() for memory allocation, while FreeBSD uses uma_zalloc(), requiring straightforward adaptations.

More complex differences include FreeBSD’s support for VIMAGE, enabling network stack virtualization for isolated pf instances within jails, a feature absent in OpenBSD but retained, and especially useful for testing purposes, in FreeBSD. Additionally, FreeBSD’s pf includes fine-grained locking for improved performance, introduced by Gleb Smirnoff in 2012.  The pf in FreeBSD also supports features like SCTP and basic layer-2 filtering, both of which OpenBSD lacks.

Subtle discrepancies also arise, such as variations in the getaddrinfo() function. OpenBSD returns an error for the input ‘10’, while FreeBSD interprets it as the IPv4 address 0.0.0.10, necessitating specific adjustments, as seen in commits like cbca60158062 and da27faa01f27.

Update Process and Challenges

Due to these and other differences, direct importation of OpenBSD’s pf code into FreeBSD is infeasible. Instead, relevant OpenBSD patches have been manually applied in chronological order, adjusted for compatibility, and supplemented with new test cases to prevent regressions.

This meticulous process has been supported by an extensive pf test suite, exemplified by commit 05c33e5acb67, which added tests for recursive rule flushing introduced in 041ce1d690f1. Pure refactoring patches, such as dd06ff741938, are also imported to reduce codebase divergence, facilitating future updates.

Bidirectional Contributions

While most updates flow from OpenBSD to FreeBSD, contributions also move in the opposite direction. For example, a FreeBSD-identified issue in NAT64 ICMP error translation, reported by Lexi Winter, was addressed in both systems after OpenBSD refined the proposed fix (FreeBSD bug 284944). Similarly, a cleanup in pfctl removed duplicated code in OpenBSD, as seen in commit e43b47e3cf56.

New Features

Recent imports have introduced several enhancements:

  • Commit 613a144a4b78 adds a reset function to pfctl for managing limits, timeouts, and debug levels.
  • Commit 041ce1d690f1 enables recursive flushing of firewall rules, including those in anchors.
  • Commit ff11f1c8c76c introduces packet rate matching, allowing restrictions like limiting ICMP echo packets to 10 per second from a specific host.

Additionally, FreeBSD 14 introduced stateful scrubbing (e.g., pass … scrub ( max-mss 1300 )), enhancing performance for multiple scrub rules. FreeBSD 15.0 will support OpenBSD-style NAT configuration (e.g. pass out on $EXT_IF from 198.51.100.0/24 to any nat-to $EXT_IF), enabling precise filtering, such as selective NAT for ICMP Echo Requests.  This work was contributed by Kajetan Staszkiewicz and sponsored by InnoGames GmbH.

Conclusion

The ongoing synchronization of OpenBSD’s pf advancements into FreeBSD, nearing completion for FreeBSD 15.0, enhances the firewall’s performance, security, and compatibility with multiprocessor kernels. These improvements benefit both FreeBSD, pfSense, as well as downstream projects, while also fostering collaboration with OpenBSD developers and delivering a major component of a modern, robust firewall solution.