A common convention in PF rulesets is to define a macro for each network interface. If a network card ever needs to be replaced with one that uses a different driver, the macro can be updated and the filter rules will function as before. Another benefit is when installing the same ruleset on multiple machines. Certain machines may have different network cards in them, and using macros to define the network interfaces allows the rulesets to be installed with minimal editing. Using macros to define information in a ruleset that is subject to change, such as port numbers, IP addresses, and interface names, is recommended practice.
Another common convention is using macros to define IP addresses and network blocks. This can greatly reduce the maintenance of a ruleset when IP addresses change.# define macros for each network interface IntIF = "dc0" ExtIF = "fxp0" DmzIF = "fxp1"
If the internal network ever expanded or was renumbered into a different IP block, the macro can be updated:# define our networks IntNet = "192.168.0.0/24" ExtAdd = "192.0.2.4" DmzNet = "10.0.0.0/24"
IntNet = "{ 192.168.0.0/24, 192.168.1.0/24 }"Once the ruleset is reloaded, everything will work as before.
Now look at the following simplification:block in quick on tl0 inet from 127.0.0.0/8 to any block in quick on tl0 inet from 192.168.0.0/16 to any block in quick on tl0 inet from 172.16.0.0/12 to any block in quick on tl0 inet from 10.0.0.0/8 to any block out quick on tl0 inet from any to 127.0.0.0/8 block out quick on tl0 inet from any to 192.168.0.0/16 block out quick on tl0 inet from any to 172.16.0.0/12 block out quick on tl0 inet from any to 10.0.0.0/8
The ruleset has been reduced from eight lines down to two. Things get even better when macros are used in conjunction with a list:block in quick on tl0 inet from { 127.0.0.0/8, 192.168.0.0/16, \ 172.16.0.0/12, 10.0.0.0/8 } to any block out quick on tl0 inet from any to { 127.0.0.0/8, \ 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
Note that macros and lists simplify the pf.conf file, but the lines are actually expanded by pfctl(8) into multiple rules. So, the above example actually expands to the following rules:NoRouteIPs = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }" ExtIF = "tl0" block in quick on $ExtIF from $NoRouteIPs to any block out quick on $ExtIF from any to $NoRouteIPs
As you can see, the PF expansion is purely a convenience for the writer and maintainer of the pf.conf file, not an actual simplification of the rules processed by pf(4).block in quick on tl0 inet from 127.0.0.0/8 to any block in quick on tl0 inet from 192.168.0.0/16 to any block in quick on tl0 inet from 172.16.0.0/12 to any block in quick on tl0 inet from 10.0.0.0/8 to any block out quick on tl0 inet from any to 10.0.0.0/8 block out quick on tl0 inet from any to 172.16.0.0/12 block out quick on tl0 inet from any to 192.168.0.0/16 block out quick on tl0 inet from any to 127.0.0.0/8
Macros can be used to define more than just addresses and ports; they can be used anywhere in a PF rules file:
Expands to:pre = "pass in quick on ep0 inet proto tcp from " post = "to any port { 80, 6667 }" $pre 198.51.100.80 $post $pre 203.0.113.79 $post $pre 203.0.113.178 $post
pass in quick on ep0 inet proto tcp from 198.51.100.80 to any port = 80 pass in quick on ep0 inet proto tcp from 198.51.100.80 to any port = 6667 pass in quick on ep0 inet proto tcp from 203.0.113.79 to any port = 80 pass in quick on ep0 inet proto tcp from 203.0.113.79 to any port = 6667 pass in quick on ep0 inet proto tcp from 203.0.113.178 to any port = 80 pass in quick on ep0 inet proto tcp from 203.0.113.178 to any port = 6667
This can now be reduced to:block in all block out all
When no direction is specified, PF will assume the rule applies to packets moving in both directions.block
Similarly, the "from any to any" and "all" clauses can be left out of a rule, for example:
can be simplified as:block in on rl0 all pass in quick log on rl0 proto tcp from any to any port 22
The first rule blocks all incoming packets from anywhere to anywhere on rl0, and the second rule passes in TCP traffic on rl0 to port 22.block in on rl0 pass in quick log on rl0 proto tcp to port 22 keep state
This can be simplified as:block in all block return-rst in proto tcp all block return-icmp in proto udp all block out all block return-rst out proto tcp all block return-icmp out proto udp all
When PF sees the return keyword, it's smart enough to send the proper response, or no response at all, depending on the protocol of the packet being blocked.block return
can also be written as:pass in log quick on rl0 proto tcp to port 22 flags S/SA keep state queue ssh label ssh
Other, similar variations will also work.pass in quick log on rl0 proto tcp to port 22 queue ssh keep state label ssh flags S/SA