>>In pf nat rules also the first match wins >> >>__but__ >> >>in pf filter rules the __last__ match wins. >> >>In fact that is the one thing I don't like in pf, but to have a "first >>match win" you can use the magic word quick in all your pass and block >>rules. (e.g "pass in quick")
>And thereby end up with yards of quick rules that can catch you later. Ah, but the matching engine doesn't have to traverse the whole rule list that way. Unless pf is doing something really tricky, every packet will have to traverse every firewall rule without use of quicks. On a complicated, busy firewall setup, this might have a noticable performance impact. >You should think of it this way: >Default security is best with block everything and then pass what >selected few things you need. >So: >block all >pass in on $int_if from $safe1 to $ok2 keep state >pass in on $ext_if from any to $ext_if port ssh keep state I agree, with the added use of quick on each of the pass rules. In fact, you can probably use quick on virtually every rule other than that default without any loss of expressiveness. Thanks to negations, having two different precedences is largely unnecessary (previously you'd have to pass nonquick for some set of packets, then block again for some subset to get the same effect as a negation). It's probably not necessary, and I may offend purists by my performance optimizations, but I actually have this as my first rule: pass quick on lo0 I also find it useful to use the following rule right after "default deny": block return on $lan_if I do have some questions about pf though. How come you can only modify source IP/ports outbound, and destination IP/ports inbound? Why not the other two alternatives? I also don't see why NAT should necessarily occur before the filtering rules. It makes more sense to my intuition to have the order in the pf.conf control the order of operations, but I admit implementation issues may make this less elegant. Also, I find supporting $macros in pf.conf a little crufty. Why not just do something like this: #! /bin/sh lan_if=xl1 wan_if=ex0 pfctl -f /dev/stdin <<EOM pass quick on lo0 block all pass quick in on $lan_if all keep state pass in quick on $wan_if from any to $wan_if proto tcp port = 22 keep state [...] EOM That way, you have the full expressive power of the shell, including command substitution, arithmetic substitution, variable substitution, trimming suffixes and prefixes, and all kinds of shell magic. It doesn't replace lists or tables of course. But you can easily do conditional inclusion of rules, and that's useful for cases like DHCP. The interface comes up with IP 0.0.0.0/0, which I think means it will accept any packet as destined for this interface, no matter what the destination IP. I only allow in replies from my ISP's DHCP server during this stage, and only those destined to 255.255.255.255 (I don't want rogue servers answering my DHCP requests, which are sent via local broadcast (hence to all my neighbors). It was also pretty useful before things supported the (interface) notation for looking up IP addresses each time. That having been said, pf is way cool. Keep up the good work. -- http://www.lightconsulting.com/~travis/ -><- GPG fingerprint: 50A1 15C5 A9DE 23B9 ED98 C93E 38E9 204A 94C2 641B