Changes in pf: Packet Filtering
Pages: 1, 2, 3, 4, 5, 6
Which interface (on), IP address (from,
to), and port (port) combination should be
used with NAT rules?
When you don't use NAT rules, it is fairly easy to decide which interface/IP address/port ought to be used for in a filtering rule. For example, if you want to limit access to port 80 on the external interface and only let TCP packets in, you'd use something like this:
pass in quick on $ext_if proto tcp from any to $ext_ad port 80
Things are different when you add NAT rules and additional subnets.
Then a single block or pass rule might not
be enough to properly structure the flow of traffic through the
firewall. In such cases, always remember that packets
redirected to another port/interface have to be filtered on the target
port/interface. For example, the following rules redirect traffic
from the external interface port 80 to a DMZ HTTP server port
8080:
ext_if = "ne1"
ext_ad = "x.x.x.x/32"
dmz_www_ad = "192.168.2.3/32"
rdr_www_protos = "{tcp}"
rdr_www_port = "8080"
rdr on $ext_if proto $rdr_www_protos from any \
to $ext_ad port www -> $dmz_www_ad port $rdr_www_port
If you want to block all incoming connections except connections to port 80 on the external interface (which are redirected to port 8080 on the DMZ HTTP server), use:
block in on $ext_if all
pass in on $ext_if inet proto tcp from any to $dmz_www_ad port 8080
The pass rule uses the DMZ HTTP host address for the
destination IP address. The same goes for the destination
port (8080 instead 80). If you used the IP address of the external
interface and port 80, you'd never see any packets passed to the DMZ
HTTP server. Similarly, if you wanted to block a redirected packet,
you'd need to write a rule that matched the destination IP
address/port after redirection.
After a packet is passed on the external interface, it may have to pass another test on the DMZ interface. This is optional, but it is prudent to filter traffic going in and out of the DMZ. For example, you might want to block all external traffic except HTTP going into the DMZ segment. This is accomplished with these rules:
block out on $dmz_if all
pass out on $dmz_if inet proto tcp from any to $dmz_www_ad port 8080
Note that these rules are for packets leaving
(out) the DMZ interface. Why is that? You need to
remember that all rules are written relative to the firewall; a packet
sent from the outside first matches in rules on the
external interface, then it matches out rules on the DMZ
interface, and then it reaches the HTTP server. A packet sent from
the DMZ HTTP server to the outside matches in rules on
the DMZ interface, out rules on the external interface,
and then it reaches some external host.
The out rules shown earlier will also match packets
sent from the private network segment. Such packets match
in rules on the private interface and then the
out rules on the DMZ interface.
Do you want to bypass the routing table or duplicate packets
(fastroute, route-to, dup-to)?
Ordinarily, packets examined by pf(4)
are routed according to the entries in the firewall's routing table,
which should be enough in most cases. However, there might be times
when you will want to bypass the routing table or to duplicate packets
for intrusion detection or logging purposes. The following three
keywords allow us to influence packet routing:
fastroute: use the routing tableroute-to: bypass the routing table and route the packet through the interface whose name must be given after theroute-tokeyword. The name of the interface may be followed by the IP address of the host that should receive packets, when the IP address is used. The name and the address must be enclosed in parentheses, as in:pass in on $ext_if route-to ($log_if $log_ad) all pass in on $ext_if route-to $log_if alldup-to: create a copy of the matching packet, bypass the routing table and route the copied packet through the interface whose name must be given after thedup-tokeyword. The name of the interface may be followed by the IP address of the host that is supposed to receive the copies, when the IP address is used. The name and the address must be enclosed in parentheses. The original packet is routed using entries in the routing table.
The dup-to keyword is very useful for setting up a
separate packet logging or intrusion detection system host. Simply
add this rule to /etc/pf.conf on the firewall:
pass in on $ext_if dup-to ($log_if $log_ad) all
Then run pf(4)
on the logging host with a the following rule:
block in log on $ext_if all
If you want to tune logging parameters, read this and this.
Letting another host take care of logging or analysis of packets is a good thing, because it moves the additional load placed on the firewall's resources to another host. It makes logging setups like those described in one of my earlier articles unnecessary, while making the whole process of logging simpler and more stable. Of course, to create such setup you will need another machine and an additional network interface on the firewall (it's best to put the logging/analysis machine on a separate segment). In any case, if you plan to log traffic, read this, this, and this.
Unlike all other keywords that can be followed by some value,
dup-to and route-to do not allow us to
specify more than one interface or interface/address combination.
Which IP addressing family will be filtered (inet,
inet6)?
pf(4)
can filter packets with IPv4 (inet) and IPv6 (inet6) addresses. You
select the addressing family with the inet (IPv4) or
inet6 (IPv6) keywords. If you plan on dealing with IPv4
traffic only, add these rules for every interface on the firewall:
block in quick inet6 all
block out quick inet6 all