Configuring IPFW firewalls on OS X

OS X comes with a unix firewall program called IPFW, and there are a variety of programs you can use to access it from the GUI. As of 10.2 Apple includes a tool in system preferences to enable the firewall, but it's a very simple implementation that will only enable or disable a port for the entire internet. This isn't the best use of a firewall--the real strength of a firewall is to enable access to a service for a limited range of ip numbers.

Also, this doc covers use of IPFW with the client versions of OS X. If you're using OS X server, the GUI tool provided allows for more customization. But the GUI tool (at least as of 10.3) doesn't build IPFW rules that track state, which makes getting things like AFS and Kerberos more difficult to work. I've put together some notes on how the firewall tools with OS X server works.

The best tool for managing IPFW out there is Brian Hill's Brickhouse. In addition to allowing the user to manage the firewall, it will also help you setup connection sharing and Network Address Translation so you can use your Mac as a router.

But if you're able to navigate via the command line and can use a text editor like vi or pico, it's not too difficult to manage your firewall with IPFW directly.

The Rules

The first thing to do is to play with looking at the firewall from the command line. Open the System Preferences, and under Sharing, enable the firewall. Then open a terminal session, and type:

sudo /sbin/ipfw list

You'll get back something like this:

[gilgamesh:~] hays% sudo ipfw list
02000 allow ip from any to any via lo*
02010 deny ip from 127.0.0.0/8 to any in
02020 deny ip from any to 127.0.0.0/8 in
02030 deny ip from 224.0.0.0/3 to any in
02040 deny tcp from any to 224.0.0.0/3 in
02050 allow tcp from any to any out
02060 allow tcp from any to any established
02070 allow tcp from any to any 80 in
02080 allow tcp from any to any 427 in
02090 allow tcp from any to any 548 in
02100 allow tcp from any to any 427 in
02110 allow tcp from any to any 22 in
02120 allow tcp from any to any 139 in
12190 deny tcp from any to any
65535 allow ip from any to any
[gilgamesh:~] hays%

In this case, my configuration is set up to allow personal file and web sharing, remote login, and windows filesharing. Your list may well vary. Compare the output from the list command to the entries in the firewall configuration of the Sharing preferences.

Now how this works is that packets both inbound and outbound are compared to the list of rules in order, and if a match is found, that action is taken. For example, in the list above, rule 02050 is processed first, and it allows any tcp packets that are outbound, so your machine can try to contact any other machine, so outbound packets are allowed out before rule 12190 is processed.

Getting your feet wet

WARNING! We're going to be playing with a fairly deep and archane portion of the OS, so you may render your machine unusable on the internet for a while. Do not do any of this unless you're sitting in front of the machine and have some spare time.

If you run the Probe My Ports option from Gibson's Shield's Up , you can see what your machine looks like from the internet with your firewall on (assuming, of course, that you aren't behind another firewall or nat--for example, if you're on the UNC campus, the NetBios ports always show as Stealth since access to those is blocked by the main campus router).

To play with the firewall settings, you'll use the command line in a terminal window. First, we'll clear all of the rules. In the terminal window, run:

sudo /sbin/ipfw -f flush

And then reenter:

sudo /sbin/ipfw list

again to list the rules. Also go back and reload the Probe My Ports page, so you can see the effect of disabling the firewall. This, btw, is how you'd get back to square one if things go wonky.

Now type

sudo /sbin/ipfw add 02070 deny tcp from any to any 80 in

This will should have the effect of blocking access to the web server, which runs on port 80. Even if you're not running a web server, you can see the effect of the command by running Probe My Ports--the port should go from Closed to Stealth.

The Script

First, you'll need to decide which script to start with. Here are some examples, both derived from scipts on the web, you should take all of them.

Then make a directory named Firewall in a StartupItems location:

sudo mkdir /Library/StartupItems/Firewall


Then, move one of the sample script files to that subdirectory: These examples are for the 2008 version.

sudo curl -o /Library/StartupItems/Firewall/Firewall \
http://www.ibiblio.org/macsupport/ipfw/firewall_2008.txt

This script is oriented to UNC Chapel Hill, but should be easily adaptable to other settings. But before you run it, you need to mark it as executable:

sudo chmod ug+x /Library/StartupItems/Firewall/Firewall

Now, try running the script manually:

sudo /Library/StartupItems/Firewall/Firewall

You should see a list of rules process, and then you can check the results with both the ipfw list command and Probe My Ports. Then try to use your machine to see how well things work. You can make modifications to the script and rerun it to institute the changes without restarting your machine, but you may have to restart some of the network applications.

Lights, Camera, Action

Once you're happy with the firewall's configuration, you'll want to set the script up to run each time the machine is started. To do this, you need to add a StartupParameters.plist file in the Firewall subdirectory, with the following lines:

{
Description = "Firewall";
Provides = ("Firewall");
Requires = ("Network");
OrderPreference = "None";
Messages =
{
start = "Starting NAT/Firewall";
stop = "Stopping NAT/Firewall";
};
}

You can either cut and past these lines, or move the file via commandline thusly:

sudo curl -o /Library/StartupItems/Firewall/StartupParameters.plist \
http://www.ibiblio.org/macsupport/ipfw/StartupParameters.plist

Also, make sure this file is writeable by root only, you don't want anyone changing your firewall startup.

Once this is done, the firewall script should run on boot. Of course, if you're using a custom script, you shouldn't run the System Preferences Firewall, as that could mess up your settings (although it won't overwrite your script file).

Dynamic Configuration

Note that you can add firewall rules while the machine is running. This opens up some interesting possibilities for dynamic security. For example, there's a patch for ssh called timelox that tracks connection failures by ip number--if threshhold of failures from a single IP is reached, it modifies the firewall to block all traffic from that IP number. For examples of this with IPFW and Iptables, see: http://wwwx.cs.unc.edu/~hays/dev/timelox_and_TheHand/

 

Acknowledgements

Most of this isn't stuff I came up with on my own, I'm indebted in particular to the following folks who have provided tools or examples that went into this page:

I recommend brian's brickhouse for purchase if you're going to do a lot of firewall configuration, it's a great product