Feature: Porting The PF Stateful Packet Filter Submitted by Jeremy on Tuesday, April 08, 2003 - 23:52
The upcoming release of OpenBSD 3.3 on May 1'st will include, among many other improvements, a notably enhanced version of PF, OpenBSD's stateful packet filter. Some of the more significant enhancements to PF include: 'queues', allowing for per-rule bandwidth control [story]; 'pool options', allowing one to utilize multiple uplinks and to intelligently redirect traffic to multiple servers; 'anchors', which allow one to divide packet filtering rule lists into logical pieces; 'tables', efficiently allowing for very large lists; and other parser improvements that make an already friendly syntax more human readable.

PF replaced its predecessor, IPF, with the release of OpenBSD 3.0 in December of 2001. Since that time, this impressive and relatively new packet filter has grown a faithful following (myself included), and continues to evolve rapidly with each new OpenBSD release. Perhaps the greatest compliment, developers have begun to port PF to other operating systems. Back in January, Joel Wilsson announced his effort to port PF to NetBSD. And more recently, Pyun YongHyeon announced his port for FreeBSD.

I approached Pyun to learn more about his recent porting efforts. In the following article he explains why he began working on this port, and what FreeBSD users can expect from the project. Additionally, I spoke with PF creator Daniel Hartmeier [interview], PF developer Henning Brauer, and OpenBSD creator Theo de Raadt [interview]. They all reflect on these recent porting efforts, as well as the exciting new features found in OpenBSD's PF.
Porting PF to FreeBSD

Pyun YongHyeon announced his port of PF to FreeBSD in the end of March, however the effort began a month before that. Pyun explains, "Since the release of OpenBSD 3.0, pf was [the] primary firewall on my company's office. At that time pf was basically the same as ipfilter. ipfilter has more advantages on state tracking against ipfw. pf has supported all alike features. I loved pf's features and saw its possibility of latent powers.

"Because I'm FreeBSD user I really have wanted to run it on my FreeBSD machine. If FreeBSD can run it, pf can make full advantage of advanced features of FreeBSD such as SMP, KSE, etc. I had looked forward to running pf on FreeBSD. Because any one who ever used pf would know its advantages over ipfw, it was matter of time.

"I had seen many requests for pf on FreeBSD but core members of FreeBSD had not merged pf. It seemed that they did not need another packet filter any more due to FreeBSD supporting both ipfw and ipfilter. I got tired of waiting for pf, have changed my mind to do it myself at about the end of Feb. 2003."

The homepage for Pyun's FreeBSD port of PF includes an earlier version based upon the current OpenBSD 3.2, as well as another more recent port based on the upcoming OpenBSD 3.3. I asked Pyun how complete and functional he felt his port was, to which he replied, " How complete/functional is a very difficult question. pf is far from complete. The port is in ALPHA stage. Many features of pf have not been tested yet. Although basic features of pf such as filtering, state tracking, 1:N NAT works fine on my box. All support code from pf was included except ALTQ. pf has many features and it takes time to experiment with all of it. It needs more feedback from users for [this project to be a] success."

That begs the question, what's left to be done? Pyun explained that his current port disables ALTQ until ALTQ is added to the FreeBSD 5 tree. Pyun went on to say, "In addition to this, there are many things left to do. Here are some of them.
  1. bug fix if any
  2. test for various rules
  3. test for load balancing
  4. test for IPv6
  5. make FreeBSD port
  6. cope with FreeBSD 5 current.
"I have made my level best to port it as it is in OpenBSD. But there are substantial differences between FreeBSD and OpenBSD. To port it as exact as possible, FreeBSD kernel code and data structures should be changed. It would be rejected by core members because its aspect on pf."

When I asked Pyun if he had received any help from OpenBSD developers when porting PF, he explained, "No. I have not even tried it. But reading the FAQ and mailing lists on pf was great help to me. It was my own desire to run pf on FreeBSD by myself due to no one ever [having] tried it. Also I thought this is not an issue for OpenBSD developers. (They already have perfect pf.) Actually, I have not mailed to any OpenBSD developers. Only after my first port came out, I have written to OpenBSD Journal."

We went on to discuss the feedback that Pyun has received since announcing his port. He said, "Unfortunately, I have not gotten a mail from FreeBSD kernel developers yet. They may not even know about pf for FreeBSD.

"I got many replies from both FreeBSD and OpenBSD users. Most of them were from users who used pf on OpenBSD. Some of them offered a dedicated home page. Many of them said words of encouragement and thanks. Especially, Max Laier has set up a dedicated home page and CVS server. He also has become co-developer for pf on FreeBSD. Without his enthusiastic help and patience on my broken english, it would not be possible to continue porting pf. Now pf for FreeBSD has an official home page."

Comparing PF To Other Packet Filters

Personally being a fan of PF, I was quite curious to know how it compares to FreeBSD's other packet filters. Pyun noted that while this may be possible eventually, the port is not yet ready for this type of comparison. He explains, "As I said earlier, my port is far from complete. In addition to this, the two have taken different approaches to the same problem. It seems it is a matter of user's taste and policy. ipfw is a good packet filter. It has it own features and advantages over the other packet filter. So direct comparison to ipfw is not possible though I am under a bias toward pf in all aspects."

"When pf for FreeBSD matures we may be able to compare pf with ipfw and ipfilter on the same machine, OS and rules. At that time we can say which one is better than this objectively."

Looking forward, Pyun expressed his hopes for this port, "To me, armed with FreeBSD's advanced feature, just to use pf on FreeBSD as if I can on OpenBSD. To other FreeBSD users, I want to let them know there is another excellent packet filter. To FreeBSD kernel developers, I would like to express demands for pf. In the long run, I look forward to merging pf into the base system."

OpenBSD Developer Reactions

I approached PF creator Daniel Hartmeier to learn if he was aware of Pyun's efforts. Daniel replied, "I just read about the port on deadly.org last week, and I'm in the process of installing a FreeBSD machine so I can test the port. There seems to be some (smaller) problem with rdr and checksums, and I hope I can help track that down and submit a patch to Pyun. I'll also have to see what parts had to be replaced (like mbuf tags) and how they're done in FreeBSD."

Regarding the existence of other ports, Daniel commented, "There was some announcement of a NetBSD port, but I never saw a tarball with sources, so I haven't tested that yet. If someone is actively maintaining or using it, I'd be interested to hear."

Interested in his opinion on these recent porting efforts, I asked Daniel for his reaction. He replied, "It's great to see that people from other BSDs are getting interested in pf, especially when someone with kernel programming knowledge is willing to invest the time to get things working. The more time I see others invest, the more obliged I feel to contribute to the port, of course. It would be great to get the basics working, so people can give it a try and compare the functionality and performance (which I'm quite curious about, too)."

PF developer Henning Brauer also commented on the recent porting efforts, "I appreciate those. Of course, as a pf developer, I'm convinced pf is superior to the other available packet filters, and the fact that ports are done is a sign of appreciation for our work."

The Difficulties Of Porting

Of course, though OpenBSD, NetBSD and FreeBSD share a common ancestry, they have long since diverged paths. As PF lives in the kernel, it's not as simple as recompiling it to get it working on another operating system. I asked Daniel what some of the harder issues might be when porting PF, to which he explained, "There are some parts which rely on things that are done differently on other BSDs (like mbuf tags or pool memory), but there's a counterpart or alternate implementation/api for each of those, I'm sure. One of the new things in 3.3 is the integration of pf with altq, which might be a larger piece of work, if altq isn't part of the target platform yet."

Regarding this recent merge, Theo de Raadt pointed out that it was not a minor effort. He explained, "To make pf and altq get married, altq has been significantly modified. The altq that kjc wrote has been heavily modified on the ioctl-end to be able to merge into the semantics we needed in for queue. If some other system has basic boring regular altq, they have got quite an effort ahead of them."

Henning also reflected on the difficulties of porting PF, adding, "There was more than one NetBSD port. NetBSD is easier as NetBSD is more similar to OpenBSD than FreeBSD, namely, NetBSD has pool(9) and since a few weeks mbuf tags. FreeBSD doesn't have pool(9), so the port to FreeBSD included changing that to zone(9), and they do not have mbuf tags the way we have but use another scheme."

Using The PF Port In FreeBSD

By the time I'd prepared this article, Daniel had already given Pyun's port a preliminary try. He described this experience, saying, "I now have a FreeBSD box running 5.0-RELEASE and the pf port as a kernel module. It will require some serious testing, but the basic functions like filtering statefully and translations (NAT, redirections) work fine so far. It's likely that there are some bugs to be found and fixed, especially in the less commonly used features, but the port appears to be stable and hasn't crashed once for me.

"Max Laier set up a page with the latests tarballs (which include some important bugfixes) and installation instructions on http://pf4freebsd.love2party.net/, I'd recommend fetching the source from there and giving him and Pyun feedback."

What's New With PF In OpenBSD 3.3

One of the biggest changes to PF in OpenBSD 3.3 is the recent merging of ALTQ. Daniel demonstrates the power of this merge in his informative paper titled "Prioritizing empty TCP ACKs with pf and ALTQ", offering instructions on how to configure the packet filter to prevent an upload from affecting download throughput, with impressive results.

Theo was responsible for the initial design of merging ALTQ with PF. The end result, referred to as queueing, offers per-rule bandwidth control. Henning, who lead the actual implementation efforts, describes how the merge resulted in a much different and more powerful queueing engine than the earlier KAME version. He explains, "well, the whole classifier is dead and replaced by pf. That means that this whole part is replaced, and thus, the whole interface is changed. Look, the only kernel<->userland interface is basically feeding the classifier, that sorts packets into different queues, feeding it the rules. Before the merge altq had its own classifier, working on a per interface basis, and being... "hard" to use. Now pf does this. And we work cross-interface, that really rocks: you classify a packet on the incoming interface (an mbuf tag is used and the queuing happens on the outgoing interface...

"Another thing, and that is really new, is the stateful nature you have with using keep state rules and queuing on those. In the state table entries we have a pointer back to the rule that created the state, and from that rule we get the queue ID(s) to classify the packets matching the state. This means you can now prioritize outgoing _connections_ instead of packets. This is really new, connection based queuing instead of packet based."

Theo further describes, "A major part of this design is that you can do queue settings on not just pass rules, but also on block rules. For a block rule, the queue setting is used for any rejection packets. This permits management of icmp or rst traffic."

An overview of the new features found in PF with the upcoming release of OpenBSD 3.3 can be found in these slides from Henning's recent presentation at FOSDEM 2003 in Brussels, Belgium. A complete overview of the packet filter including the new features can be found in these slides from Daniel's recent presentation at LinuxForum in Copenhagen, Denmark.

Daniel also offered a summary of the more major new features in PF, "The most important changes in 3.3 are probably:
  • "Altq integration: now the packet filter is used to assign packets to queues. The (somewhat complicated) altq.conf is gone, and queue definitions and assignments are done in pf.conf, which simplifies syntax. Packet filter rules assign packets to queues, which saves a separate evaluation of a classification ruleset, and the state engine in pf can use that state entries to assign connections to queues statefully.

  • "Anchors: there was only a single, flat ruleset before. Now, you can create sub-rulesets and reference them from the main ruleset, using names (or placeholders) called 'anchors'. This is useful to partition larger rulesets into smaller, independent ones. Especially for daemons (like authpf) which manage their own set of rules, this is useful.

  • "Tables: imagine a rule like
        pass from { s1, s2, ..., sN } to { d1, d2, ..., dM }
    where N and M are large. This gets expanded to N*M rules by the parser, so every combination of source and destination address is passed. Evaluating a large list of such rules can get slow. Tables are just a list of addresses (or netblocks), like
        pass from <src> to <dst>
    where 'src' and 'dst' are arbitrary names. You can load huge lists of addresses into each one (using pfctl), and the kernel builds a binary radix tree. The rule doesn't have to be expanded, and evaluation can be done using two simple lookups, which is very fast even with huge lists (tens of thousands of entries).

  • "Parser improvements: the keywords and options can now be placed more freely within rules, and many parts are optional now. This can make rules shorter and more human readable.
"We've given some talks during the last couple of weeks presenting those and other changes. If you're interested, you can view most of the slides on http://www.openbsd.org/events.html."

I asked Daniel about rumors I'd heard of support for firewall redundancy being added recently, to which he replied, "We don't have firewall redundancy and failover yet, that's something to tackle for 3.4. But with 3.3, you can already balance load to multiple uplinks or servers, like a redirection rule that forwards incoming HTTP requests to multiple local web servers, distributing the load according to various schemes (round-robin, source hash, etc.). It's also possible to make use of multiple Internet connections (uplinks), spreading outgoing connections across all of them (or based on any criteria the filter can use, like protocols, ports or addresses), and routing replies back through the uplink where an incoming connection arrived on."

OpenBSD 3.3

OpenBSD 3.3 will be available on May 1'st, 2003. It can be freely downloaded from a local FTP mirror, or purchased as a 3-CD set, which includes images for i386, MacPPC, Vax, Sparc, and Sparc64. Versions for Alpha, HP300, HPPA, Mac68k and MVME68k are available by FTP. The project's homepage states, "OpenBSD is developed by volunteers. The project funds development and releases by selling Cd's and T-shirts, as well as receiving donations. Organizations and individuals donate and thus ensure that OpenBSD will continue to exist, and will remain free for everyone to use and reuse as they see fit."

Related Links