Tables make your life easier

By this time you may be thinking that this gets awfully static and rigid. There will after all be some kinds of data which are relevant to filtering and redirection at a given time, but do not deserve to be put into a configuration file! Quite right, and PF offers mechanisms for handling these situations as well. Tables are one such feature, mainly useful as lists of IP addresses which can be manipulated without needing to reload the entire rule set, and where fast lookups are desirable. Table names are always enclosed in angle brackets, ie < >, like this:

table <clients> { 192.168.2.0/24, !192.168.2.5 }

here, the network 192.168.2.0/24 is part of the table, except the address 192.168.2.5, which is excluded using the ! operator (logical NOT). It is also possible to load tables from files where each item is on a separate line, such as the file /etc/clients

192.168.2.0/24
!192.168.2.5

which in turn is used to initialize the table in /etc/pf.conf:

table <clients> persist file "/etc/clients"

Then, for example, you can change one of our earlier rules to read

pass inet proto tcp from <clients> to any port $client_out \
         flags S/SA keep state

to manage outgoing traffic from your client computers. With this in hand, you can manipulate the table's contents live, such as

$ doas pfctl -t clients -T add 192.168.1/16

Note that this changes the in-memory copy of the table only, meaning that the change will not survive a power failure or other reboot unless you arrange to store your changes.

You might opt to maintain the on-disk copy of the table using a cron job which dumps the table content to disk at regular intervals, using a command such as pfctl -t clients -T show >/etc/clients. Alternatively, you could edit the /etc/clients file and replace the in-memory table contents with the file data:

$ doas pfctl -t clients -T replace -f /etc/clients

For operations you will be performing frequently, you will sooner or later end up writing shell scripts for tasks such as inserting or removing items or replacing table contents. The only real limitations lie in your own needs and your creativity.[1]

We will be returning to some handy uses of tables shortly, including a few programs which interact with tables in useful ways.

Notes

[1]

One improvement you could consider is rewriting the martians macro from the Section called Handling non-routable addresses from elsewhere in the Chapter called Network hygiene: Blocking, scrubbing and so on as a table