Using the PF Firewall on FreeBSD
How to build a firewall based on FreeBSD, PF, and fwbuilder; how to proxy FTP connections; how to configure a transparent web proxy/cache using Squid; how to share iTunes; etc.
FreeBSD is well suited to service as a bastion host or border router. The default installation has few services running and requires little additional hardening. Its security team is well organized and prompt. FreeBSD supports a variety of firewall software products, and FreeBSD 5.3 includes IPFW, IP Filter, and PF in the GENERIC kernel. Advanced routing using BGP or OSPF is available using the net/zebra package. A graphical user interface for creating, editing, and deploying firewall configuration files is provided by the excellent Firewall Builder tool, packaged as security/fwbuilder.
This document assumes FreeBSD 5.3 is installed, with certain tools from the ports tree already installed and configured. Some of the specifics of network interface configuration, such as dial-up connections or virtual private networking, are beyond the scope of this document.
The policy described creates a firewall that blocks traffic by default and hides connections behind the firewall's Internet interface. Several services are published to the Internet, and Internet access is heavily filtered. For the purposes of this document, the network topology is as follows:
FIXME: diagram of network, with interfaces and IP addresses labeled
Firewall Design Considerations
default deny, in and out
role-based policy
readability and ease-of-use
rule order (most specific to most general, intranetwork/inbound/outbound)
inbound an interface, NAT before filter; oubound, filter before NAT
terminology: inbound/outbound, exterior/interior/perimeter, etc.
Post-installation Configuration
The following commands must be executed while logged in as root:
Network Interface Configuration
FIXME: how to configure the network interfaces, including multiple IP addresses on a single interface; assumptions regarding SNMP
Additional System Hardening
FIXME: add additional system hardening instructions, e.g. securelevel (and what must be moved where in order not to break things), accounting, dropping redirects, etc.
The OpenBSD Packet Filter (PF)
- You do not need to recompile the kernel in order to use the PF
firewall unless you want IPSEC support. FreeBSD 5.3 includes PF as
a kernel loadable module, and the initialization scripts know to
load the module at boot if necessary, along with the relevant
configuration files. Firewall Builder names its configuration files
after the firewall, so the initialization scripts need to be
adjusted accordingly. Configure PF to start at boot time and load
the generated configuration file with the following commands:
ed /etc/rc.conf a pf_enable="YES" pf_rules="/etc/${hostname}.conf" pflogd_enable="YES" . wqDo not reboot. The firewall is not yet configured, and the generated configuration file does not yet exist.
Firewall Builder
- Optional: On slower systems, you may skip building many
of Firewall Builder's pre-requisite packages by running the
following commands:
pkg_add -r xorg pkg_add -r qt pkg_add -r qmake pkg_add -r net-snmp pkg_add -r libxml2 pkg_add -r libxslt pkg_add -r libgpg-error pkg_add -r libgcrypt pkg_add -r gmake
- A binary package for
security/fwbuilder
is not available. Install it with the following commands:
portinstall -m BATCH=yes security/fwbuilder rehash
Using Firewall Builder
Run Firewall Builder under X with the command
fwbuilder. Since my
firewall is headless, I have
Cygwin/X installed on a
Windows workstation
(I created a shortcut that runs XWin.exe -nounixkill
-multiwindow -clipboard) and forward the X traffic over an SSH
tunnel with
PuTTY
(instructions).
Policy Initialization and Version Control
Create a new policy file as follows:
- When prompted after starting Firewall Builder, create a new
configuration file by clicking Create new project
file. Enter a sensible name for the file; I recommend
naming it after the organization or department.


- Version control allows you to track changes to the firewall
configuration. Enable it by clicking Next, then
clicking Activate Revision Control System..., then
clicking Finish.


- Configure Firewall Builder to automatically save changes between
dialog windows, to enable tool tips, and to give the color codes
meaningful labels. From the Edit menu, choose
Preferences. On the General tab,
click Automatically save data in dialogs... and
Enable object tooltips. On the
Labels tab, set the color red to
Policy exceptions, green toAnti-spoofing rules, blue toOutbound traffic, and gray toIntra-network traffic. White (the default color for a rule) is used to denote traffic inbound from the Internet. Click OK to apply these changes.


- Add an object for the firewall itself. From the
Object menu, choose New Object,
then choose New Firewall.


- In the New Firewall wizard, enter the host name
of the firewall, select the PF firewall software, and the FreeBSD
operating system. While the pre-configured templates provide useful
starting points for common topologies, you may need to change the
interface names and IP addresses later. Click Next
to continue onto the network interface definition prompts.

- Configure the firewall's network interfaces manually by choosing
Configure interfaces manually and clicking
Next. Refer to the network diagram above for the
example network configuration. Make certain to click
Add after specifying each interface. Click
Finish to exit the wizard.


- This example configuration does not rely on Firewall Builder's
generated configuration files to change the operating system
configuration. From the firewall's properties dialog, click
Host OS Settings, change Packet
forwarding to
No change, and click OK.

- I configure the rule compiler to ignore rule shadowing
(FIXME: because I am relying on the ability to override
lower-priority, more general rules), to ignore empty groups in
rules (FIXME: because I am using role-based controls), and
to always permit SSH logins from a trusted workstation on the
interior network (FIXME: for remote access to the firewall if I
screw up its configuration). From the firewall's properties
dialog, click Firewall Settings. On the
Compiler tab, clear the Detect rule
shadowing in policy checkbox, click Ignore empty
groups in rules, check Always permit ssh
access..., and enter the IP address of a trusted
workstation or server.

- Again, this example configuration does not rely on Firewall
Builder's generated configuration files to change the operating
system configuration. Still in the Firewall
Settings dialog, click on the Script
Options tab, and clear both the Configure
interfaces of the firewall machine and the Add
virtual addresses for NAT checkboxes. Click
OK, then close the firewall's properties dialog
box.

A Basic Rule Set
Configuration File Generation
Deploying the Configuration
DHCP Relay
FreeBSD 5.3 only includes the ISC DHCP client. A DHCP relay agent must be installed from the ports tree, and the firewall must be configured to allow the DHCP traffic over the relevant interfaces. This example relays DHCP requests from hosts connected to the perimeter network (on interface fxp2) to the DHCP server on the interior network (on interface fxp1).
- Install the ISC DHCP relay agent with the following command:
portinstall -m BATCH=yes net/isc-dhcp3-relay
- Configure the relay agent by specifying the DHCP servers' names
or IP addresses, the name of the network interface facing the DHCP
server, and the names of the interfaces facing the client networks
with the following commands:
ed /etc/rc.conf a dhcrelay_enable="YES" dhcrelay_servers="dhcp.example.com" dhcrelay_ifaces="fxp1 fxp2" . wq /usr/local/etc/rc.d/isc-dhcrelay.sh start
- Explicitly allow the relay agent running on the firewall to communicate with the DHCP servers, as this traffic will be blocked by default. In Firewall Builder, ...
- DHCP uses the null (0.0.0.0) and the broadcast (255.255.255.255) IP addresses by design. These packets will be blocked by sophisticated address spoofing rules on well-designed firewall policies, so you must add a rule on the client-facing interface that allows this DHCP traffic. In Firewall Builder, ...
Transparent FTP Client Proxy
PF does not include an in-kernel FTP proxy (I'll rant later). FreeBSD includes compatible proxy software in the base system, and you can create the appropriate transparent proxy rules with Firewall Builder. In the following example, the firewall is configured to block traffic by default, but allow traffic outbound from the firewall itself.
- Enable inetd, bind it to the loopback interface, and enable
additional logging with the following commands:
ed /etc/rc.conf a inetd_enable="YES" inetd_flags="${inetd_flags} -l -a 127.0.0.1" . wq - Activate the FTP proxy service (and start inetd) with the
following commands:
ed /etc/inetd.conf a ftp stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy . wq /etc/rc.d/inetd start
Do not use ftp-proxy's NAT mode, because a default-deny firewall will block passive-mode data transfers (which can happen over any TCP port above 1024 and would require too permissive a filter policy). - Allow access to the FTP data transfer ports opened dynamically
by the FTP proxy. In Firewall Builder, from the
Object menu, choose New Object,
then choose New Custom Service. Give the service a
sensible name, change the platform to
PF, and enter the codeuser proxy flags S/SA. Click Apply Changes to save the object.FIXME: screen captures of custom service creation
- 4. Create a rule that allows FTP control connections (21/tcp), e.g. to FTP servers on the Internet.
- 5. Create a translation rule that redirects an FTP control connection (port 21/tcp) from its original destination (i.e. **any**) to the firewall's loopback interface (i.e. **127.0.0.1**).
- Compile and install the firewall policy.
Be aware of the order in which NAT and filter rules apply: For inbound traffic, NAT happens first, then filtering; outbound is the reverse. I bind the FTP proxy's listener to 21/tcp because otherwise, my "allow FTP connections" filter rule in step 3 must list 8021/tcp (the translated port) instead of 21/tcp (the actual FTP control port). (This can be confusing.)
Transparent Web Client Proxy
iTunes Sharing
Sharing an iTunes library over the Internet has two major hurdles. iTunes explicitly issues packets with a low time-to-live (TTL) to keep its users from sharing an iTunes library beyond one or two router hops. iTunes relies on Rendezvous multicast service discovery messages that typically are only available within a local area network. The Rendezvous messages can be spoofed at the client with tools like RendezvousProxy, but bypassing the TTL restrictions is a little challenging. There is software that uses the IPFW/NATD divert socket to rewrite the TTL on the file, but since I'm using PF, I used its packet scrub feature to normalize the TTL:
- NAT 3689/tcp from the firewall's Internet interface back to the iTunes server.
- Allow connections from the Internet to the iTunes server on port 3689/tcp.
- In the firewall object's PF properties, choose
Scrub rule optionsand enforce a minimum TTL of32.
High Availablility and Load Balancing
The Common Address Redundancy Protocol (CARP) is not yet a part of a stable FreeBSD release. Please see http://people.freebsd.org/~mlaier/CARP/ for more information and patches.