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. As of
10.5 the situation is much better, in that the firewall is application
oriented and you can enable or disable connections based on the
application used. But I find it useful to be able to manipulate the
firewall directly, and this document covers some of the basics.
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 Flying
Buttress. In addition to allowing the user to manage the firewall,
also help you setup connection sharing and Network Address
Translation so you can use your Mac as a router. Another good GUI
frontend to IPFW is WaterRoof.
So if your needs are simple, those may be good ways to go. 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 first thing to figure out is whether you need a special firewall
set up at all. The first thing to check is whether you have any
services enabled. Check your System Preferences and look at the Sharing
In my case, I have ssh (Remote Login) and httpd (Web Sharing)
enabled. So these are two services I've set up to allow remote machines
to use to connect. Ssh is pretty secure since it requires a user id and
password, and has some security built in. And httpd isn't inherently
Now, if you're running 10.5, check the Security preference pane, and
see that the firewall is enabled. Click on Advanced and you'll likely
see something like this:
Under 10.4 and earlier, the location of these settings is a bit
different, and the panes are arranged differently, but the basic setup
is similar. Notice that both Remote Sharing and Web Sharing are set to
allow all incoming connections. This is the key thing to understand
about the built in firewall--it doesn't offer you the chance to refine
what machines are allowed to connect over a given protocol and which
are not--it only allow you to open a port to the world, or to close a
port to the world.
Let's take ssh as an example. I enable ssh so I can login to my
laptop with a terminal connection, and to mount my laptop's filesystem
via sshfs (eg. MacFusion).
I don't need to be able to do this from anywhere on the internet,
however. I'm usually very close to my laptop, so these connection are
made at my house or from somewhere on the UNC Chapel Hill campus. So
there's really no reason that I should enable ssh connection from, say,
China or Bulgaria or Indiana. If I restrict ssh connections to my home
network and the UNC campus, I'm still in good shape, and I've lowered
the number of IP addresses that can try to connect via ssh to my laptop
from a billion or so to just several thousand. That reduces my exposure
considerably. The basic rule is that if you need to enable a service,
think about who needs to connect to it, and if you don't need the
entire world to have that opportunity, use a more complex firewall rule
to restrict it a bit. If you're not running any services, you're not
really that exposed in the first place, so you don't need to worry
nearly so much.
Another consideration is whether you are using a Public IP address
or a Private IP address. Most home users are connected via a cable
modem or DSL connection that has a Network Address Translation (NAT)
router. If you're not familiar with these terms, don't worry, it's
pretty simple. A NAT router supports multiple computers in your home or
office, and it does that by handing out Private IP addresses to those
machines. These addresses are, according to networking conventions, not
routable on the internet. That just means that someone out there on the
internet cannot attempt to directly connect to your machines in your
house--in effect, the NAT acts as a firewall for you. Pretty much
all home connections, and connections in coffee houses and the like use
private addresses. Now this doesn't mean that no one can try to connect
to your machine--if someone knows what they are doing and they are in
the same coffee house as you, they can try to connect to your laptop
from there. But again, the number of folks who can try this is really
small compared to the total number of users on the internet. So if
you're a laptop user, and you're not running services, and you connect
only from your home and a couple of other locations, setting up a
complex firewall isn't going to help you much.
Private addresses all fall in the following ranges:
For more information see the Wikipedia article
on Private Addresses.
On the other hand, if you're using a public IP address, you're the
world's oyster and anyone on the internet can try to talk to your
machine. So keeping the shell closed to a narrow range makes sense.
Public addresses are in wide use, for example, at universities and
colleges in the USA. So if you have a desktop computer in your dorm
room, and you don't use an address in the ranges above, and you enable
some services like File Sharing, or Screen Sharing, or Remote Login,
you definitely should look into using a more selective firewall than
what's provided by the operating system out of the box.
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
In 10.4 and prior, you might get back something like this if you have services running like Remote Login and Web Sharing:
[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 18.104.22.168/3 to any in
02040 deny tcp from any to 22.214.171.124/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
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.
In 10.5, you'll probably get a single rule back, since the firewall
is oriented to the applications.
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. The first part of this is pretty safe since all you have to
do to get back to "normal" is to reboot and check your sharing settings.
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
The first thing we're going to do is enable Web Sharing in the
System Preferences, under Sharing. Just click that checkbox, and save
the changes. Then use your browser to connect to http://127.0.0.1/. A web page should
load, the default page for the OS X web server. (Just so you'll know if
you don't already, 127.0.0.1 means "ME!" in networking, so all
connections of any kind to 127.0.0.1 stay on your local machine.
Now, use your browser to do to Gibson's Shield's Up, the shields up link is down about halfway on that page. Click on that link, and then click on the Proceed button, and on the next page, click on the Common Ports link. This will scan your machine and see what ports are open. If port 80, HTTP, shows as "stealth", it's likely you're on a Private IP address and protected by a NAT. If that's the case, there's not much else you can do here. But if port 80, http is marked as open, then you're on a Public IP address and anyone on the internet can connect to your web service.
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. Go back and reload the Probe My Ports page, so you can see the effect of disabling the firewall.
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 on the Shield's Up site again--the port should go from Closed to Stealth.
Ok, so far so good. We'll start with a simple firewall. Open a
terminal window and run the following commands:
curl -o Firewall.simple http://www.ibiblio.org/macsupport/ipfw/Firewall.simple
chmod a+x Firewall.simple
sudo ./Firewall.simple start
Flushed all rules.
00100 allow ip from me to me
00200 allow ip from 192.168.0.0/16 to 126.96.36.199/3 in
00300 deny tcp from any to any dst-port 0 in
00500 allow tcp from me to any keep-state
00600 allow udp from me to any keep-state
25000 deny tcp from any to any established
25100 allow udp from any 67 to any dst-port 68 in
25200 allow ip from 192.168.0.0/16 to any in
25300 allow icmp from any to any in
25400 allow tcp from any to any dst-port 80
25500 allow tcp from any to any dst-port 443
25600 allow tcp from 192.168.0.0/16 to any dst-port 22 in
25700 allow tcp from 192.168.0.0/16 to any dst-port 548 in
25800 allow tcp from 192.168.0.0/16 to any dst-port 427 in
25900 allow tcp from 192.168.0.0/16 to any dst-port 3689 in
26000 allow ip from 192.168.0.0/16 to any dst-port 5353 in
26100 allow udp from 192.168.0.0/16 5353 to any dst-port 1024-65535 in
65000 reject udp from any to any in
65100 deny icmp from any to any in
65200 deny ip from any to any in
sudo ./Firewall.simple startNext, go to Shield's Up and run another test. You'll most likely find that port 80 is open, port 443 is closed, and the others are marked as stealth. Closed means that the grc site can contact a port, but there's no service there.
Once you have a script that defines a firewall you like, you'll want to put that script up in such a way that it runs when you start the computer. First 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 \
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
sudo chmod o-rwx /Library/StartupItems/Firewall/Firewall
Now, try running the script manually:
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.
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";
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 \
Also, make sure this file is writeable by root only, you don't
want anyone changing your firewall startup. When you next boot, the
system may tell you that the setup for these files isn't safe--if that
happens, let the system change the file permissions for you and reboot.
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).
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/
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.