Use firewall software like PF to protect your desktop systems

PF is the default firewall software for OpenBSD, and is an excellent example of a powerful, flexible firewall system. Something like it should be used to protect your desktop computer, and a minimal configuration example can help you get started.

Choosing an operating system with care can ensure a certain amount of security right away. At one end of the spectrum we find Microsoft Windows, which installs by default with a myriad of often unnecessary services turned on by default, a largely ineffective privilege separation model, and a vendor attitude toward security patching that could reasonably be described as "lackluster". At the other end, we find OpenBSD, whose core developers obsessively perform code security reviews, and whose base install comes with pretty much nothing turned on that could be used to access the computer remotely.

Once you have selected an OS, based on whatever criteria you decide are most important, measures can be taken to mitigate some of the problems that might come in a default install. For instances, turning off services in MS Windows is an important step toward reducing the security weaknesses normally found in the operating system. A number of other measures are important for any desktop deployment.

Even if all but the most critical services are shut down, there is always the possibility that one of the remaining services will be vulnerable, or that some bug in the system may allow a supposedly deactivated service to be exploitable anyway — or, in the case of an OS whose updates can change basic configuration settings without the user's knowledge, as often happens with MS Windows — an intentional "feature" of the system management model might allow previously deactivated services to be turned on again.

Firewalls can help reduce your exposure to remote exploits of vulnerabilities in your system's services. Some OSs have a firewall installed by default, and some of these firewalls are better than others. In some, that firewall software might be active by default, and in others it may be inactive. Configuration may be adequate to your needs, or it may not. In some cases, the default firewall software may not be the best choice available, and it may even be subject to the same potential for having its configuration silently and unexpectedly changed by system updates. These are all concerns that should be investigated by the conscientious user, and addressed with care.

Open source Unix-like systems tend to come with very well-regarded firewall tools, in terms of the fine-grained control they can provide and their strength and effectiveness. The Linux kernel offers iptables; BSD Unix systems offer options such as ipfilter. One of the most highly regarded suites of firewall software is the OpenBSD project's PF, which has been ported to every major BSD Unix system available. There is even a Microsoft Windows firewall application that claims to be based on PF source code called Core Force, though it must by necessity be heavily modified to run outside of a BSD Unix environment.

While PF does not by default offer the kind of point-and-click interface that MS Windows users tend to prefer, its flexibility and capability is far beyond what is offered by the Windows Firewall and other MS Windows firewall applications like ZoneAlarm. Amongst firewall software options that compare more directly to PF, it is considered one of the easiest to configure and maintain.

A minimal ruleset for PF on a desktop system can be set up in a handful of lines in a configuration file. On current OpenBSD, NetBSD, and FreeBSD systems, that configuration file is /etc/pf.conf. Such a ruleset might look like this:

tcp_services = "{ ssh }"

block all

pass in proto tcp to any port $tcp_services

pass from lo0 to lo0 keep state

pass out all keep state

Each of these lines serves an important purpose:

  • tcp_services = "{ ssh }": This is what is called a "macro" in PF parlance. PF macros serve much the same purpose as variables in many programming languages, in that you can use a single term to stand in for a varying value or a more complex value that would take a while to type over and over again. In this example, the SSH protocol has been assigned to the tcp_services command; if you have other services you need to work with in a similar manner, they can be added to that list, the PF shortcut terms for various protocols being separated by spaces.
  • block all: This is the first actual firewall rule in this ruleset. Because PF evaluates from top to bottom, each rule takes precedence over previous rules, so that earlier rules are treated as "defaults" and later rules as exceptions to those defaults. Taking a "least privilege" approach to security is usually a good idea, so we block all traffic by default and use more specific rules later in the ruleset to identify specific cases where we want to allow network traffic through.
  • pass in proto tcp to any port $tcp_services: This is the rule that makes use of the tcp_services macro. Because many Unix-like desktop systems are configured with an SSH server so that they can be securely accessed remotely from within the same network, for administrative and troubleshooting purposes, this rule allows any SSH traffic into the system. This assumes that you have some kind of external protection, such as a firewall for the entire network so that random security crackers on the Internet cannot directly access the desktop, and that you have your SSH service configured securely on the system as well; otherwise, you may want to use a more restrictive rule for the SSH protocol.
  • pass from lo0 to lo0 keep state: This rule allows the desktop system to communicate with itself via the localhost interface, which is important for a lot of common system functionality.
  • pass out all keep state: This rule has two important parts. The first is pass out all, which ensures it can send out whatever network traffic it needs to send. This can be dangerous on systems that might become infected by malware that then tries to contact the outside world to work mischief. On a firewalled BSD Unix desktop system in a network with good perimeter defense, operated by a tech-savvy user, this risk is so minimal as to be nearly nonexistent; on an MS Windows system, it is much more substantial, regardless of other conditions. Regardless of the OS, however, the risk does still exist.The second part of the rule, keep state, ensures stateful operation of network connections. This means that when the local system attempts to communicate with a remote system, and a connection is established, return communications from the remote system will be able to get through — without affecting whether other remote systems will be able to establish unsolicited connections. In the most recent versions of PF, keep state is default behavior for pass rules, but including the keep state instruction should not cause any problems.

PF may be activated and this ruleset loaded in a single command:

pfctl -ef /etc/pf.conf

Further action may need to be taken to ensure that PF will run every time the system is booted, however. On FreeBSD, for instance, PF is not enabled by default. To ensure that it will start on system startup, and pick up your ruleset, add these lines to the /etc/rc.conf file:



If PF is not already running, the above pfctl command on a default FreeBSD install needs to be preceded by loading the PF kernel module with the kldload command:

kldload pf

As already stated, this PF ruleset is minimal. Its simplicity makes it easy to understand, and easy to employ and extend. It may be sufficient for some needs, but improving on it for your particular needs is always a good idea. Even unchanged, however, this ruleset is a tremendous improvement over no firewall at all.


Chad Perrin is an IT consultant, developer, and freelance professional writer. He holds both Microsoft and CompTIA certifications and is a graduate of two IT industry trade schools.

Editor's Picks