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 # private IP address ipconfig getoption en0 router # router IP address 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 # available interfaces 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 # dynamic WAN IP address curl -L -s --max-time 10 http://checkip.dyndns.org | grep -Eo 'Current IP Address: [[:digit:]\.]+'
ipfw rules in /usr/local/sbin/rc.firewall:
# $ sudo cat /usr/local/sbin/rc.firewall #!/bin/sh exec >/dev/console 2>&1 # write stdout & stderr to console.log in /Library/Logs/Console/ 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:]\.]+$' #DNS_SERVERS="{ 224.0.0.251 or xxx.xxx.xxx.xxx or xxx.xxx.xxx.xxx }" #$add_rule allow udp from me to ${DNS_SERVERS} 53 out via $IF keep-state # alternative DHCP rule with specified IP addresses # ipconfig getoption en0 router (use when online) #DHCP="{ me or xxx.xxx.xxx.xxx or 255.255.255.255 or 0.0.0.0 }" #$add_rule allow udp from $DHCP 67 to $DHCP 68 in via $IF keep-state #$add_rule allow udp from $DHCP 68 to $DHCP 67 out via $IF keep-state #$add_rule deny log ip from any to any not verrevpath in # automated anti-spoofing #------------------------------------ $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 # grep -i ' 873' /etc/services # grep -i 'IRC' /etc/services # http://docs.info.apple.com/article.html?artnum=106439 (known ports) # defaults read /Library/Preferences/com.apple.sharing.firewall $add_rule allow udp from me to any 123 out via $IF uid root keep-state # allow root to query ntpd #$add_rule allow udp from me to any 123 out via $IF uid root #$add_rule allow udp from any 123 to me in via $IF uid root $add_rule allow udp from me to 239.255.255.253 427 out via $IF keep-state # svrloc (Service Location Protocol; Bonjour) #$add_rule allow udp from any to any 427 in via $IF keep-state $add_rule allow udp from me to any 194,529,994 out via $IF keep-state # IRC (Internet Relay Chat Protocol), IRC-SERV, IRC over TLS/SSL $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 # Colloqy, http://colloquy.info/project/wiki/FAQs $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 # rsync; try /opt/local/bin/port list (http://www.macports.org) $add_rule allow tcp from me to any 873 out via $IF setup keep-state #SECOND_LIFE="{ 63.210.156.0/21 or 66.150.244.0/24 or 64.129.40.0/21 }" # Second Life #$add_rule allow udp from me to $SECOND_LIFE out via $IF keep-state #$add_rule allow udp from $SECOND_LIFE to me in via $IF keep-state #$add_rule allow tcp from me to $SECOND_LIFE out via $IF setup keep-state #$add_rule allow tcp from $SECOND_LIFE to me in via $IF setup keep-state $add_rule allow tcp from me to any 80,443 out via $IF setup keep-state # HTTP, HTTPS $add_rule allow tcp from me to any 8080,16080 out via $IF setup keep-state # Alternate port for Apache, Web service with performance cache $add_rule allow tcp from me to any 8000 out via $IF setup keep-state # cf. http://wooledge.org:8000/BashFAQ $add_rule allow tcp from me to any 25 out via $IF setup keep-state # SMTP (Simple Mail Transport Protocol) #$add_rule allow tcp from any 25 to me in 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 # POP3, POP3S $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 { tcp or udp } from me to any 110,995 out via $IF keep-state # POP3, POP3S alternative #$add_rule allow { tcp or udp } from any 110,995 to me in via $IF keep-state $add_rule allow udp from me to any 143,993 out via $IF keep-state # IMAP, IMAPS $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 udp from any 5353 to 224.0.0.251 5353 in via $IF keep-state # Bonjour multicast (already allowed above) $add_rule allow tcp from me to any 3689 out via $IF setup keep-state # iTunes Music Sharing $add_rule allow tcp from any 3689 to me in via $IF setup keep-state #$add_rule allow udp from me to any 137,138,139 out via $IF keep-state # Samba #$add_rule allow udp from any 137,138,139 to me in via $IF keep-state #$add_rule allow tcp from me to any 137,138,139 out via $IF keep-state setup #$add_rule allow tcp from any 137,138,139 to me in via $IF keep-state setup $add_rule allow udp from me to any isakmp in via $IF keep-state # Internet Security Association and Key Management Protocol; IPsec $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 # VPN $add_rule allow { gre or esp or ipencap } from any to me in keep-state # cf. rule 5000 for esp above; and http://www.maclive.net/sid/132 #$add_rule allow tcp from any to any dst-port 20,21 via $IF setup keep-state # FTP; limit src-addr 10 #$add_rule allow tcp from any to any 1024-65535 via $IF setup keep-state # cf. sysctl -a | grep net.inet.ip.portrange #$add_rule allow tcp from any to any 49152-65534 in via $IF setup keep-state # cf. http://forums.the-kingdom.net/viewtopic.php?t=92 #$add_rule allow tcp from me 22 to any out via $IF setup limit src-addr 4 # SSH #$add_rule allow tcp from any to me 22 in via $IF setup limit src-addr 4 #$add_rule allow tcp from me 23 to any out via $IF setup limit src-addr 4 # Telnet #$add_rule allow tcp from any to me 23 in via $IF setup limit src-addr 4 $add_rule deny log all from any to any #$add_rule allow all from any to any # setup finished : reopen firewall #/sbin/ipfw delete 1 /sbin/ipfw delete 1 /sbin/ipfw delete 2 # IPv6 Firewall # close firewall during setup #/sbin/ip6fw -q add 1 deny ipv6 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/ip6fw -q add 1 allow all from any to any via lo0 /sbin/ip6fw -q add 2 deny ipv6 from any to any # delete previous rules (but not those with id < 100) 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 1 /sbin/ip6fw delete 2 export IFS=$OIFS export PATH=$OPATH exit 0
firewall.plist launchd item:
# $ sudo cat /Library/LaunchDaemons/firewall.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>com.apple.firewall</string> <key>ProgramArguments</key> <array> <string>/usr/local/sbin/rc.firewall</string> </array> <key>RunAtLoad</key> <true/> <key>UserName</key> <string>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