Published on (
 See this if you're having trouble printing code examples

Building a Desktop Firewall

by Dru Lavigne

Everyone knows that you should be behind a firewall whenever you go online. However, not everyone knows that it's easy to create a personal firewall for a FreeBSD (or PC-BSD or DesktopBSD) system. This article shows how even a casual home user can get a firewall up and running in about ten minutes.

The Software

Like all of the BSDs, FreeBSD has always been security conscious. It offers several built-in firewalls to choose from: ipfw, ipf, and pf. I use pf because it is built into all of the BSDs, including OpenBSD, NetBSD, and DragonFly BSD.

I also recommend using a GUI firewall editor called fwbuilder. While my examples will demonstrate this utility from a FreeBSD system, it is available for Linux, Mac OS X, and Windows XP and supports iptables, ipfilter, pf and ipfw.

pf comes with FreeBSD, but double-check that it is loaded on your system by typing the following as the superuser:

# kldload pf.ko

If you get your prompt back, you just loaded it manually. If you're in the habit of turning off your computer, add a line to /etc/rc.conf to reload pf when your system boots:


If you instead get an error like:

kldload: can't load pf.ko: File exists

it means that your system is already configured to load pf for you.


Become the superuser and install fwbuilder:

# pkg_add -r fwbuilder
# rehash
# fwbuilder

The fwbuilder command will open up the Welcome to Firewall Builder screen. A prompt will ask if you want to open an existing project file or create a new one. Click on the Create new project file button and give it a filename; the program will add the .fwb extension. Click on the Next button to proceed.

The next screen offers two possibilities:

Revision control is a very good thing. Every time you start fwbuilder, it maintains a copy of your existing project file (i.e., your last session). This gives you a history of all of your sessions. More importantly, if you mess things up, you can go back to a previous working session. I recommend selecting both options, then pressing Finish.

Configuring the Firewall Object

This will take you to the fwbuilder GUI, which is divided into two main sections. The left frame contains an Object tree and the right frame contains your firewall rules (after you have defined some objects). Using objects is a very powerful visual aid, allowing you to quickly see your networks, computers, and services, and to cut and paste these objects into firewall rules.

The first object you create should represent your firewall. Click on the New Object icon (it looks like a sheet of paper) and select New Firewall from the drop-down menu. Give your firewall a name (I called mine my_firewall), select PF from the drop-down menu of firewall software, and click Next. Keep the default to Configure interfaces manually, and press Next.

You should see a screen like Figure 1.

your new firewall
Figure 1. Your new firewall

Note: if your screen doesn't include the Netmask and MAC options, you didn't start fwbuilder as the superuser. Only the superuser can create firewall objects and firewall rules.

Be sure to Add the interface information for each NIC in your computer as well as the loopback. If your firewall will protect only your personal computer, you need only one physical NIC installed in your computer. If you wish your computer to provide NAT to other computer(s) on your home network, you need to have two NICs installed.

If your ISP assigns you a DHCP address, check the Dynamic address option. Otherwise, enter your static IP address and subnet mask.

To determine the FreeBSD names of your interfaces as well as the associated IP addressing information, type:

# ifconfig
    inet netmask 0xffffff00 broadcast
    ether 00:04:75:ee:e0:21
    media: Ethernet autoselect (100baseTX <full-duplex>)
    status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    inet netmask 0xff000000

With my information, I entered into the New Firewall screen:

Name:        xl0
Address:    (greyed out because I checked Dynamic address)
Netmask:    (greyed out because I checked Dynamic address)
MAC:        00:04:75:ee:e0:21
Label:        external

Name:        lo0
MAC:        (leave empty)
Label:        loopback

When choosing a label, "external" is good for the NIC you use to access the internet, and "internal" is good for the NIC attached to your home network. If you need to add a static subnet mask, you must first convert that hex number (0xffffff00, for example) to decimal. Ignore the 0x, as that simply indicates a hex number. What remains is four pairs of numbers: ff ff ff 00. ff is easy; it represents 255, and 00 represents 0, so this mask is: If you have a pair that isn't an ff or a 00, use a conversion table:

Hex Decimal
80 128
c0 192
e0 224
f0 240
f8 248
fc 252
fe 254

Note to users of modems: your interface name will be either ppp0 or tun0. Running ifconfig while connected to the internet will make it easier to spot your IP address.

Once you've entered the information for a NIC, click Add and repeat for each of your NIC(s). When finished, click on the Finish button. The Firewall properties menu will stay open for you, but you can close it to keep the defaults. If you take a look at your Object tree, it now contains some new objects: one for your firewall and one for each interface you defined.

You have one last change to finish the firewall object--marking one of the interfaces as a Management interface. For a personal firewall, it should be the loopback. Double-click your loopback object and check the Management interface box, then close that screen.

Creating a Simple Firewall Ruleset

You now have everything you need to create a simple firewall ruleset that allows your personal computer to access the internet and prevents anyone on the internet from accessing your computer.

Click on the Rules menu and select Insert Rule (Figure 2). Notice that the default rule denies any source from reaching any destination using any TCP/UDP service. To allow the system running the firewall, right-click your firewall object and select Copy. Right-click inside the Source box of the rule and Paste. Your firewall should now show as the source of packets. Next, right-click the Deny word under Action and change it to Accept. In the Options box, right-click and select Logging Off--you don't want to log every one of your successful packets.

Thumbnail, click for full-size image.
Figure 2. Inserting a rule (Click for full-size image)

You should always add a comment to remind yourself why you made a rule. If you double-click on the box, you can type in your comment. I wrote:

allow my computer to access the internet

That one rule is enough to give you a working firewall. If you want, you can add a second rule. Click on the Rules menu and select Add Rule Below. Add a comment:

deny all other traffic

If you don't plan on looking at your firewall logs, turn off logging in the Options box.

Note that this second rule isn't necessary for this setup, because the pf firewall assumes you want to deny any traffic you didn't explicitly accept. This is an implicit deny. You may find it useful to add the rule with a comment to remind you of this behavior.

Tip: A quick administrator's trick is to add this rule only when you are troubleshooting a problem and to leave the Logging option on.

Installing your Firewall Rules

You've just created a firewall ruleset, but it won't start working until you install it.

First, you need to configure sshd to allow the superuser to connect and install the firewall rules. By default, FreeBSD doesn't allow superuser ssh sessions. Change this default by typing the next line very carefully and double-checking your upper- and lowercase and your >> before pressing enter:

# echo "PermitRootLogin yes"  >> /etc/ssh/sshd_config

Don't worry; no one on the internet will be able to ssh to your computer once you install your firewall rules. Next, tell sshd about that change:

# /etc/rc.d/sshd reload
Reloading sshd config files.

If you see an error:

sshd not running? (check /var/run/

use this command instead:

# /etc/rc.d/sshd start
Starting sshd.

Double-check that sshd is running with:

# /etc/rc.d/sshd status
sshd is running as pid 5467.

Next, select Install from the Rules menu. You'll receive this message:

    Some objects have been modified since
    you compiled the policy last time.
    Do you want to recompile it before you install?

You do, so click the Compile button. A text box should open and the last message should read "Policy compiled successfully." Click the Install button. Under authentication information, enter root for the username and type in the password for your superuser account, then press Next. You should receive a New RSA key message:

    You are connecting to the firewall 'my_firewall'
    for the first time. It has provided you its
    identification in a form of its host public key. The
    fingerprint of the host public key is: "
    You can save the host key to the local database
    by pressing YES, or you can cancel connection
    by pressing NO. You should press YES only if
    you are sure you are really connected to the 
    firewall 'my_firewall'.

It is safe to press Yes because you know you are connecting to your own firewall. However, it is good to know how to check a host's fingerprint in case you ever connect to a remote FreeBSD system:

# ssh-keygen -l -f /etc/ssh/
1024     b6:76:30:aa:01:27:64:48:3b:18:28:18:5b:c9:ae:e4

Note: you will only need to verify the fingerprint the very first time you install your firewall.

Once you click Yes, a text box will open (mine was minimized). You will get a message about No ALTQ support in the kernel, but that's OK, as you aren't using it. Simply close the message box. Your firewall is now running.

Controlling the Firewall

Use the pfctl (pf control) command to see what's happening with your firewall and to stop and start the firewall. Use the show switch (-s) to view the rules currently running on the firewall:

# pfctl -s rules
No ALTQ support in kernel
ALTQ related functions disabled
pass out quick inet from (xl0) to any keep state label "RULE 0 -- ACCEPT "
block drop in quick inet all label "RULE 1 -- DROP "
block drop out quick inet all label "RULE 1 -- DROP "
block drop in quick inet all label "RULE 10000 -- DROP "
block drop out quick inet all label "RULE 10000 -- DROP "

If you compare that text to the rules you made in fwbuilder, you'll recognize rules 0 and 1. Rule 10000 is that implicit deny rule.

If you ever wish to stop your firewall, use the disable switch:

# pfctl -d

To restart the firewall, specify the name of your ruleset. It will be in /etc and have the same name as your firewall. In my case, it is in /etc/my_firewall.conf. To start this firewall, I use pfctl at the command line with the enable switch:

# pfctl -e /etc/my_firewall.conf

Alternatively, I can right-click the firewall in the Objects tree and choose Install from the drop-down menu. (Note that this will fail for the current set of rules. It's easy to fix though.)

Note: if you added the line to /etc/rc.conf mentioned at the beginning of this article, add another line to load your ruleset if you reboot your computer:


where my_firewall.conf is the name of your ruleset. It is always a good idea to run pfctl -s rules after a reboot to double-check that your firewall is running.

Fine-Tuning the Rules

If you take a look at your first rule, it allows the firewall to go anywhere as a Source. However, nothing can connect to the firewall as a Destination. This includes the firewall making a connection to itself in order to install a policy, so if you were to add a rule you would get an error when you tried to install it. This is fine if you are happy with your firewall as is. Try it out--you should be able to surf, send/receive email, and do most of the things you normally do on the internet.

However, if you find you need to add more rules, you must start with a rule that allows the firewall to install a policy. Click on the number 0 in the first rule, go to the Rules menu, and select Insert Rule. Because the firewall needs to access the loopback management interface over ssh, it makes sense to have the rule look like this:

Source:        my_firewall
Destination:    my_firewall:lo0:ip    (you'll find this if you click the + 
                     by your loopback object)

Service:    ssh
Action:        Accept
Options:    Logging On
Comment:    allow firewall to install policy

You haven't made a ssh object yet, so do so now. Click + next to Services to expand its tree. Right-click TCP and select New TCP Service. Under Name:, enter ssh. Under Destination Port Range Start, enter 22 and click the Apply Changes button. When finished, your firewall rules should resemble Figure 3.

Thumbnail, click for full-size image.
Figure 3. Firewall rules that allow ssh (Click for full-size image)

Before you can install the new rule, you will have to temporarily stop the firewall--remember, it currently doesn't allow any connections to itself.

# pfctl -d

Install the rulebase as usual; it will restart the firewall for you. You should be able to see your new rule if you type:

# pfctl -s rules

My new rule looks like:

pass out log quick inet proto tcp from (xl0) to port = ssh keep 
state label "RULE 0 -- ACCEPT "


Today, I've demonstrated how to make a personal firewall that protects your system while allowing you to access the internet. My next article will show you how to install a NAT policy with fwbuilder and explore some of its other features.

Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.

Return to the BSD DevCenter.

Copyright © 2009 O'Reilly Media, Inc.