I'm just starting my research into pf, but I have quite a bit of experience with Linux iptables. With iptables the ruleset is a first-match design. Upon finding a packet that matches a rule the list is exited and the packet is acted upon. From my reading with pf it appears to be the opposite.

I'm wondering if anyone can explain the idea behind this--it seems backwards to me. Or has anyone else gone through the transition between one design and the other and has any advice on how to change my way of thinking?

Perhaps I should post my pf.conf here for some critique and improvement. To give you an idea of what I'm working with here I have seven jails on the system, each providing a service. Everything from mail, dns, dhcp, monitoring (nagios), git, etc. I've added comments for the sake of this thread regarding what I'm attempting to do with each set of rules. Perhaps I can get some feedback on the accuracy and efficiency of this ruleset:

# SSH
# $claire and $rebel should be available from anywhere.
# $parkman should be available from anywhere in the LAN
# $mohinder should only be accessible from $parkman
pass in on $interface proto tcp from any to $claire port = 22222 keep state
pass in on $interface proto tcp from any to $rebel port = 2200 keep state
pass in on $interface proto tcp from <secure> to $parkman port = 22 keep state
pass in on $interface proto tcp from $parkman to $mohinder port = 22 keep state

# MAIL
# smtp/imap(s) open to anyone
pass in on $interface proto tcp from any to $mail port = 25 keep state
pass in on $interface proto tcp from any to $mail port = 143 keep state
pass in on $interface proto tcp from any to $mail port = 993 keep state

# allow mail full connectivity to itself
pass in on $interface proto { tcp, udp } from $mail to $mail keep state

# HTTPD
# https available for webmail to anyone, $angela http only available in LAN
pass in on $interface proto tcp from any to $mail port = 443 keep state
pass in on $interface proto tcp from <secure> to $angela port = 80 keep state

# DNS
# allow tcp/udp to $molly for DNS from anyone
pass in on $interface proto { tcp, udp } from any to $molly port = 53 keep state

# DHCP
# do I need this if $molly is the DHCP server? or is it covered by the outbound?
pass in on $interface proto {tcp, udp } from <secure> to $molly port = 67 keep state

(yes my Jails are named after "Heroes" characters. I have another server + jails all named after BSG characters if that is any consolation)

You also should use flags S/SA keep state for TCP traffic to make sure that state will be created on the first TCP packet of the three-way TCP handshake. The reason is explained in the "Filter statefully" section of http://undeadly.org/cgi?action=artic...20060927091645.

__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump