Login  |  Register  |  Contact

ipfw Rules, v2007/12/12

Based on extensive feedback, these rules are now much improved over the initial draft. Thanks, all!

All the versions of this post are getting out of hand, so Rich has provided a permanent URL for the current Leopard ipfw post for future reference. Please use that link, so future visitors get the latest and greatest.


DO NOT USE THESE RULES without customizing them first!

Version: 2007/12/12

For more information, see http://securosis.com/2007/11/15/ipfw-rules/

& http://securosis.com/2007/11/16/ipfw-rules-20071116-revision/#comments

These rules MUST be customized to your requirements.

In particular, if you have a private home network (behind an AirPort

Base Station, Linksys WRT54G, etc.), change “” below to

your private network range; duplicate rules with different ranges, if use use this computer on multiple networks.

Additionally, allow only ports you actually use; block unused ports.

Thanks to:

Rich Mogull http://securosis.com

windexh8er: http://www.slash32.com/


Lee: http://thnetos.wordpress.com/


Chris Pepper http://www.extrapepperoni.com/

Apple (Server Admin is a good way to create an ipfw ruleset)


FreeBSD (where Apple got ipfw) http://www.freebsd.org/

We don’t really want this, but it’s unavoidable on Mac OS X Server, so

document it here (serialnumberd).

100 allow udp from any 626 to any dst-port 626

Let me talk to myself over the loopback.

add 200 allow ip from any to any via lo0

Loopback traffic on a ‘real’ interface is bogus.

add 300 deny log logamount 1000 ip from any to

Block multicast unless you need it.

add 400 deny log logamount 1000 ip from to any in

If we let a conversation begin, let it continue.

Let my clients go!

add 500 allow tcp from any to any out keep-state add 510 allow udp from any to any out keep-state

Block replies, if we don’t recall initiating the conversation.

add 520 deny log tcp from any to any established in

Allow DHCP responses (keep-state can’t handle DHCP broadcasts).

add 600 allow udp from any to any src-port 67 dst-port 68 in

Do you never need fragmented packets?

add 700 deny udp from any to any in frag

Let yourself ping.

add 1000 allow icmp from to any icmptypes 8

Server Admin provides these by default.

add 1100 allow icmp from any to any icmptypes 0 add 1110 allow igmp from any to any

mDNS (Bonjour) from trusted local networks (fill in your own,

preferably non-standard, networks after ‘from’).

For Back to My Mac, you might need this from ‘any’.

add 5000 allow udp from to any dst-port 5353

add 5010 allow udp from 5353 to any dst-port 1024-65535 in

ssh – should be restricted to trusted networks if at all possible; if

open to the Internet, make sure you don’t have “PermitRootLogin yes

in sshd_config (at least use

PermitRootLogin without-password”, please!)

add 5200 allow tcp from any to any dst-port 22

iTunes music sharing

add 5300 allow tcp from to any dst-port 3689


add 5400 allow tcp from to any dst-port 548

HTTP (Apache); HTTPS

add 5500 allow tcp from any to any dst-port 80

add 5510 allow tcp from any to any dst-port 443

L2TP VPN – is this complete?

add 5600 allow udp from any to any dst-port 1701

add 5610 allow esp from any to any

add 5620 allow udp from any to any dst-port 500

add 5630 allow udp from any to any dst-port 4500

iChat: local

add 5700 allow tcp from to any dst-port 5298

add 5710 allow udp from to any dst-port 5298

add 5720 allow udp from to any dst-port 5297,5678

Server Admin SSL (Mac OS X Server only)

add 5800 allow tcp from to any dst-port 311

add 5810 allow tcp from to any dst-port 427

add 5820 allow udp from to any dst-port 427

syslog – uncommon

add 5900 allow udp from to any dst-port 514

ipp (CUPS printing)

add 6000 allow tcp from to any dst-port 631

MTU discovery

add 10000 allow icmp from any to any icmptypes 3

Source quench

add 10100 allow icmp from any to any icmptypes 4

Ping out; accept ping answers.

add 10200 allow icmp from any to any icmptypes 8 out add 10210 allow icmp from any to any icmptypes 0 in

Allow outbound traceroute.

add 10300 allow icmp from any to any icmptypes 11 in

My default policy: log and drop anything that hasn’t matched an allow

rule above

add 65534 deny log logamount 1000 ip from any to any

Hard-coded default allow rule (compiled into Darwin kernel)

add 65535 allow ip from any to any


No Related Posts
Previous entry: Data Security Lifecycle- Technologies, Part 3 | | Next entry: Network Security Podcast Up: With Special Guest Chris Hoff


If you like to leave comments, and aren't a spammer, register for the site and email us at info@securosis.com and we'll turn off moderation for your account.

By windexh8er  on  12/11  at  07:55 PM

Nice work—haven’‘t really gone over it in detail yet but the one thing that stuck out was commented out line 1000 is already uncommented in line 10200.  1100 trumps 10210, so it would never get hit.  1100 lets replies go so people can ping you.  If you don’‘t need that just erase 1100 and 10200 and 10210 will take care of you nicely.


By davidlballenger  on  12/12  at  12:35 AM

Thanks for this, it’s helped me tune up my on rule set.  However, this version seems to be missing the check-state statement that was in previous versions. Isn’‘t that required?

- David

By windexh8er  on  12/12  at  03:37 AM

They catch it back in with the established in line (520).  I personally don’‘t like doing it that way, but…  I’‘ve argued my point on that one enough.  :)

By windexh8er  on  12/12  at  03:39 AM

Ooop, read that wrong they left that as a deny.  Not sure actually if this would work the way it’s stated.

By diem  on  12/12  at  06:07 PM


None of the rules now include the ‘‘keep-state’’ or ‘‘limit’’ keywords which create the dynamic ruleset, hence there is no need to check this dynamic set with ‘‘check-state’‘.

It would however be nice to know the rationale for removing this?

By diem  on  12/12  at  06:11 PM

By the by, I really like the variable substitution features of the ruleset published here:


By reppep  on  12/12  at  07:25 PM


You’‘re right, 1000/1100 doesn’‘t make sense; I lifted that directly from the configuration Apple’s Server Admin creates, but I can’‘t think of a reason to do it that way. Next round, 1000 is for the chop!

What do you mean about a deny not working as stated? The keep-states are allows.


keep-state (500/510) implicitly includes check-state, so the preceding check-state rule was redundant and I removed it (someone suggested this in a previous comment). If there were intervening rules, having the check-state earlier might be worthwhile, but not if they’‘re adjacent.


No, dynamic rules are all handled within 500/510.

Yes, I really like variable substitution. If you write your own shell script, you can do it, too! But I’‘m not going to take on the task of writing a robust, safe, and secure firewall loading engine, so I suggested Hany add this to WaterRoof. It’s a new type of complexity, though, so I don’‘t know if he’‘ll bother.

Just note that it’s easy to re-cast these rules (or whatever you get out of "ipfw list" as a shell script to load rules, and then you get shell features like $VARIABLES.

What I <strong>really</strong> want, though, is auto-configuration of local networks, so you can allow Bonjour, printing, SLP, etc. from whatever network you’‘re in. For that, we’‘d need code with enough smarts to detect the addresses and netmasks of all active interfaces, and a trigger on network reconfiguration (I had this back in the Jaguar area—it’s probably easier to do with <code>launchd</code> now), and a preference for whether to update automatically on network reconnection.

The idea is that whenever <code>configd</code>/<code>launchd</code> notices a network change, the firewall configuration engine would generate 0 or more lines, substituting in all the local networks for $LOCAL in a template ruleset. Note that in this scenario, (un-)plugging a network cable or changing AirPort networks would implicitly flush all dynamic rules, so outstanding HTTP/HTTPS responses would be dropped.

By windexh8er  on  12/12  at  08:54 PM


Sure there are:
add 500 allow tcp from any to any out keep-state
add 510 allow udp from any to any out keep-state

So where is the check-state?

By windexh8er  on  12/12  at  09:00 PM

The reason why check-state, to me, is valuable is in this situation.  I have my check-state above my deny established which directly follows.  Now I have my keep-states below this.  What this does for me is allows my check-state (as in the config posted here) to not get lost in the mix and accidentally allow something I might otherwise not have wanted back in.  That and if my ruleset is particularly large, having the check-state at the top of the rules allows IPFW to do less work (as we parse the rules in order until we get an allow or deny).  For a workstation this is probably trivial, but I like to know where things are getting back in with regards to dynamic entries.  I can also easily log all dynamic transactions in as well using this methodology.

By reppep  on  12/12  at  09:49 PM


If there were intervening rules, I’‘d keep the check-state so it ran earlier for performance reasons (since most traffic statistically is HTTP & email responses to dynamic rules). Since the rules were adjacent, though, the only performance impact would be a negative—one more rule to process before <code>ipfw</code> gets to 520.

As far as clarity, I think that makes perfect sense for you, but less for the intended audience of this post, many of whom don’‘t yet know what check-state/keep-state do.

I don’‘t see any mention of the source rule in the dynamic entries ("ipfw -d list"), so I’‘m not too concerned with breaking that out for logging.

By windexh8er  on  12/12  at  11:06 PM


You’‘re correct with regards to your explanation (and it’s a good one).  I think if someone were to read through IPFW they would wonder where the check-state is however since the outline usually describes the check-state as a staple rule.

The source rule (i.e. check-state) never gets referenced in the dynamic entries list because that would make it confusing to see why the dynamic entry was allowing the traffic in with no apparent reference.  If you have a lot of keep-states it makes sense that the dynamic entries tell you which rule it is paired up with, but the primary check-state will still be the rule to process the transaction.

For me I’‘m more in the mindset of using IPFW on a server or as a dedicated firewall, and I’‘ve seen rulesets in excess of 70k rules which probably drives my persuasion of building rulesets slightly.  :)

By arnulf  on  12/17  at  02:33 PM

here’s yet another ipfw rule set: http://textsnippets.com/posts/show/1267

By Sicher mit OS X Leopard: Firewall einrichten | Qua  on  02/11  at  02:32 AM

[...] die Möglichkeiten zum Feintuning. Wer möchte kann sich aber richtig austoben und sein eigenes ipfw-Ruleset erstellen, denn letztendlich ist die neue Leopard Firewall nur ein graphische Oberfläche für den [...]

By nobby  on  04/15  at  12:21 AM

I tried to add pptp support for this ruleset, but despite making port 1723 available and allowing gre packeges to pass through my Mac failed to establish a connection with the VPN-gateway. Any hints on that?

By random  on  04/16  at  04:03 PM

Are implicit check-states (via keep-state) rule specific?
That is, in the absence of an explicit check-state: does
the first rule with a keep-state (call it rule N) invoke
a check-state that applies to all dynamic rules, or just
those created by rule N?

My apologies if that’s terribly worded.

By reppep  on  04/16  at  04:12 PM


keepstate applies to all dynamic rules.

By random  on  04/17  at  12:21 AM

Thanks, Pepper.

Also, I wonder if 500&510 should or could
have a "setup keep-state" rather than just
"keep-state". Perhaps that’s unnecessarily
strict for outgoing traffic.

By Andy  on  06/25  at  02:03 AM

Do not want to get posted online but you can pass on the thanks to those who assist in this group.

As a single home computer plugging into a router I often get confused as to how to set up Leopard Firewall for max security. So many rule-sets are for networks and thus complicated, or with too many rules for a simple single user.
I’‘m pretty much an average user with an unusual amount of hacking and hijinx going on trying to get into my system. I don’‘t use bonjour or sharing. I just pretty much use iTunes for internet radio, almostVPN and Secure-Tunnel.com for security at times while surfing,(it’s the principle-I don’‘t view porn or engage in subversive activities, unless now days poetry or other writings of our current state is such?), and email. I want to keep my system tight just for those services and block others. (Those guys next door are skilled and can and do get in at times.)

I have included my most recent rule-set patched out of the basic Leopard rules with a few other suggestions added.
Can anyone comment on these? (I do want to express my gratitude to all you security geeks who post on setting up the ipfw firewall in OS X and of course the WaterRoof people. They make it possible that I can actually setup and adjust my ipfw firewall and you all give the rule-sets to try out)

I wonder if I am being overly redundant with the check-state and ‘‘deny log all from any to any not verrevpath in’’ and if I have them placed correctly?
And from rule 2 to 5?
Do I need to put in rules to keep out netbios as not being on a network I don’‘t think I need it and in many firewall suggestions, as in Windows, they suggest blocking it or closing it’s ports? Or is this rule-set pretty much an air tight, hack-proof, set? 

I do suggest a series of single home rule-sets for us less
skilled at this than you who post on this site. The basic Leopard set was a great start at this. Something easy to import into WaterRoof. If each line had a basic explanation as the Basic Leopard did then people would know what to delete or change to deny. Once done it would of enormous benefit to thousands of non-networked home users and perhaps WaterRoof could include your webpage as added security sets for the single home user. 
Perhaps I will email them suggesting that.

From the Basic Leopard ipfw rule-set with a few added suggestions. How good is this?

add 01000 allow ip from any to any via lo0
add 01200 deny ip from to any in
add 01300 deny ip from any to in
add 01400 deny log ip from to any in
add 01500 deny log ip from to any in
add 01600 check-state
add 01700 deny log ip from any to any frag
add 01800 deny log tcp from any to any established in
add 01900 allow udp from any 67 to any dst-port 68 in
add 02000 deny log all from any to any not verrevpath in
add 02100 allow icmp from any to any icmptypes 3
add 02110 allow icmp from any to any icmptypes 4
add 02120 allow icmp from any to any icmptypes 8 out
add 02130 allow icmp from any to any icmptypes 0 in
add 02140 allow icmp from any to any icmptypes 11 in
add 01800 deny igmp from any to any
add 65500 allow tcp from me to any keep-state
add 65510 allow udp from me to any keep-state
add 65534 deny log ip from any to any
add 65535 allow ip from any to any

Again: Much thanks to you all who assist us home users.

I did check out MIT ipfw@http://codesnippets.joyent.com/posts/show/1267. As soon as I get my brain transplant I will try this one out. Most of us need it to be kept pretty simple.

Cheers-Andy Apple-Seed

By Juanito  on  07/02  at  04:01 AM


This is all nice but i would need a dynamic rule that would work as Fail2Ban on linux.
I’‘m a total new-bee when it comes to firewalls and computer security, but i doo lately have a lot of brute-force hackling attempts. At least my secure.log is full of failed login attempts.

I don’‘t want to ban any ip for good. Just block them for a while when 3 failed attempts has happend.

Any one able to assist someone a new-bee like me. I would prefere to keep it as simple as possible. If i need to recompile anything i will need assistance there too.

I was considering writing an AppleScript but that is not the way to go i think.

By Juanito  on  07/06  at  01:06 AM

Thank you for your reply.

I’‘ve tried to figure out this with TCP_Wrappers but as I sit on Mac OS X Leopard. I cannot find the files that this tutorial referes to ( http://www.la-samhna.de/library/brutessh.html#5 ).

Or doo I need to do some further configurations for sshd?

By cygo  on  07/06  at  06:02 PM


Just make sure the files & directories the script is going to use exist, i.e. just create them if necessary.

sudo mkdir -p path_to_dir
sudo touch path_to_file
chmod 0644 path_to_dir path_to_file

(see: man 5 hosts_access)

For an alternative btw see:

To block an IP address on the fly you may use:

sudo route -n add -host -blackhole   # block
netstat -rn | grep   # show routing table
sudo route delete   # undo blocking



By cygo  on  07/06  at  06:11 PM


Correcting ... To block an IP address on the fly you may use:

sudo route -n add -host IPNUM -blackhole   # block IPNUM
netstat -rn | grep IPNUM   # show routing table
sudo route delete IPNUM   # undo blocking

... and in /private/etc/sshd_config you may specify

MaxStartups 5

to specify the maximum number of concurrent unauthenticated connections to the SSH daemon.

(see man 5 sshd_config for further options)



By yo  on  10/12  at  04:02 PM

Hi :)
any update till now?
Please, does this set allow Skype?
What about other voip application such Voipstunt/OpenWengo?
What about audium/messenger?

I know these are silly questions but can’t find any asnwer and I’m not ready to full configure a firewall by myself.

Thanks a lot for your work



Remember my personal information

Notify me of follow-up comments?