Packet Filtering with Tables

A table is a list of IPv4 and/or IPv6 addresses, much like a list. A table is faster than a list, however, and uses less memory. If you have only a few addresses, using a list is fine, but once you have more than a few, use a table.

Interestingly, you can edit tables without reloading the filter rules, and several programs use this feature to dynamically change how a server behaves. Some people load lists of malware-laden computers into a table to block those hosts, or use external programs to generate such lists. (“You’ve tried to send us four invalid emails in a row? Good-bye!”) Tables can be kept permanently in external files, or you can treat them as ephemera. It’s your choice.

Defining Tables

You can create and manipulate tables entirely with pfctl, but that’s not as common as defining the table within pf.conf. Give the table name in angle brackets, and provide the initial members delimited by commas inside braces.

table <management> {192.0.2.5, 192.0.2.8, 192.0.2.81}

In this case, the management table contains three IP addresses.

If you want to define a table that pfctl cannot change, use the const keyword. The following example defines a table for private (RFC 1918) address space. This address space has been well defined for many years, so no one should alter it.

table <private> const {10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16}

If no rules reference a table, PF drops it. This makes sense for static rules, but if you’re using anchors (discussed later this chapter), you might want to retain the table for when rules reappear. Use the persist keyword to make a table stick around even if it’s not used in a rule.

table <scumbags> persist

Some tables contain enough addresses that you wouldn’t want to list them in your configuration. For convenience, you can populate a table from a file, like this:

table <fullbogons> persist file "/etc/fullbogons.txt"

I have a script that updates the fullbogons.txt file every day. (Bogons are addresses that should never appear in the global Internet routing table.)

The bogons list includes private address space, addresses reserved for experimentation or documentation, addresses not assigned to any network, and addresses assigned to other exotic purposes. Several organizations produce and update full bogon lists. I use the bogons list at my border to weed out obvious garbage. The file looks like this:

# last updated 1352220481 (Tue Nov  6 16:48:01 2012 GMT)
0.0.0.0/8
10.0.0.0/8
14.1.96.0/19
…

You can include individual addresses, but not dotted-quad netmasks. You can use hostnames, but before pfctl feeds the rules to the kernel, it checks the IP address or addresses of the host. This means that if a host changes its IP address after you load the rules, PF will not know about the new IP address.

Using Tables

Use the table in your firewall rules exactly as you would use an address or list.

block in on egress from <fullbogons> to any

You can put multiple tables in a list.

block in on egress from {<fullbogons>, <scumbags>} to any

Yes, a list is slower than a table. But if you maintain two different tables in different ways, you probably want those tables separated. And if a list of two items triggers firewall exhaustion, you really need more hardware.

Viewing Tables

Tables have their own subset of pfctl commands. To see which tables are in the kernel, use pfctl -s Tables. (Note that Tables begins with a capital T.)

# pfctl -s Tables
fullbogons
scumbags

Why would you need to ask the kernel what tables it has? Because dynamic rules can add and remove tables, as discussed in Anchors.

If you already know the table name, and you want to view the addresses within the table, use the -t argument to specify a table name. The -T argument has several subcommands, much like -s, but is for table operations. Here’s how to examine the contents of the scumbags table:

# pfctl -t scumbags -T show
   157.166.248.10
   157.166.248.11
   157.166.249.10
   157.166.249.11

For many table operations (add, delete, replace, and test as of right now), you can add one or two -v options before the -T to increase verbosity. If you work on multiple addresses simultaneously, adding verbosity shows details of what the command did.

Searching Tables

You can eyeball a table with four entries pretty easily, but if a table has thousands of entries, you won’t want to page through it searching for an address. You could use grep(1), but that can fail because an address might be part of a network that looks completely different. (I’m sure I could write a grep expression that matches 10.0.0.0/8 if I enter 10.99.61.4, but I don’t want to try it.) You can test an address to see if it’s in a table.

# pfctl -t fullbogons -T test 192.0.2.88
1/1 addresses match.

This address appears in the fullbogons table.

If you test multiple addresses in one command, use -v or -vv before -T to see which addresses match and which don’t.

# pfctl -t scumbags -vvT test 192.0.2.88 198.51.100.90
1/2 addresses match.
M  192.0.2.88    192.0.0.0/22
198.51.100.90    nomatch

Using a single -v shows only matching addresses.

Changing Tables

One important feature of tables is that you can dynamically alter them without reloading the firewall rules. If you must add an address to a table, use -T’s add command.

# pfctl -t scumbags -T add 192.0.2.88
1/1 addresses added.

Add networks by specifying a netmask and multiple addresses in a single command.

# pfctl -t scumbags -T add 198.51.100.0/24 2001:db8::/32
2/2 addresses added.

If you add addresses to a nonexistent table, PF automatically creates the table (so now you know where that scumbags table came from).

Add all the addresses in a file to a table with the -f argument.

# pfctl -t scumbags -T add -f scumbags.txt
1/1 addresses added.

To remove addresses, use the delete command.

# pfctl -t scumbags -T delete  198.51.100.0/24
1/1 addresses deleted.

To completely remove all entries from a table, use flush.

# pfctl -t scumbags -T flush
6 addresses deleted.

If emptying the table is not enough, and you want to completely remove it from the rules, use kill.

# pfctl -t scumbags -T kill
1 table deleted.

Tables and Automation

OpenBSD includes software that can adjust tables algorithmically. In Chapter 16, I mentioned the DHCP server’s ability to assign leased, abandoned, and changed addresses to tables. You can use PF to assign different rules to each group of addresses.

Assume you have dhcpd(8) add all leased IP addresses to the leased table, abandoned addresses to the abandoned table, and changed addresses to the changed table. Hosts with properly leased addresses can access the network, but hosts with abandoned and changed addresses cannot. Here, interfaces in the office group face the local network:

table <leased> persist
table <abandoned> persist
table <changed> persist
pass in on lan from <leased> to any
block in on lan from {<abandoned>, <changed>} to any

If someone decides to configure an address from the DHCP server as a static address for their computer, they automatically lose access to the rest of the network—problem solved. Other OpenBSD software, such as spamd(8), has similar features.

At first glance, it might seem like this feature is ready for integration with other programs. It’s fairly simple to write a script that parses a log, grabs the IP addresses, and feeds those addresses to a table. Several years ago, I wrote a script to take alerts from the Snort intrusion detection system and automatically block attackers from the network. Without careful and skilled attention though, Snort generates many false positives. My autoblocking script very effectively created a denial-of-service attack against my own development team.

Be careful with automatically feeding PF tables to block traffic. It’s very easy to harm desirable connectivity.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.179.85