Strotmann.de
07 Apr 2011

Managing the MacOS X IPv6 firewall

MacOS X (10.3 and up) contains an IPv6 firewall (ip6fw), which has been inherited from FreeBSD and the KAME project. However there are no configuration or startup scripts, nor any other support available in a stock MacOS X system to manage this firewall.

The script presented here will read a firewall configuration from /etc/ip6fw.conf and will apply the IPv6 firewall rules to the MacOS X firewall.

#!/bin/sh

ip6fwconf="/etc/ip6fw.conf"
ip6fw=`which ip6fw` 
logcmd="logger -p local0.info -t IP6FW"

if [ -z "$ip6fw" ]; then
   $logcmd "no ip6fw binary found in path"
fi

$ip6fw -fq flush

while read line; do
  # remove comments and normalize to lowercase
  line=`echo $line | sed '/^ *#/d;s/#.*//' | tr "[:upper:]" "[:lower:]"`


  if [[ $line == *logging=* ]]; then
    value=${line#*=}
    if [[ $value == 'yes' ]]; then
      $logcmd "logging on"
      sysctl -w 'net.inet6.ip6.fw.verbose=2'
    else
      $logcmd "logging off"
      sysctl -w 'net.inet6.ip6.fw.verbose=0'
    fi
  fi
  action=`echo $line | awk '{ print $2 }'`
  rulenum=`echo $line | awk '{ print $1 }'`
  rule=`echo $line | awk '{ for (i = 3; i <= NF; i++) { printf "%s ",$i } }'`

  case $action in 
     allow | deny | unreach )
        $logcmd -s "add $rulenum $action $rule"
        $ip6fw add $rulenum $action $rule
       ;;
     "")
       ;; 
     *) $logcmd "unsupported action $action"
       ;;
  esac

done < $ip6fwconf

The default configuration for the MacOS X firewall is

# MacOS X 10.x ip6fw configuration

logging=yes

# loopback 
10000 allow ipv6 from any to any via lo0

# Duplicate Address detection (DAD)
20000 allow ipv6-icmp from any to FF02::/16

# Neighborhood discovery (ND)
20010 allow ipv6-icmp from FE80::/10 to FE80::/10
20015 allow ipv6-icmp from FE80::/10 to FF02::/16
20016 allow ipv6-icmp from any to any icmptype 135,136

# ICMPv6 from the network
20020 allow ipv6-icmp from any to any in icmptype 1,2,3,4,128,129

# Router Advertisements 
20050 allow ipv6-icmp from any to any icmptype 134
20055 allow ipv6-icmp from any to any icmptype 133

# allow established TCP connections
20100 allow tcp from any to any established

# NTP multicast
20210 allow udp from any to ff02::1010 123 via en0

# mDNS (Rendezvous/Bonjour)
20220 allow udp from any to ff02::fb 5353 via en0

# allow all outgoing IPv6 connections
20230 allow ipv6 from any to any out

# allow DNS in and out
20240 allow udp from any to any 53 out
20241 allow udp from any 53 to any in

# Secure Shell
20500 allow tcp from any to any 22

# Web-Server
#20510 allow tcp from any to any 80

# Postfix SMTP
#20520 allow tcp from any to any 25

# IPP / CUPS
20530 allow tcp from any to any 631

# Apple Filing Protocol
20540 allow tcp from any to any 548
20541 allow tcp from any to any 427

# block all not otherwise allowed and log
65534 unreach admin log ipv6 from any to any

To execute this script everytime MacOS X boots, a LaunchDaemon configuration is installed in /Library/LaunchDaemons:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Disabled</key>
    <false/>
    <key>Label</key>
    <string>de.strotmann.ip6fw</string>
    <key>OnDemand</key>
    <false/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/sbin/ip6fw-load</string>
    </array>
    <key>LaunchOnlyOnce</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>ServiceDescription</key>
    <string>loads ip6fw firewall rules from /etc/ip6fw.conf</string>
</dict>
</plist>

The installer package will install the script into /usr/local/sbin/ip6fw-load, a default configuration file into /etc/ip6fw.conf/default and if no file /etc/ip6fw.conf exists, it will create this file containing the default configuration. It will then load the LaunchDaemon configuration with

launchctl load -w /Library/LaunchDaemons/de.strotmann.ip6fw.plist

MacOS X 10.5/10.6 installer package

With sudo ip6fw list on the terminal commandline we can check that all the rules are loaded and active:

# sudo ip6fw list
Password:
10000 allow ipv6 from any to any via lo0
20000 allow ipv6-icmp from any to ff02::/16
20010 allow ipv6-icmp from fe80::/10 to fe80::/10
20015 allow ipv6-icmp from fe80::/10 to ff02::/16
20016 allow ipv6-icmp from any to any icmptype 135,136
20020 allow ipv6-icmp from any to any in icmptype 1,2,3,4,128,129
20050 allow ipv6-icmp from any to any icmptype 134
20055 allow ipv6-icmp from any to any icmptype 133
20100 allow tcp from any to any established
20210 allow udp from any to ff02::1010 123 via en0
20220 allow udp from any to ff02::fb 5353 via en0
20230 allow ipv6 from any to any out
20240 allow udp from any to any 53 out
20241 allow udp from any 53 to any in
20500 allow tcp from any to any 22
20530 allow tcp from any to any 631
20540 allow tcp from any to any 548
20541 allow tcp from any to any 427
65534 unreach admin log ipv6 from any to any
65535 allow ipv6 from any to any
Other posts
Creative Commons License
strotmann.de by Carsten Strotmann is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License .