Get started with the Mac OSX firewall

Fri 02 May 2014

In this post I will give you the details you need to setup an effective firewall on your Mac. OS X comes with two types of firewalls, where one works at the application layer, and the other at the network layer. I give a brief introduction to both variants.

Introduction to ALF

Application Level Firewall (ALF) allows you to block incoming connections to your computer. I recommend that you turn on the firewall, which can be done via the graphical configuration tool found under:

"System Preferences" -> "Security and Privacy" -> "Firewall".

OS X Application Level Firewall Settings OSX Application Level Firewall Settings

You can also turn on ALF via the command line:

# defaults write /Library/Preferences/com.apple.alf globalstate -int 1

# launchctl load /System/Library/LaunchDaemons/com.apple.alf.agent.plist

# launchctl load /System/Library/LaunchDaemons/com.apple.alf.agent.plist

optionally disable ALF via the command line:

# defaults write /Library/Preferences/com.apple.alf globalstate -int 0

# launchctl unload /System/Library/LaunchDaemons/com.apple.alf.agent.plist

# launchctl unload /System/Library/LaunchDaemons/com.apple.alf.agent.plist

You can also edit most settings in ALF from the command line:

# cd /usr/libexec/ApplicationFirewall

# ./socketfilterfw --help

You can read the current ALF configuration using defaults command:

# defaults read /Library/Preferences/com.apple.alf.plist

You can restore the default ALF configuration:

# cp /usr/libexec/ApplicationFirewall/com.apple.alf.plist /Library/Preferences/

Introduksjon til PacketFilter

Packet Filter (PF) is the firewall originating from the operatingsystem OpenBSD. PF was launched on December 1, 2001, and is used by OpenBSD, FreeBSD, NetBSD, MacOSX + Apple iOS (FreeBSD), BlackBerry (NetBSD) and more.

  • Starting with Mac OS X 10.7 Lion, Apple has replaced ipfw to pf
  • Mac OS X version of pf is ported from FreeBSD, using pre-OpenBSD 4.6 syntax

To get started with pf we need two things:

  • pf configuration file(s).
  • one launchd entry for pf so that it starts up when booting the machine.

By default, we find an empty configuration file in / etc / pf.anchors / com.apple, which gives us two possibilities:

  • Use the existing empty configuration file
  • Ignore the existing configuration file and create a new

The disadvantage of the first option is that you will lose your configuration if Apple see fit to do anything with this file during a system update.

pfctl also have some issues with loading the rules from the default configuration file.

I decide to go for option 2 here since my experience with updates from Apple are varying.

Get started with PF

To get started we need the following four files:

  • pf configuration file that is read at startup
  • one anchorfile containing rules and options that we load into pf at startup
  • one macrofile containing variables that we can use in our rules
  • one launchdaemon which ensures that pf gets started when starting the machine

We create the files with the following content:

/etc/pf.anchors/no.visualisere.pf.conf

anchor “no.visualisere.pf"load anchor “no.visualisere.pf" from "/etc/pf.anchors/no.visualisere.pf.rules"
/etc/pf.anchors/no.visualisere.pf.rules

include "/etc/pf.anchors/no.uib.visualisere.pf.macros"

# Don't filter on the loopback interface
set skip on lo0

set ruleset-optimization basic

# Return blocked packet so that the other entity can free up its resources without waiting for timeouts
set block-policy return

# Scrub incoming packets, with no-df to prevent nfs from malfunctioning
scrub in all no-df

# Antispoof, with logging
antispoof log for $ext_if
antispoof log for $int_if

# Block by default, without log
block in

# Allow outgoing, without log
pass out

# Allow DHCP, without log
pass in inet proto udp from any port 67 to any port 68

# Allow ICMP, and log it
pass in log inet proto icmp

# Allow all from trusted servers, and log it
pass in log from $trusted_servers

/etc/pf.anchors/no.visualisere.pf.macros

icmp_types = "{ echoreq, unreach }"
ext_if = "{ en0 }"
int_if = "{ lo0 }"
trusted_servers = "{ 10.10.12.12, 10.10.13.13 }"

/Library/LaunchDaemons/no.visualisere.pf.plist


<?xml version="1.0" encoding="UTF-8" ?>
<!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>no.uib.visualisere.pf</string>
<key>WorkingDirectory</key>
<string>/var/run</string>
<key>UserName</key>
<string>root</string>
<key>GroupName</key>
<string>wheel</string>
<key>Program</key>
<string>/sbin/pfctl</string>
<key>ProgramArguments</key>
<array>
<string>/sbin/pfctl</string>
<string>-e</string>
<string>-f</string>
<string>/etc/pf.anchors/no.uib.visualisere.pf.conf</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>ServiceDescription</key>
<string>FreeBSD Packet Filter (pf) daemon</string>
<key>StandardErrorPath</key>
<string>/var/log/pf.log</string>
<key>StandardOutPath</key>
<string>/var/log/pf.log</string>
</dict>
</plist>

This is a simple setup that blocks most incoming traffic except DHCP and ICMP. We also opens for trusted IP addresses so that we can reach the machine via ssh.

If you want to learn PF, there are links to articles and books that you can look into at the bottom of this post.

Some nifty commands


pfctl -sa , give full status information
pfctl -v -n -f <path to configuration file> , parse configuration file and any anchor files referenced

Turn on logging in PF

To log what happens we can use tcpdump to listen on the interface that pf logs.

First we create the interface:


# ifconfig pflog0 create

, then we can listen on it:

# tcpdump -n -e -ttt -i pflog0

More resources

  • http://home.nuug.no/~peter/pf/
  • http://www.openbsd.org/faq/pf/
  • https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man8/pfctl.8.html
  • https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/pf.conf.5.html#//apple_ref/doc/man/5/pf.conf

Comments