I read
The Boof of PF and figured it out. The essential pfctl NAT and filter rules are
nat on en0 from 10.0.0.0/8 to any -> (en0)
pass from { lo0, 10.0.0.0/8 } to any keep state
and you have to do a lot of trial-and-error to make sure you don't break your access while integrating these rules into OS X Server's basic rule set. A description of the complete setup with the following pf.conf is
here.
sudo vi /etc/pf.conf
# References for modifications:
# The Book of PF by Peter N.M. Hansteen
# http://hints.macworld.com/article.php?story=20121011004626997
# http://blog.scottlowe.org/2013/05/15/using-pf-on-os-x-mountain-lion/
# http://krypted.com/mac-security/a-cheat-sheet-for-using-pf-in-os-x-lion-and-up/
# Options
set block-policy drop
set fingerprints "/etc/pf.os"
set ruleset-optimization basic
set skip on lo0
# Normalization
# Scrub incoming packets
scrub in all no-df
#
# com.apple anchor point
#
scrub-anchor "com.apple/*"
# Queueing
# Translation
# OpenVPN Server NAT
#
# The Book of PF, p. 21
int_if = "en0" # macro for internal interface
localnet = "10.0.0.0/8"
nat on $int_if from $localnet to any -> ($int_if)
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
# Filtering
lan_server = 10.0.1.3
# Antispoof
antispoof log quick for { lo0 en0 }
# Block by default
block in log
# Allow outgoing traffic from NAT'd { lo0, $localnet }
# The Book of PF, p. 21
pass from { lo0, $localnet } to any keep state
# Block to/from illegal destinations or sources
block in log quick from no-route to any
# Allow critical system traffic
pass in quick inet proto udp from any port 67 to any port 68
# Allow ICMP from home LAN
pass in log proto icmp from $lan_server:network
# Allow outgoing traffic
pass out inet proto tcp from any to any keep state
pass out inet proto udp from any to any keep state
# Internet services
internet_udp_services = "{ https, 500, 1194, 1701, 4500, 5060, 5190, 5297, 5298, 5678, 16384 }"
internet_tcp_services = "{ ssh, smtp, https, 143, 587, 993, 995, 1640, 2170, 2195, 2196, 4190,\
5218, 5223, 5190, 5220, 5222, 5298, 8008, 8443, 8800, 8843 }"
pass in quick inet proto tcp from any to { lo0, $lan_server } port $internet_tcp_services
pass in quick inet proto udp from any to { lo0, $lan_server } port $internet_udp_services
# LAN services: block access, except from localnet
lan_udp_services = "{ 5001 }"
lan_tcp_services = "{ domain, auth, nntp, www, 311, 3128, 5001, 5900:5909, 8118, 8123 }"
pass in quick inet proto tcp from { lo0, $localnet } to { lo0, $lan_server } port $lan_tcp_services
pass in quick inet proto udp from { lo0, $localnet } to { lo0, $lan_server } port $lan_udp_services