Author: jv
License: The MIT License, Copyright (c) 2007 jv
Description: basic ipfw ruleset for a personal firewall (behind a DSL router); the given ipfw ruleset aims to protect only a single computer as a network (LAN) endpoint, it does not know the dynamic WAN IP address; use at your own risk.
Platform: Mac OS X 10.4.11
Installation:
mkdir -p /usr/local/sbin
sudo touch /usr/local/sbin/rc.firewall
sudo touch /Library/LaunchDaemons/firewall.plist
sudo chmod 0750 /usr/local/sbin/rc.firewall
sudo chown root:wheel /usr/local/sbin/rc.firewall
sudo chmod 700 /Library/LaunchDaemons/firewall.plist
sudo chown root:wheel /Library/LaunchDaemons/firewall.plist
sudo nano /usr/local/sbin/rc.firewall
sudo nano /Library/LaunchDaemons/firewall.plist
sudo launchctl list
sudo launchctl load -w /Library/LaunchDaemons/firewall.plist
sudo launchctl unload -w /Library/LaunchDaemons/firewall.plist
Some useful network commands:
system_profiler SPNetworkDataType
scutil --help
scutil --dns
ipconfig getpacket en0
ipconfig getifaddr en0
ipconfig getoption en0 router
ipconfig getpacket en0 server_identifier
ipconfig getoption en0 subnet_mask
ipconfig getoption en0 domain_name_server
ifconfig en0 | grep broadcast | awk '{print $NF}'
netstat -rn | grep default
netstat -rn | awk '/default/ { print $NF, $2 }'
ifconfig -l
ifconfig -u
ifconfig -ld
ifconfig -lu
ifconfig -u | grep inet | tail -n 1 | grep -Eo '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}'
route -n get default
scselect 2>&1 | awk '/^ *\*/ {print $NF}' | sed -E 's/^\((.*)\)$/\1/'
dig -x 17.112.152.32
curl -L -s --max-time 10 http://checkip.dyndns.org | grep -Eo 'Current IP Address: [[:digit:]\.]+'
ipfw rules in /usr/local/sbin/rc.firewall:
exec >/dev/console 2>&1
if [[ "$(/usr/bin/id -u)" != "0" ]]; then echo "Must be run as root!"; exit 1; fi
OPATH=$PATH
export PATH=/usr/bin:/usr/sbin:/bin:/sbin
OIFS=$IFS
export IFS=$' \t\n'
sysctl="/usr/sbin/sysctl -w"
$sysctl net.inet.ip.fw.enable=1
$sysctl net.inet.ip.fw.verbose=2
$sysctl net.inet.ip.fw.verbose_limit=65535
if [[ -n $(/usr/sbin/sysctl -a | grep -o 'net.inet6.ip6.fw.enable:') ]]; then $sysctl net.inet6.ip6.fw.enable=1; fi
$sysctl net.inet6.ip6.fw.verbose=2
$sysctl net.inet6.ip6.fw.verbose_limit=65535
$sysctl net.inet.icmp.icmplim=1024
$sysctl net.inet.icmp.drop_redirect=1
$sysctl net.inet.icmp.log_redirect=1
$sysctl net.inet.icmp.bmcastecho=0
$sysctl net.inet.icmp.maskrepl=0
$sysctl net.inet.ip.redirect=0
$sysctl net.inet.ip.sourceroute=0
$sysctl net.inet.ip.accept_sourceroute=0
$sysctl net.inet.tcp.delayed_ack=0
$sysctl net.inet.ip.forwarding=0
$sysctl net.inet.tcp.strict_rfc1948=1
$sysctl net.inet.tcp.rfc1323=1
$sysctl net.inet.tcp.rfc1644=1
$sysctl net.inet.udp.blackhole=1
$sysctl net.inet.udp.log_in_vain=1
$sysctl net.inet.tcp.blackhole=2
$sysctl net.inet.tcp.log_in_vain=1
$sysctl net.inet.ip.fw.debug=1
$sysctl net.inet.ip.fw.autoinc_step=100
$sysctl net.inet.ip.check_interface=1
$sysctl net.inet.tcp.drop_synfin=1
$sysctl net.link.ether.inet.log_arp_warnings=1
$sysctl net.inet.ip.fw.dyn_keepalive=0
$sysctl kern.coredump=0
# redirect ipfw log messages to /private/var/log/ipfw.log for use
# with tools such as GeekTool, http://projects.tynsoe.org/en/geektool/
# requirement: $sysctl net.inet.ip.fw.verbose=2
if [[ -e "/usr/libexec/ipfwloggerd" ]]; then /usr/libexec/ipfwloggerd; fi
# close firewall during setup ...
#/sbin/ipfw -f -q add 1 deny all from any to any
# allow traffic on loopback interface during booting process (cf. firewall.plist launchd item) or for setting up uid rules, etc.
/sbin/ipfw -f -q add 1 allow all from any to any via lo0
/sbin/ipfw -f -q add 2 deny all from any to any
# ... and delete previous rules (but not those with id < 100)
# cf. http://maxao.free.fr/index.php?itemid=27 and curl -O http://maxao.free.fr/telechargements/firewall_startupitem.tgz
old_rules=`/sbin/ipfw list | /usr/bin/awk '{ if($1 >= 100 && $1 != 65535) print $1 }' | /usr/bin/uniq`
for rule in $old_rules; do
/sbin/ipfw -q delete $rule
done
IF="en0" # interface
add_rule="/sbin/ipfw -q add"
# logging traffic for testing or debugging only
# cf. $sysctl net.inet.ip.fw.autoinc_step=100
#$add_rule skipto 110 log all from any to any # log all traffic
#$add_rule skipto 210 log all from any 67-68 to any # DHCP
#$add_rule skipto 310 log all from any to any 67-68
#$add_rule skipto 410 log all from any to any 53 # DNS
#$add_rule skipto 510 log all from any to any 5353 # log all mDNS traffic
#$add_rule skipto 610 log all from any to 224.0.0.251 5353
#$add_rule skipto 710 log all from any 5353 to any 5353
$add_rule skipto 810 log all from any to 239.255.255.253 427 # multicast address for Service Location Protocol (SLP)
$add_rule skipto 910 log all from any to any 427
$add_rule skipto 1010 log igmp from any to any # log all igmp traffic
$add_rule skipto 1110 log all from any to any bridged # log forwarded packets
$add_rule skipto 1210 log layer2 mac-type arp # log ARP requests
$add_rule skipto 1310 log icmp from any to any # ICMP
$add_rule 2000 check-state
# limit the overall number of concurrent TCP sessions per unique source address
#$add_rule allow tcp from any to any via $IF setup limit src-addr 50
# ICMP
$add_rule allow icmp from me to any icmptypes 8 out via $IF keep-state # allow ping out
$add_rule allow icmp from any to me icmptypes 0 in via $IF keep-state
$add_rule allow icmp from any to any icmptypes 3,4 keep-state
$add_rule deny log icmp from any to any
$add_rule allow all from any to any via lo0 keep-state
$add_rule deny log ip from 127.0.0.0/8 to any in
$add_rule deny log ip from any to 127.0.0.0/8 in
$add_rule deny log ip from 224.0.0.0/3 to any in
$add_rule deny log tcp from any to 224.0.0.0/3 in
$add_rule deny log tcp from any 0 to any
$add_rule deny log tcp from any to any 0
$add_rule deny log udp from any 0 to any
$add_rule deny log udp from any to any 0
$add_rule deny log not udp from 0.0.0.0/8 to any
$add_rule 5000 skipto 5200 esp from any to any via $IF keep-state
$add_rule deny log all from any to any in frag
$add_rule deny log tcp from any to any established
#$add_rule deny log tcp from any to any established in
# block some invalid TCP flag combinations
$add_rule deny log tcp from any to any tcpflags '!fin,!syn,!ack,!rst,!psh,!urg' keep-state
$add_rule deny log tcp from any to any tcpflags '!syn,fin,!ack,!rst,!psh,!urg' keep-state
$add_rule deny log tcp from any to any tcpflags '!syn,!fin,!ack' keep-state
$add_rule deny log tcp from any to any tcpflags syn,fin keep-state # cf. net.inet.tcp.drop_synfin=1
$add_rule deny log tcp from any to any tcpflags ack,urg keep-state
$add_rule deny log tcp from any to any tcpflags syn,rst keep-state
$add_rule deny log tcp from any to any tcpflags fin,rst keep-state
$add_rule deny log tcp from any to any tcpflags fin,psh,urg keep-state
$add_rule deny log tcp from any to any tcpflags fin,psh keep-state
$add_rule deny log tcp from any to any tcpflags fin,urg keep-state
$add_rule deny log tcp from any to any tcpflags 'urg,!ack' keep-state
$add_rule deny log tcp from any to any tcpflags 'psh,!ack' keep-state
$add_rule deny log tcp from any to any tcpflags 'fin,!ack' keep-state
$add_rule deny log tcp from any to any tcpflags 'rst,!ack' keep-state
$add_rule deny log ip from any to any ipoptions rr,ts,lsrr,ssrr keep-state
# block blacklisted IP addresses
# http://www.stopforumspam.com/downloads/bannedips.csv
# http://danger.rulez.sk/projects/bruteforceblocker/blist.php (SSH bruteforce attacks blacklist)
# also see http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/afctl.8.html (for Mac OS X Server only)
$add_rule deny log src-ip 222.35.3.136
$add_rule deny log src-ip 202.54.130.157
$add_rule deny log src-ip 219.237.17.161
$add_rule deny log src-ip 122.160.64.237
$add_rule deny log src-ip 216.42.81.141
$add_rule deny log src-ip 216.42.81.143
$add_rule deny log src-ip 211.0.0.0/8
$add_rule deny log src-ip 80.116.0.0/16
$add_rule deny log src-ip 207.103.247.50
$add_rule deny log src-ip 221.0.0.0/8
$add_rule deny log src-ip 220.0.0.0/8
$add_rule deny log src-ip 80.117.0.0/16
$add_rule deny log src-ip 210.0.0.0/8
$add_rule deny log src-ip 217.0.149.0/24
# enable DHCP initialization (DSL router)
# get the router IP address by using the command: ipconfig getoption en0 router
# this rule should precede the automated anti-spoofing rule
$add_rule allow udp from $(/usr/sbin/ipconfig getoption $IF router 2>/dev/null || /bin/echo any) 67 to 255.255.255.255 68 via $IF keep-state
# also DHCP initialization, cf. http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol
$add_rule allow udp from 0.0.0.0 68 to 255.255.255.255 67 keep-state
$add_rule deny log all from 0.0.0.0/8 to any keep-state
$add_rule deny log ip from any to any not verrevpath in # automated anti-spoofing
# allow some multicast traffic
#$add_rule allow { igmp or udp } from any to 224.0.0.0/3 via $IF keep-state # for debugging only
$add_rule allow { igmp or udp } from me 5353 to 224.0.0.251 5353 out via $IF keep-state
$add_rule allow { igmp or udp } from me to { 224.0.0.1 or 224.0.0.2 } out via $IF keep-state
$add_rule allow { igmp or udp } from me to 224.0.0.251 out via $IF keep-state
$add_rule deny log all from any to 224.0.0.0/3 keep-state
# generic DNS & DHCP rules
$add_rule allow udp from me to any 53 out keep-state # DNS
$add_rule allow udp from any 53 to me in keep-state
$add_rule allow udp from any to any 67-68 via $IF keep-state # DHCP
$add_rule allow udp from any 67-68 to any via $IF keep-state
#------------------------------------
# alternative DNS & DHCP rules with specified IP addresses
# compare the output of the following commands online & offline
# alternative DNS rule with specified IP addresses
# sudo scutil --dns | awk '/nameserver/ { print $3 }' | sort | uniq | grep -E '^[[:digit:]\.]+$'
$add_rule allow { igmp or udp } from any to 224.0.0.0/3 via $IF keep-state
$add_rule deny log all from any to 224.0.0.0/3 via $IF keep-state
$add_rule allow udp from me to any 123 out via $IF uid root keep-state
$add_rule allow udp from me to 239.255.255.253 427 out via $IF keep-state
$add_rule allow udp from me to any 194,529,994 out via $IF keep-state
$add_rule allow tcp from me to any 194,529,994 out via $IF setup keep-state
$add_rule allow { tcp or udp } from me to any 6667 out via $IF keep-state
$add_rule allow { tcp or udp } from any 6667 to me in via $IF keep-state
$add_rule allow udp from me to any 873 out via $IF keep-state
$add_rule allow tcp from me to any 873 out via $IF setup keep-state
$add_rule allow tcp from me to any 80,443 out via $IF setup keep-state
$add_rule allow tcp from me to any 8080,16080 out via $IF setup keep-state
$add_rule allow tcp from me to any 8000 out via $IF setup keep-state
$add_rule allow tcp from me to any 25 out via $IF setup keep-state
POP3="110,995"
POP3="109,110,473,995,3206"
$add_rule allow udp from me to any $POP3 out via $IF keep-state
$add_rule allow udp from any $POP3 to me in via $IF keep-state
$add_rule allow tcp from me to any $POP3 out via $IF setup keep-state
$add_rule allow tcp from any $POP3 to me in via $IF setup keep-state
$add_rule allow udp from me to any 143,993 out via $IF keep-state
$add_rule allow udp from any 143,993 to me in via $IF keep-state
$add_rule allow tcp from me to any 143,993 out via $IF setup keep-state
$add_rule allow tcp from any 143,993 to me in via $IF setup keep-state
$add_rule allow tcp from me to any 3689 out via $IF setup keep-state
$add_rule allow tcp from any 3689 to me in via $IF setup keep-state
$add_rule allow udp from me to any isakmp in via $IF keep-state
$add_rule allow udp from any to me isakmp out via $IF keep-state
$add_rule allow { gre or esp or ipencap } from me to any out keep-state
$add_rule allow { gre or esp or ipencap } from any to me in keep-state
$add_rule deny log all from any to any
/sbin/ipfw delete 1
/sbin/ipfw delete 2
/sbin/ip6fw -q add 1 allow all from any to any via lo0
/sbin/ip6fw -q add 2 deny ipv6 from any to any
old_rules_ip6=`/sbin/ip6fw list | /usr/bin/awk '{ if($1 >= 100 && $1 != 65535) print $1 }' | /usr/bin/uniq`
for rule_ip6 in $old_rules_ip6; do
/sbin/ip6fw -q delete $rule_ip6
done;
/sbin/ip6fw -q add deny log ipv6 from any to any
/sbin/ip6fw delete 1
/sbin/ip6fw delete 2
export IFS=$OIFS
export PATH=$OPATH
exit 0
firewall.plist launchd item:
<?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>Labelkey>
com.apple.firewall</string>
<key>ProgramArgumentskey>
/usr/local/sbin/rc.firewallstring>
</array>
<key>RunAtLoadkey>
/>
<key>UserNamekey>
root</string>
dict>
</plist>
Further information:
- man ipfw
- Well Known TCP and UDP ports used by Apple software products
- Port Numbers
- Internet Multicast Addresses
- Multicast DNS
- OSX Firewall
- Le firewall ipfw
- Stateful OS X firewall
- Advanced Firewall Configuration
- ipfw Rules (for Mac OS X 10.5)
- Setting up firewall rules on Mac OS X
- Sample ipfw firewall ruleset
- IPFW Rule Sets - Stateful + NATD Rule Set
- 101 FreeBSD Ipfw resources
- Sysctl Node Analyser Table
- FAQ: Firewall Forensics (What am I seeing?)
- Exploring the Mac OS X Firewall
- Firewalls For Beginners
- Firewall Q&A
- Abnormal IP Packets
- TCP/IP Suite Weaknesses
- ICMP Stands For Trouble
- IPGadget - TCP/IP address calculator
- Superior Ad Blocking on OS X
-
Switching firewall settings from the command line