- Contact Info
- matt@haught.org
- PGP Public Key
- Wishlist
- MySpace
OSX Firewall
Introduction
The built-in firewall in Apple's OSX is somewhat easy to configure. The OS has a GUI for configuring the firewall, but it is limited to a few services and you cannot limit the access to a subnet or single IP. Lucky, Apple's firewall is based off of FreeBSD's IPFW. From the command line, the firewall rules can be added, and from a startup shell script all your rules can be easily be set.
The rules here are split into three groups; basic, services, and default blocks. When combined in order and set to startup automatically in OSX 10.4+, they create a nice highly configurable firewall
IPFW syntax
The syntax for IPFW may seem a little complex and overwhelming at first sight, but it is actually pretty simple. First the rules are processed in order they are added unless a number is given to them. If no rule number is given, it is automatically given a incrementing number.
As exampled below, after the /sbin/ipfw command is given the switch -f is given. This switch stops any confirmation from IPFW about the rule. Next is the add keyword telling IPFW that you are adding a rule.
/sbin/ipfw -f add allow log udp from any to any 5353 keep-state
After add comes what action you want to take. The most common choices are allow, deny, and reject.
/sbin/ipfw -f add allow log udp from any to any 5353 keep-state
Next comes the optional logging with the log keyword.
/sbin/ipfw -f add allow log udp from any to any 5353 keep-state
After the log keyword comes the protocol we are matching. The common choices are ip, tcp, udp, and icmp.
/sbin/ipfw -f add allow log udp from any to any 5353 keep-state
Next comes the keywords that tell what IP addresses to match on the source and destination part of a packet. These are all from the point of view of the computer and are in the form from <source address> <source port> and to <dst address> <dst port>. The port for both are optional. The address can be any to match any address or can be an IP address to match a single host, or a subnet in the CIDR format like 192.168.1.1/24.
/sbin/ipfw -f add allow log udp from any to any 5353 keep-state
Lastly is keep-state which keeps a "state" table of connections that matched the rule. Keeping state allows for the firewall to automatically open a hole for the corresponding outgoing connection and thus removing the need for an additional rule with the source and destination reversed.
/sbin/ipfw -f add allow log udp from any to any 5353 keep-state
The options for configuration of IPFW are huge and only the most common are explained here. To understand more, read the man page.
Basic Config
#!/bin/sh
trust="192.168.1.0/24"
# Purge existing rules
/sbin/ipfw -f flush
# Allow localhost
/sbin/ipfw -f add 00100 allow ip from any to any via lo0
# Deny spoofed localhost
/sbin/ipfw -f add 00110 deny log ip from 127.0.0.0/8 to any in
/sbin/ipfw -f add 00120 deny log ip from any to 127.0.0.0/8 in
# Keep state table
/sbin/ipfw -f add 25000 check-state
# Allow outbound tcp/udp/icmp and keep state on udp/tcp
/sbin/ipfw -f add allow tcp from any to any out setup keep-state
/sbin/ipfw -f add allow udp from any to any out keep-state
/sbin/ipfw -f add allow icmp from any to any out
# Allow incoming icmp traffic for ping and traceroute
/sbin/ipfw -f add allow icmp from any to any in
Services
######################
###### Services ######
######################
# Allow SSH
/sbin/ipfw -f add allow tcp from any to any 22 keep-state setup
# Allow Apple File Sharing from our trusted subnet
/sbin/ipfw -f add allow tcp from $trust to any 548 keep-state setup
/sbin/ipfw -f add allow tcp from $trust to any 427 keep-state setup
# Allow SMB file sharing from our trusted subnet
/sbin/ipfw -f add allow tcp from $trust to any 139 keep-state setup
/sbin/ipfw -f add allow tcp from $trust to any 139 keep-state setup
/sbin/ipfw -f add allow tcp from $trust to any 139 keep-state setup
# Allow Rendevous fron our trusted subnet
/sbin/ipfw -f add allow udp from $trust to any 5353 keep-state
# Allow bacula-fd from our trusted subnet
/sbin/ipfw -f add allow tcp from $trust to any 9102 keep-state setup
Default Blocks
#####################
### Default Block ###
#####################
# Default reject for udp
/sbin/ipfw -f add 65532 reject log udp from any to any in
# Default reject for tcp
/sbin/ipfw -f add 65533 reject log tcp from any to any in
# Default reject for ip
/sbin/ipfw -f add 65534 deny log ip from any to any in
Start Up
Putting the three sections above together in an executable shell script will flush the default apple rules and add you own. All of the services will be restricted to the subnet that is set as the trust variable except for ssh.
One could run the script manually from the terminal, but making it run when the Mac starts is a much cleaner solution. Using Mac OSX 10.4+'s launchd facility, the firewall script can be executed on startup. Name the script rc.firewall and as the root user place it in /usr/local/sbin. Make the file executable with
# chmod 0750 /usr/local/sbin/rc.firewall. Run the script to make sure there are no problems with your syntax. In /Library/LaunchDaemons create a file named firewall.plist and add the following to it:
<?xml version="1.0" encoding="UTF-8"?>
Next the plist file needs to be loaded into launchd using the following command:
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.firewall</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/sbin/rc.firewall</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>UserName</key>
<string>root</string>
</dict>
</plist>$ sudo launchctl load /Library/LaunchDaemons/firewall.plist
Make sure that the launcher is added with:
$ sudo launchctl list
