Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Building Firewalls With OpenBSD And PF, 2nd Edition (2003)

.pdf
Скачиваний:
39
Добавлен:
17.08.2013
Размер:
2.74 Mб
Скачать

Section 5.3: Tables (table)

107

 

 

rdr on $ext_if proto tcp from any to $ext_ad port 80 \ -> $dmz_ad port 8080

For simplicity and security, macros are not expanded recursively, so the following notation is not legal:

ext_if = "ne0" dmz_if = "ne1" prv_if = "ne3"

all_if = "{$ext_if, $dmz_if, $prv_if}"

A proper deŒnition of all_if would be:

all_if = "{ne0, ne1, ne2}"

It is possible to redeŒne a macro while pf(4) is running, without reloading the whole ruleset, as it is explained in Chapter 16, Firewall Management.

5.3 Tables (table)

Tables are collections of IP addresses. They are similar to groups of host and network addresses listed in braces, but more efŒcient. Another difference is the fact that you can add or remove addresses to and from a table at will. Also, macros can store other information or names, while tables are used solely for addresses. Their syntax is simple, each table deŒnition starts with the table keyword followed by table name (in <>), table options (optional), and a list of addresses in braces:

table <DMZ> persist {192.168.34.10/24}

table <myLANs> persist {10.0.200.1/24, 10.0.12.2/24}

References to tables use their names, e.g.:

block in on ne0 from any to <myLANs> port 25 pass in on ne0 from any to <DMZ> port 25

It is OK to group tables in braces:

block in on ne0 from any to {<DMZ>, <myLANs>} port 25

108

Chapter 5: /etc/pf.conf

 

 

It is also OK to deŒne an empty table:

table <spammers> persist

Why deŒne an empty table? Because it is possible to load, remove and modify tables with pfctl(8) while pf(4) is running, without the need to reload the whole ruleset, and without •ushing the ruleset. This feature is used in dynamic rulesets described in Chapter 9, Dynamic Rulesets.

Table options have the following meaning:

ƒconst Š once the table has been created, it cannot be modiŒed or removed, you will need to boot OpenBSD into single-user mode and do the changes by hand (see Chapter 4, ConŒguring OpenBSD for explanation of securelevels). This option is handy when you want another layer of protection, but makes table management a pain.

ƒpersist Š table won't be removed when there are no rules that refer to it. This prevents automatic removal of tables after rules that refer to them are •ushed from memory and lets you deŒne an empty table that you will populate later on. You can still modify that table with pfctl(8) (see Chapter 16, Firewall Management).

Tables can be used in place of lists of addresses and macros deŒning lists of addresses. For example, the following constructs are similar in effect, but tables are evaluated faster (the gains in speed will be more noticeable for longer lists of addresses):

# address group, and ...

myLANs = "{10.0.200.1/24, 10.0.12.2/24}" pass out on ne1 from $myLANs to any

# ... the equivalent table

table <myLANs> persist {10.0.200.1/24, 10.0.12.2/24} pass out on ne1 from <myLANs> to any

If, instead of listing addresses in brackets, you'd like to have them automatically loaded by pf(4) from one or more Œles, use the file keyword:

table <myLANs> persist file "/etc/spammers" \ file "/etc/openrelays" \ file "/root/scanners" \

file "/root/idiots"

Addresses in these Œles must be given one per line, e.g.:

Section 5.4: Anchors (anchor, nat-anchor, rdr-anchor, binat-anchor)

109

 

 

192.168.255.1

192.168.255.2

192.168.255.3

Any line that begin with # will be ignored. It is OK to use hostnames, their names will be resolved into IP addresses when pfctl(8) loads them into memory, e.g (it is possible that a single hostname will be resolved into more than one IP address, if that's what DNS reports):

192.168.255.1

www.example.com

mail.example.com

Tables cannot be used in rdr rule's redirect target addresses (except for round-robin pools), although you can still use them as source or destination addresses in these rules (see Chapter 7, Packet Redirection). Also, they cannot be used in the routing options of Œltering rules (see Chapter 8,

Packet Filtering).

5.4 Anchors (anchor, nat-anchor, rdr-anchor, binat-anchor)

Anchors are used to mark points at which you can inject additional rules into the main ruleset that's already loaded into memory. Like tables, these rulesets can be modiŒed while pf(4) is running. Each anchor can contain several separate sections, each with it's own name, independent of others. The names of these sections do not have to be pre-deŒned in the main ruleset. When you deŒne more than one section in a single anchor, they are evaluated in the alphabetic order.

Only the main ruleset can contain anchors. The names of anchors ought to be unique and cannot be reserved names used in pf(4) rules. There are four types of anchors, used to load four different kinds of rules:

ƒnat-anchor abc Š used to mark the place that you can add more nat rules to. The name of the anchor is abc.

ƒrdr-anchor abc Š used to mark the place that you can add more rdr rules to. The name of the anchor is abc.

ƒbinat-anchor abc Š used to mark the place that you can add more binat rules to. The name of the anchor is abc.

110

Chapter 5: /etc/pf.conf

 

 

ƒanchor abc Š used to mark the place that you can add more Œlter rules to. The name of the anchor is abc.

You will Œnd more information about anchors in Chapter 9, Dynamic Rulesets; Chapter 12, Using authpf, and Chapter 16, Firewall Management.

5.5 Common Components Found in pf Rules

Every pf(4) rule is made of several parts, some obligatory and some optional. We will now discuss common parts found in many pf(4) rules. Those parts that are more speciŒc parts are discussed in other chapters, where it is appropriate.

5.5.1 Directions (in, out)

The direction keywords (in, out) match inbound (in) and outbound (out) packets. Users new to pf(4) often get this wrong and we'll be returning to this subject in the following chapters.

The key to proper use of these keywords is remembering that the direction the packets are traveling in is relative to the Œrewall machine. Imagine that you are sitting inside the Œrewall and you should have no problem deciding which packets are inbound and which ones are outbound. It is not OK to group both keyword on the same line, as in:

block in all block out all

cannot be replaced with:

block {in, out} all

5.5.2 Interfaces (on)

Every pf(4) rule needs to be assigned to a speciŒc interface. The name of the interface should be listed after the on keyword, as in:

block in on rl0 all

It is OK to group several interface names on the same line, as in:

Section 5.5: Common Components Found in pf Rules

111

 

 

block in on {rl0, rl1, ne0} all

If you are unsure what interfaces are available on your machine use the following commands:

$ dmesg

$ ifconfig -a

When dmesg(8) shows interfaces missing from the ifconŒg(8) output, you need to conŒgure those that are missing. To do that, consult Chapter 4, ConŒguring OpenBSD. If pfctl(8) complains about the interface name, check the spelling, then check if that interface is properly conŒgured, when you run ifconŒg(8), as in:

$ ifconfig rl0

And if you do not see UP in the flags Œeld, then the interface is not initiated at system startup. It may be missing its /etc/hostname.* Œle or there may be a problem with the hardware or kernel conŒguration. See if Chapter 4, ConŒguring OpenBSD will help. When the status Œeld is not active, you need to check if the cables are connected. You will Œnd additional help on that subject in Chapter 3, Installing OpenBSD and Chapter 4, ConŒguring OpenBSD.

5.5.3 Address Families (inet, inet6)

Pf(4) can match packets with IPv4 and IPv6 addresses. When you want to match either of these address families, use one (or both) of these keywords: inet (IPv4), inet6 (IPv6). The use of these keywords is optional. A lot of the area covered by the address families is also covered by constructs used to deŒne addresses of hosts and networks (address notation, tables). Not all rules apply to both address families, but that's something that will be brought to your attention later in this book.

5.5.4 Protocols (proto)

It is often necessary to block or pass certain protocols. This can be achieved with the proto keyword followed by the protocol name or the number of the chosen protocol. The list of protocol names and numbers is stored in /etc/protocols. For example, to block UDP packets on the external interface, you'd use:

112

Chapter 5: /etc/pf.conf

 

 

block in on ne0 proto udp all

It is also OK to group protocols:

block in on ne0 proto {udp, tcp} all

Note that you cannot use protocol ip (number 0), pfctl(8) won't allow it. The latest list of protocols and their numbers can be found at:

http://www.iana.org/assignments/protocol-numbers

(IANA protocols)

5.5.5 Addresses (from, to, any, all, no-route)

One of the most important sections in every pf(4) rule are addresses. Therefore, it is a good idea to spend now some time discussing address notation:

ƒIPv4 addresses Š Every IPv4 address has a length of 32 bits. It is written as a group of four integers joined with dots, e.g. 10.0.3.1 to make it more convenient to remember and write. Every address is divided into two parts: network and host. The relationship between these two parts is inversely proportional: the shorter the network address the more hosts on the same network can be connected without routing, or the more subnets it can be divided into. How do you know which bits in the address belong to the network part and which belong to the host part? Use a netmask. For example, if you see something like 10.0.3.7/24 it is a notation describing a network whose address is 10.0.3 and which has 256 unique host IPv4 addresses. This notation is often called Classless Inter-Domain Routing (CIDR). The /24 sufŒx is the netmask and contains the number of bits in the address that describe its network part, so in this example we know that the network part of 10.0.3.7 is made of the Œrst 24 bits and the host addresses are created using the remaining 8 bits. The Œrst 24 bits in the example address do not change, so there is another way to think of netmasks as numbers that deŒne how many initial bits in an IPv4 address remain unmodiŒed.

The number of hosts that can have addresses on a given network is calculated using the following formula:

hosts = 232-netmask - 2

Section 5.5: Common Components Found in pf Rules

113

 

 

For our example network address, the result is:

hosts = 232-24 - 2 = 254

The netmask can be any integer between 0 and 32, although some of its values have a special meaning: 0 is a shortcut for all networks, not very useful in practical applications; 31 is a funny network, because it has only two addresses, but cannot contain any real hosts, because two addresses on each network are always reserved; Œnally, 32 is an address of a single host. Hosts with addresses on the network with the same netmask are said to belong to the same: subnet, network segment, or broadcast domain

(because packets sent to the broadcast address are received by all of these hosts).

ƒIPv6 addresses Š The IPv6 addresses have a length of 128 bits and use a slightly different notation. First of all, because the addresses are longer, they use hex notation instead of decimal notation and are divided into 8 pairs separated with colons instead of dots, e.g.:

FEC0:A702:0000:0000:0000:448A:0000:0005

As you can see, even with this notation, an IPv6 address is quite long. However, there is a trick that makes it possible to compress parts with 0s, as in:

FEC0:A702::448A:0000:0005

The :: symbol that replaces 0s may only be use once to avoid ambiguity. Other than that, IPv6 addresses work just like IPv4 addresses, and they too use netmasks e.g.:

FEC0:A702::448A:0000:0005/64

The formula used to compute the number of hosts on a network is a bit different for IPv6 addresses, because the netmask can be longer (0‰128 bits).

hosts = 2128-netmask - 2

The above information about IPv6 addresses ought to be enough to get you started, but if you crave more, refer to [RFC 2373].

114

Chapter 5: /etc/pf.conf

 

 

Both types of addresses can be grouped in braces or listed in tables (both constructs are described in this chapter). Because pf(4) can check the source and the destination addresses of packets it looks at, there are special keywords that you put in front of addresses to tell pf(4) which ones are source (from) and which ones are destination (to), e.g.:

# match packets with source address 10.0.1.3/24 and

#

destination address 192.168.23.4/18

... from 10.0.1.3/24 to 192.168.23.4/18 ...

There are also two shortcuts for telling pf(4) to match all addresses:

# match packets with any source address and destination

#

address 192.168.23.4/18

 

... from any to 192.168.23.4/18 ...

# match packets with source address 10.0.1.3/24 and any

#

destination address

 

... from 10.0.1.3/24 to any ...

# match packets with and source and any destination

#

addresses

 

... from any to any ...

The last example can be written in an even shorter form:

... all ...

Another shortcut is the no-route keyword, which matches addresses, which have no routes deŒned at the time they are matched. This particular keyword won't be of much use if your Œrewall has a default route deŒned (it won't match any packets). Its usefulness will be visible on Œnely-tuned Œltering bridges that control packet •ow between network segments that do not need to communicate with the outside world directly and don't need a catch-all default route. A sample rule using no-route could look like this:

#block all outbound packets with destination IP addresses for

#which no routes exist.

block out on ne1 from any to no-route

It doesn't matter if you are using IPv4 or IPv6 addresses, the syntax stays the same.

Section 5.5: Common Components Found in pf Rules

115

 

 

5.5.6 Dynamic Assignment of Addresses (hostname, (if), :broadcast, :network)

When you use a PPP device like the good old analog or DSL modem, the IP address of the interface this device is connected to will be assigned via DHCP in a more or less random way. Since there is no way of knowing which address will be assigned when you log on, this creates an interesting problem. Unless OpenBSD is conŒgured as an invisible Œltering bridge (see Chapter 4, ConŒguring OpenBSD, pf(4) must know the address of each interface mentioned in its ruleset. If it is missing, the ruleset won't load. Fortunately, there is a way out of this with the (interface) notation which tells pf(4) to adjust the address in parentheses whenever the address of the interface changes. So, instead of writing:

#redirect all packets sent to port 80 on the external

#interface to the internal HTTP server listening on port 8080 ext_if = "tun0"

ext_ad = "10.3.4.6"

rdr on $ext_if from any to $ext_ad port 80 \ -> 192.168.55.13 port 8080

you could write:

#redirect all packets sent to port 80 on the external

#interface to the internal HTTP server listening on port 8080 ext_if = "tun0"

rdr on $ext_if from any to ($ext_if) port 80 \ -> 192.168.55.13 port 8080

You could also write the name of the interface without parentheses, e.g.:

rdr on $ext_if from any to $ext_if port 80 \ -> 192.168.55.13 port 8080

OpenBSD 3.4 introduced an interesting extension to this notation in the form of the :broadcast and :network keywords, which expand into the broadcast addresses assigned to the given interface, or the addresses of networks assigned to the given interface:

block out on ne1 from any to ne1:broadcast pass in on ne1 from ne1:networks to any

116

Chapter 5: /etc/pf.conf

 

 

Note that if you use the expanded interface notation, you should not put interface name and modiŒers inside parentheses. For example, the following rule is not correct:

pass in on ne1 from (ne1:networks) to any

Always check what these rules will expand into with:

# sudo pfctl -f testfile ; sudo pfctl -s rules

Another trick of similar nature is to use the name of the host. For example, if your Œrewall host's name is fw0, you could write the following rule blocking access to the host via interface ne1:

block in on ne1 from any to fw0

Interface names and hostname are not interchangeable. To see that they can result in different sets of rules consider the following rules:

#(replace ne1 and fw0 with the name of the interface and host

#used in your machine)

#rule 1:

pass in on ne1 from any to fw0

# rule 2

pass in on ne1 from any to ne1

Load rule 1 and check how it was translated with:

# sudo pfctl -f testfile ; sudo pfctl -s rules

Then, replace rule 1 with rule 2 and do the same. If you see rules that you did not expect (like IPv6 rules), write rules that block them. To make the ruleset more efŒcient, use the quick keyword in those blocking rules, see Chapter 8, Packet Filtering.

5.5.7 Ports (port)

An even Œner degree of control than source or destination address matching can be achieved with port matching. Ports are used to connect to various