Setting up firewall rules on Mac OS X

Preamble

The correct link for this page: http://www.novajo.ca/firewall.html


This page describes how I set up firewall rules on my Mac OS X (Jaguar or Panther) home computer using the built-in firewall (ipfw). The old 10.1 page is available here. You will need to use the Terminal application. If you want something simpler, go get the excellent Brick House, Firewalk or SunShield which all have simple options and a nice interface. In Mac OS X 10.2 and up, you can also use the System Preferences panel, Sharing:Firewall. For most cases (if you don't want anything fancy or if you don't know and don't want to know anything about firewalls), this is enough. If you use more than standard Apple services and want to know more, read on. Mom, stop here.

A firewall is a strict set of rules to allow or deny certain connections to or from your computer. Without a firewall, any connection to your computer is allowed (see Figure below).

The firewall software is part of the operating system (i.e. you don't have to buy anything), and by default lets everything through (which means it is as if you had no firewall). Configuring your firewall means adding rules to permit only certain connections. The approach taken here is to explicitly allow only certain things to and from your computer, while blocking everything else. This is by far the most secure configuration.

All computers on the internet can communicate with each other if they have the required hardware (i.e. a network card, a modem, an airport card, etc...). These devices on your computer are related to a given network interface. These interfaces can be labelled with an acronym and a number that represent the language they talk (ppp0) or just with a generic name (en0). A network interface can also be logical (i.e. it is not related to an actual physical device) and play the role of routing traffic from one place to another. Network interfaces are the start and the end points of any connections.

But what is a connection? A connection is a discussion between two computers that are uniquely identified with an address (IP address, or IP for short) . The connection has a source IP address and a destination IP address. These refer respectively to the computer from which the connection was initiated and the destination computer to which the information is going.

To avoid various internet attacks that fake your IP address (or others') and fool your computer into doing something it should not do, you want to explicitly specify the address of your computer in the firewall rules. The idea is simple: there are certain IP addresses that represent something specific. For instance, the address 127.0.0.1 represents your computer, locally. Some other addresses are valid only when they come from "the inside world". Hence, by looking at the source IP address of an attempted connection, you can often prevent attacks to your computer. However, if you have a dynamic IP (often DSL, Cable), your IP address may change and you need to change the rules to reflect that. You could of course simply avoid using your IP address in the firewall rules, but it is not as safe as explicitly stating what your IP address is. The approach taken in this document is to be as restrictive as possible and always use your outside IP address. When the IP address changes, the firewall rules are reset.

A connection between two computers is made through specific ports. To make a simple analogy, the IP address is the building address and the port is the appartment number. Each computer (including yours) has several ports, numbered from 1 to 65000. Everything we do on the web (surfing the web, sending mail, etc...) is a use of a specific port on each computer. For instance, when you use a web browser, your computer connects to the port 80 of the web server through one of its own port. The ports below 1024 are considered reserved ports and are assigned to various services (http is port 80, ftp is 21, pop3 is 110, etc...). Your computer listens to some of the ports. For instance, if you have your own web server, your computer listens to port 80. If somebody tries to contact your computer via a web browser, it will do so by trying to connect to your port 80. But your computer also listens to some other ports, some of which should only be used by yourself (the port mechanism is very general and has more use than just communicating between two computers). Therefore, you want to restrict access to certain ports only and you do that with a firewall.

In addition to my regular internet connection (in my case, via DSL), I also have a tiny private network to share files with an iBook, which means I actually have two IP addresses: the outside IP (on interface ppp0, dynamic IP) and an internal static IP (inside interface en0, fixed IP 192.168.0.1). This configuration allows me to plug in an iBook at anytime at the back of my G4 and log in to kill jobs if I ever lose the console (not that I ever did, but it's nice to have it there). With the advent of Rendez-vous (Mac OS X 10.2), you don't even need that anymore: your computer can "create" IP addresses to be able to talk to other Rendez-vous enabled computers.

With a dynamic IP, you must make sure that the firewall is always synchronized with your IP. For instance, if you disconnect, then reconnect, your IP might have changed, but your firewall rules have not. You must then change the firewall rules to reflect the change of your IP. A script is available at the bottom of this page to do just that.

It might come to your attention when you set up the rules that your DNS Agent seems to time out pretty often, especially when you set up the rules. I don't know why that is.

The layout for the code (black outline, dark background) is identical to the one used on the very useful Stepwise. I thought it looked good.

ipfw firewall rules for Mac OS X

I deserve no credit whatsoever since Peter Brezny at BSDToday has published an article on that. The original of this file can be found at http://www.bsdtoday.com/2000/December/Features359.html. The only thing I did is to make slight modifications:

Modify the file to suit your needs: outside interface (pppoe? ppp?) and inside interface (necessary?). I removed the original comments in and commented out the lines I modified. I found a few interesting tutorials on Firewalls at OnLamp.com if you want more info. Hopefully, my modifications are correct. Feel free to email me for corrections.

Download

You can get all the necessary files in the tar file MacOS_X_Firewall.tar. The tar file contains:

The firewall rules

The rules are described below. To execute it, do sh rc.firewall.current as root, or sudo sh rc.firewall.current. Once you know it works, you can set up the computer to start the firewall automatically. The log is found at /var/log/system.log. If you make a mistake and it locks up, wait or type ipfw flush, look at the system.log and start over. You can look up every denied connection by typing grep "Deny" /var/log/system.log.

You need to modify the document in order to provide some information about your configuration, right after the line that says: # Define your variables.

Transition to 10.2 or 10.3 from 10.1: Mac OS X 10.2 (Jaguar) or 10.3 (Panther) has an udpated firewall software which allows what are called "dynamic rules". With those, it is possible to temporarily keep track of the friendly computers with which you have initiated connections and allow them back in when they talk to you. This is particularly useful for a certain type of connections (Domain Name server lookups) since they use UDP instead of TCP, and UDP connections have no short term memory (i.e. they are clueless, just like my boss). Also, Rendezvous makes use of certain addresses that used to be considered internal (draft-manning-dsua-01.txt below). We now allow those connections (I am not quite sure how safe that is, but that's all I can do for now). You will see (with sudo ipfw show) many dynamic rules to port 427 on your machine from machines like 239.255.255.253. That's normal, although I am unsure exactly what it is (svrloc?). Finally, the small script to extract the outside ip address now has a "-w" option to work properly (thanks to Adrian Milliner for that).

#!/bin/sh # Originally found at http://www.bsdtoday.com/2000/December/Features359.html # By Peter Brezny # Modifications done to support dynamic IP and default OS X configuration # by D. Cote, available at: http://www.novajo.ca/firewall.html # # Simple stateful network firewall rules for IPFW with NAT v. 1.01 # See bottom of file for instructions and description of rules # Created 20001206206 by Peter Brezny, pbrezny@purplecat.net (with a great # deal of help from freebsd-security@freebsd.org). Specific questions # about the use of ipfw should be directed to freebsd-ipfw@freebsd.org or # more general security questions to freebsd-security@freebsd.org. # Use this script at your own risk. # # if you don't know the a.b.c.0/xx notation for ip networks the ipsubnet # calculator can help you. /usr/ports/net/ipsc-0.4.2 # ############################ # Make sure logging is enabled (disabled by default) if [ `/usr/sbin/sysctl -n net.inet.ip.fw.verbose` == 0 ] ; then /usr/sbin/sysctl -w net.inet.ip.fw.verbose=1 fi # # Define your variables # fwcmd="/sbin/ipfw" # leave as is if using ipfw oif="ppp0" # set to outside interface name (for DSL pppoe0 in 10.0.x, # pppoe0 in > 10.1.x) # set following line to outside ip address # or leave as is for dynamic IP address) oip=`/sbin/ifconfig $oif| grep -w inet | awk '{ print $2 }'`; onwr="$oip/8" #set to outside network range iif="en0" #set to internal interface name inwr="192.168.0.0/16" #set to internal network range iip="192.168.0.1" #set to internal ip address # # End of required user input if you only intend to allow ssh connections to # this box from the outside. If other services are required, edit line 96 # as necessary. # ### # Rules with descriptions # # Basic rules: there is no need to modify anything in this first section. # This is the bare minimum to block simple spoofing. ### # # Force a flush of the current firewall rules before we reload $fwcmd -f flush # Allow your loop back to work $fwcmd add allow all from any to any via lo0 # Prevent spoofing of your loopback $fwcmd add deny log all from any to 127.0.0.0/8 # # Stop spoofing of your internal network range $fwcmd add deny log ip from $inwr to any in via $oif # # Stop spoofing from inside your private ip range $fwcmd add deny log ip from not $inwr to any in via $iif # # Stop private networks (RFC1918) from entering the outside interface. $fwcmd add deny log ip from 192.168.0.0/16 to any in via $oif $fwcmd add deny log ip from 172.16.0.0/12 to any in via $oif $fwcmd add deny log ip from 10.0.0.0/8 to any in via $oif $fwcmd add deny log ip from any to 192.168.0.0/16 in via $oif $fwcmd add deny log ip from any to 172.16.0.0/12 in via $oif $fwcmd add deny log ip from any to 10.0.0.0/8 in via $oif # # Stop draft-manning-dsua-01.txt nets on the outside interface # $fwcmd add deny log all from 0.0.0.0/8 to any in via $oif # $fwcmd add deny log all from 169.254.0.0/16 to any in via $oif # $fwcmd add deny log all from 192.0.2.0/24 to any in via $oif # $fwcmd add deny log all from 224.0.0.0/4 to any in via $oif # $fwcmd add deny log all from 240.0.0.0/4 to any in via $oif # $fwcmd add deny log all from any to 0.0.0.0/8 in via $oif # $fwcmd add deny log all from any to 169.254.0.0/16 in via $oif # $fwcmd add deny log all from any to 192.0.2.0/24 in via $oif # $fwcmd add deny log all from any to 224.0.0.0/4 in via $oif # $fwcmd add deny log all from any to 240.0.0.0/4 in via $oif # ### # User rules: Some of the rules below are dependent on your configuration. # They might require some adjustments. They are emphasized with the # word "ADJUST". ### # ADJUST: If you use NATD (for your 192.168.0.1 interface for instance) # you must uncomment the following. If you don't or if you don't know, # make sure next rule (divert) is commented. # Divert all packets through natd # $fwcmd add divert natd all from any to any via $oif # # Allow all established connections to persist (setup required # for new connections). $fwcmd add allow tcp from any to any established # # ADJUST: Allow incoming requests to reach the various services. # To allow multiple services you may list them separated # by a coma, for example ...to $oip 22,25,110,80 setup # If you have an internal interface (e.g. if you do not run NATd) # uncomment the second line to enable AppleTalk on it. $fwcmd add allow tcp from any to $oip ftp,ssh,http,svrloc,afpovertcp setup # $fwcmd add allow tcp from $oip to $iip 548 setup # # NOTE: you may have to change your client to passive or active mode # to get ftp to work once enabled, only ssh, ftp and appletalk enabled by default. # 21: ftp enabled by default # 22: ssh enabled by default # 23: telnet # 25: smtp # 80: http enabled by default # 110: pop # 143: imap # 80: http # 427: svrloc (?) # 443: ssl # 548: appleshare enabled by default # 2401: cvs # 5900-5909: VNC server, screen 0 through 9 # 6669: Limewire # # # Allow icmp packets for diagnostic purposes (ping traceroute) # you may wish to leave commented out. $fwcmd add allow icmp from any to any # # Allow required ICMP $fwcmd add allow icmp from any to any icmptypes 3,4,11,12 # Politely and quickly rejects AUTH requests (e.g. email and ftp) $fwcmd add reset tcp from any to $oip 113 # # Checks packets against dynamic rule set below. $fwcmd add check-state # # Allow any traffic from firewall ip to any going out the # external interface $fwcmd add allow ip from $oip to any keep-state out via $oif # # Allow any traffic from local network to any passing through the # internal interface $fwcmd add allow ip from $inwr to any keep-state via $iif # # Deny everything else $fwcmd add 65435 deny log ip from any to any # ##################################################### # # End firewall script.

Installing and starting the firewall

You need either option 1) or option 2), not both.

1) Dynamic IP address with ppp connection (most modems)

There used to be a shell script that would monitor the IP address and adjust the firewall accordingly when required. This broke with 10.1.x. However, I found out in the mean time that there is a much simpler way of doing that. With a ppp connection (i.e. modem), two scripts are automatically called when the connection is up and when the connection is taken down. They are /etc/ppp/ip-up and /etc/ppp/ip-down (see man pppd for more info in the terminal). Hence, one simply has to start the firewall in /etc/ppp/ip-up and flush the firewall in /etc/ppp/ip-down. I have provided two very simple ip-up and ip-down scripts. It assumes you will keep rc.firewall.current in /usr/local/sbin/. The script ip-up also works around a small bug in natd for 10.1 where it does not reset itself after a change of IP address (look at ip-up for more info, but it is pretty trivial).

Dynamic IP with ppp: start firewall when connection is up cd /wherever/you/downloaded/MacOS_X_Firewall sudo install -o root -g admin -m 0700 rc.firewall.current /usr/local/sbin/ sudo install -o root -g admin -m 0770 ip-up ip-down /etc/ppp/

You do not need anything in the /Library/StartupItems/ directory and if you do have a /Library/StartupItems/Firewall directory, you should delete it. You are done.

2) Static IP address without ppp

The best thing to do with a static IP address is to set up the firewall at boot time by adding an item in /Library/StartupItems/Firewall/. In the archive provided above, you will find Firewall and StartupParameters.plist which you will copy into /Library/StartupItems/. It assumes you will keep rc.firewall.current in /usr/local/sbin/.

Static IP and no ppp: start firewall on startup cd /wherever/you/downloaded/MacOS_X_Firewall sudo install -o root -g admin -m 0700 rc.firewall.current /usr/local/sbin/ sudo install -o root -g admin -m 0770 Firewall StartupParameters.plist /Library/StartupItems/Firewall/

Next time you reboot, the firewall will be up. For now, you should simply do: sudo /Library/StartupItems/Firewall/Firewall. No need to reboot, you are done.

Connection log

By default, if you don't change anything, every logged connection (i.e. those with a "log" option) will be written to /var/log/system.log. With Mac OS X 10.3, connections now get logged as "ipfw" and can be sent to a separate file. All you need to do is modifiy the file called /etc/syslog.conf.

Add this at the top of /etc/syslog.conf: # Exclude ipfw entries from other logs !-ipfw Add this at the bottom: # Redirect ipfw entries to ipfw.log !ipfw *.* /var/log/ipfw.log

Then call sudo kill -HUP `cat /var/run/syslog.pid`. Now all logged connections (denied or accepted) will be sent to /var/log/ipfw.log instead of system.log.

Troubleshooting

There are a few problems when you have a firewall:

Contact information

You can email me at dccote@novajo.ca for corrections, comments or questions.