Changes in pf: Packet FilteringIn previous installments of this series (NAT with pf and More NAT) we examined macros, options, scrub rules, and NAT rules. This time we'll look at packet filtering rules, which kick in after packets have been scrubbed and (optionally) redirected to another IP address or port with NAT rules.
Once you get your scrub and NAT rules sorted, it's time to add some packet filtering rules to the mix. There are three kinds of rules:
block—block matching packetsantispoof—a special case of
block rulespass—let matching packets throughPackets are matched against filtering rules after scrubbing and NAT'ing have been done. When you design your ruleset and plan to use NAT or port/interface redirection, remember to design your filtering rules to match packets after NAT'ing and redirection, or you will waste a lot of time debugging the ruleset and scratching your head wondering what's wrong with your design and its implementation. We will return to this subject later in this article, but first we need to focus on the packet filtering grammar.
|
Related Reading
Essential System Administration |
Packet filtering rules are written using a specialized grammar, similar to that of NAT rules, but capable of describing much finer detail required to implement detailed filtering rules. The large number of keywords and their possible configurations make them a bit overwhelming for a beginner, but there is a method behind this madness. The following guide should make them easier to digest. I divided it into small sections each describing one part of a packet filtering rule, following the order in which they are described in pf.conf(5).
Hint: if you have trouble making sense of the
syntax describing those rules in pf.conf(5),
remember that the items listed in square brackets ([...])
are optional, while the items separated with a vertical bar
(|) are alternative values. Items in double-quotes
("...") are meant to be typed literally, but without the
double quotes.
block, pass)?The block or pass keywords tell pf(4)
what to do with the packet that matches all conditions listed after
either block or pass (we are leaving the
antispoof keyword aside for a while, but think of it as a
special case of block rules). These keywords are
required and either of them must be used at the
beginning of every filtering rule. To block all incoming and outgoing
packets, use:
block in all
block out all
The opposite would be pass rules that let all traffic
in and out of the firewall:
pass in all
pass out all
With such rules in place, all traffic can move freely in or out of
the firewall. Both policies are too general for practical use, but
they are handy for explaining the basics. As a general rule, the more
conditions you list after pass or block the
more specific the rule will be. Conversely the less conditions you
use, the more general the rule will be. As you will see later on, I
always advise that you start your packet filtering section with a set
of block {in, out} all rules. It is safer to block all
traffic first and only open those routes that are absolutely necessary
later. Apart from being a safer way to write pf(4)
rulesets, such approach greatly simplifies the ruleset, which is good,
because simple rulesets are easier to debug.
return-icmp,
return-rst) after blocking a packet?A plain block rule drops all matching packets without
sending any kind of notification back to the host that tried to
initiate the connection. Silently dropping all unwanted packets is
good security practice, because the firewall does not have to waste
its own resources on sending redundant information, and because
"silent" firewalls are harder to scan and fingerprint. (Broadly
speaking, scanning is the process of looking for open ports
that the attacker could use to break into your firewall or network,
while fingerprinting is the process of identifying the
operating system or other software running on the scanned host.)
However, as with all general rules, there are exceptions. One of
these is sending the ICMP destination-unreachable message
to hosts trying to connect to port 113 (auth). It is
quite safe to do so and is considered to be good net citizenship.
Returning that message helps some services, such as
sendmail, complete connections faster, without waiting
for connections to port 113 to time out.
This can be achieved with a rule that begins with:
block in all
block return-icmp in on $ext_if from any to $ext_ad port auth quick
pass in on $ext_if from any to $ext_ad port smtp quick
You can add the ICMP message number or name after the
return-icmp keyword, although it is optional and only
required in special cases. For more information about ICMP, read
RFC792 [Postel
1981]; if you want to learn how it works in practice, and how it is
implemented, especially on BSD systems, consult [Stevens,
Wright 1994].
Another possibility is to answer unwanted packets with the TCP RST
message. This is achieved with the return-rst keyword,
which can be followed by an integer number defining the TTL (time to
live) value for the returned packet as in:
block return-rst in quick on $ext_if from any to $ext_ad
or
block return-rst 100 quick in on $ext_if from any to $ext_ad port
The return-rst and return-icmp keywords
are optional.
|
in, out)?The next required keyword that appears after
either the block (followed by optional
reset-icmp or reset-rst keywords) or the
pass keyword is the direction keyword. There are two
direction keywords you can use: in or out.
They are known to cause some confusion, especially when the firewall
is equipped with more than one network interface, and when NAT rules
are used along with filtering rules.
The key to understanding when a packet matches either the
in or the out rule is remembering that these
directions are relative to the firewall itself. Iif a packet is sent
from an external host to the firewall, it matches the in
rule on the firewall's external interface; when it is sent from the
firewall itself, it matches the out on the external
interface. Similarly, packets sent from internal hosts to the
firewall and destined to external host will match in
rules on the interface connecting your private network segment to the
firewall and out rules on the firewall's external
interface.
log, log-all)?You can tell pf(4)
to log packets matching certain rules to the pflog0(4)
interface. From there, they are picked up by pflogd(8)
and stored in rotated
log files located in /var/log.
To start packet logging, use the log or the
log-all keywords. The difference between them lies in
the way they work with rules that contain either keep
state or modulate state rules (more on these
later). log logs only the state-making packets, while
log-all logs all packets. If you use stateful filtering
and want to capture all packets that match the log rule,
use log-all, otherwise, use log.
If you want to log all traffic on all interfaces, add either the
log or log-all keywords to the rules that
cover most traffic. For example, to log all traffic entering and
leaving the firewall on the external interface, use these rules:
block in log on $ext_if
block out log on $ext_if
Similar rules should be added to sections describing packet
filtering policy for other interfaces on the firewall. If you would
rather log only incoming HTTP traffic, add the log
keyword to the rule that lets HTTP packets through.
Although I wrote
earlier that the firewall need not be the latest, fastest machine
you can get, the more traffic you log and the heavier the traffic that
passes through the firewall's interface, the faster the hardware you
use the better. This is especially true for the disks that must store
the data. As you will learn later in this article, when I discuss the
dup-to keyword, you can duplicate packets and send them
to a different interface, where a dedicated packet logging machine can
sit, listen, store, and analyze traffic. If you use
dup-to for logging, then log, and
log-all are redundant.
quick)?Unlike NAT (nat, binat, rdr)
rules, which are processed in the "first matching rule wins" fashion,
packet filtering is done in the "last matching rule wins" way. While
it is possible to carefully structure your ruleset in a way that
avoids letting unwanted packets through, it is more convenient and
simpler to put rules that you want to process faster (like very
specific blocking rules) at the top of the packet filtering section of
the ruleset and add the quick keyword to such rules.
Whenever this keyword is used, pf(4)
will execute the matching rule and will not try to match the packet
against the rest of the ruleset. This saves some processing time,
which quickly adds up on a busy link, so I use this keyword
frequently.
The quick keyword is added after the log
or log-all keywords, or, in the absence of these
keywords, after the in or out direction
keywords:
pass in log-all quick on $ext_if proto tcp from any to $ext_ad port 80
or
pass in quick on $ext_if proto tcp from any to $ext_ad port 80
Typical applications of quick rules include quickly
blocking addresses of problematic sites and blocking packets with
spoofed addresses.
on)?While the packet filtering rules grammar allows us to write general
rules that apply to all interfaces, we can seldom write a good ruleset
without adding rules for specific interfaces. The name of the
interface is given after the on keyword that appears
after the quick keyword. The following examples show a
few possible variations of keywords that appear before
on:
block in on $ext_if
block in log-all on $ext_if
block in log-all quick on $ext_if
Hint: If you forgot the name of the interface,
check the output of dmesg | less. If OpenBSD is not
recognizing your network interface, read this article for kernel
modification tips. Note that if you are using a device connected to
the serial interface (like a modem), such device may not be listed in
dmesg output, but should still be recognized by the
system. When you are not sure what name your network card falls under
in OpenBSD, check the list displayed by apropos
driver. Still no luck? Look at this list.
|
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.
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 the
route-to keyword. 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 the dup-to keyword. 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.
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
|
proto)?Another layer of filtering is filtering by protocol name or number.
This is done with an addition of the proto keyword
followed by the name(s) or number(s) of protocols that the packets are
formed in accordance with. The list of protocols can be found in
/etc/protocols.
For example, if you want to let in only TCP packets, use this rule:
pass in quick on $ext_if proto tcp
Tip: Almost all popular services use TCP. You
should block UDP packets sent to servers that only use TCP, because
such packets are almost never legitimate traffic. If you do not know
which protocol is used by which services, check
/etc/protocols. This file is current as of the time of
release of the OpenBSD system you are using. The latest and the
freshest listings are always in the IANA's online database.
from, any,
all)?Source address filtering is typically used to stop two kinds of packets: those originating from hosts with legal IP addresses that we do not want to accept traffic from, and those that carry spoofed source addresses. In the first case, you will want to block packets from legal IP addresses if they're giving you so much trouble that you'd rather not accept traffic from them. In the second case, you ought to block packets with spoofed source addresses for your own safety as they will never be legitimate traffic. The following rule blocks packets with spoofed source addresses sent from external hosts and arriving on the firewall's external interface:
$blockIPs = {10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, \
224.0.0.0/4, 240.0.0.0/5, 127.0.0.0/8, 0.0.0.0}
block in quick on $ext_if from $blockIPs
Conversely, we can specify addresses of hosts that we want to accept traffic from, as in:
block in quick on $ext_if from ! $allow_ad to any
Tip: Note the exclamation mark (!),
which negates the value that follows it, so the rule above reads
"block incoming packets (and don't match them against other filtering
rules) arriving on the external interface send from all IP addresses
except $allow_ad and destined for any host."
There are two shortcuts that you can use to specify wider ranges of
IP addresses. One is the any keyword, which when placed
after from or to, matches any source
(from any) or target (to any) address:
block in quick on $log_if from any to $log_ad
block in quick on $ext_if from $blockIPs to any
The second shortcut is the all keyword which replaces
from any to any. The following two rules are
synonymous:
block in on $ext_if from any to any
block in on $ext_if all
Tip: from and to go together, and
you cannot write a rule with just either of them.
Source address specification is a required part of
any packet filtering rule, even if you use an all-encompassing
any or all shortcuts.
port)?For a finer degree of control, we can block or pass packets sent
from a specific port on the interface from which the matching packets
were sent. The port specification is listed after the source address
specification and is marked with the port keyword, as
in:
block in on $ext_if proto tcp from any port 80
The port 80 is equivalent to port = 80
Other possible operators are <, >,
<=, >=, !=,
<>, and ><. Their use is shown
in the following rules:
# block packets destined for port 80
block in on $ext_if proto tcp from any to $dmz_www_ad port = 80
# block packets destined for all ports except port 80
block in on $ext_if proto tcp from any to $dmz_www_ad port != 80
# block packets destined for ports lower than port 80
block in on $ext_if proto tcp from any to $dmz_www_ad port < 80
# block packets destined for ports lower than and port 80
block in on $ext_if proto tcp from any to $dmz_www_ad port <= 80
# block packets destined for ports higher than and equal to port 80
block in on $ext_if proto tcp from any to $dmz_www_ad port > 80
# block packets destined for ports higher than and equal to port 80
block in on $ext_if proto tcp from any to $dmz_www_ad port >= 80
# block packets destined for ports higher than port 80 and lower than port 1024
block in on $ext_if proto tcp from any to $dmz_www_ad port 80 >< 1024
# block packets destined for ports lower than port 80 and higher than port 1024
block in on $ext_if proto tcp from any to $dmz_www_ad port 80 <> 1024
Specifying port numbers makes sense only for those protocols that
carry source port information (like TCP or UDP). That is why you need
to use the proto keyword when you use the
port keyword. Otherwise, pfctl(8)
will complain and refuse to load rules.
to, any,
all)Destination address filtering is typically used to pass only those packets that are destined to addresses where there are servers listening for connections, for example:
pass in on $ext_if from any to $dmz_www_ad
All syntax rules for source addresses discussed earlier are applicable to destination addresses.
Source target address specification is a required
part of any packet filtering rule, even if you use an all-encompassing
any or all shortcuts.
port)The destination port specification follows the destination address specification. All rules that apply to source ports, apply to destination ports. Of course, both are independent. You will probably use destination ports more often than source ports, as such rules are usually used to only let those packets through that are destined to ports where appropriate servers are listening, for example:
pass in on $ext_if proto tcp from any to $ext_www_ad port $ext_www_port
pass in on $ext_if proto tcp from any to $ext_smtp_ad port $ext_smtp_port
pass in on $ext_if proto tcp from any to $ext_ftp_ad port $ext_ftp_port
|
user) and groups (group) are allowed
to receive or send packets?One very handy feature of pf(4)
is its ability to filter packets based on user and group names of the
users and groups who own the sockets on which packets are sent or
received. The user and group IDs can be given in form of names or
numbers and it is possible to specify ranges and lists of IDs. When
you list ranges, it is possible to construct them using the operators
described earlier in the section on source ports.
The user and group names are effective names, which may not be the same as the real name (as is the case with setuid and setgid processes). If you are having problems with these rules, remember that the user and group IDs are stored at the time a socket is created and they are not updated when the process creating a socket drops privileges (e.g., after a process binds to a privileged port as root, and then drops root privileges), so it may be that you need to use root ID in a rule instead of an unprivileged users's ID. Try this when you hit a stumbling block with rules user or group
In case of outgoing connections, the user IDs will match the user
that opened the connection from the firewall itself.
Similarly, for incoming connections, the user IDs will match the user
that opened the socket for listening on the firewall. It is
not possible to match usernames on connections forwarded with NAT
rules. In case of forwarded connections, user or group IDs can match
(or not match) a special username unknown. In this case,
only two operators are allowed: = and
!=.
Hint: User and group rules can only be used with TCP and UDP protocols.
flags)?TCP packet headers contain a flag field which plays an important role in the process of establishing, maintaining, and closing connections. Flags are important from the point of view of security, because some attackers abuse the three-way-handshake mechanism and other uses of TCP flags in denial of service (DOS) attacks (see CERT-1996.21, CERT-2000.21) and other types of attacks aimed at hosts connected to the Internet.
As of OpenBSD 3.2, pf(4)
recognizes the following TCP header flags:
(S)YN: synchronize sequence numbers(A)CK: acknowledge(R)ST: reset(F)IN: finish(P)USH: push(U)RG: urgent pointer(E)CE: (ECN-Echo) explicit congestion notification echoC(W)R: congestion window reducedThe syntax for this portion of filtering rules is as follows: the
flags keyword is followed by two lists of flags separated
with a slash (/); the first is a list of flags from the
second list that must be set. Those flags not on the first list must
be unset. Flags not listed on the second list are ignored, and those
flags from the second list missing from the first list may or may not
be set.
# FIN must be set, ignore the rest
block in proto tcp all flags F/F
# FIN must be unset, ignore the rest
block in all flags /F
# FIN must be set, the rest must be unset
block in all flags F
# FIN must be set, ACK must be unset, ignore the rest
block in all flags F/FA
# FIN and ACK must be unset, ignore the rest
block in all flags /FA
TCP flags are described in RFC761 [Postel 1980], and RFC793 [Postel 1981]. A far more detailed discussion of TCP flags can be found in [Stevens, Wright 1994]. Note that [Stevens, Wright 1994] do not describe the ECE and CWR flags, as these were added to the TCP header after TCP/IP Illustrated was published. For more information on ECE and CWR read RFC3168 [Ramakrishann, Floyd, Black 2001] and RFC3360 [Floyd 2002].
The flags keyword makes sense only for TCP
(proto tcp) packets.
Bogus ICMP packets are another way attackers can make your site
inoperable, which is why pf(4)
has special syntax for dealing with these useful, but potentially
dangerous packets. For more information about the havoc ICMP packets
can wreak read this paper
(pdf) from SANS [Jeon 2001] and the CERT-1996.26
advisory.
ICMPv4 packets are matched by icmp-type keyword, while
ICMP IPv6 are matched by the ipv6-icmp-type keyword.
Both keywords are followed by the ICMP type number and the ICMP code
number, separated with the code keyword.
Explanations of ICMPv4 message types and codes can be found in RFC792 [Postel 1981], ICMPv6 message types and codes are discussed in RFC2463 [Conta, Deering 1998].
|
keep state, modulate state)pf(4)
is a stateful packet filter, which means that it is capable
of keeping track of the state of connections. Stateful filtering has
the following advantages:
The basic principle behind stateful filtering is simple. When the initial packet makes the connection on the firewall, the packet filter will create an entry in its state table for that connection. All subsequent packets that belong to the connection for which an entry in the state table exist will be let through without matching them against the whole ruleset. State tables are checked before the filter begins evaluating filtering rules.
The packet filter decides if a packet belongs to a connection for which a state exists by checking the packet's sequence number stored in the TCP header. When the sequence number falls out of a narrow window, the packet is dropped. This mechanism prevents spoofed packet injection into an established connection.
Stateful inspection of packets is turned on with the keep
state keywords placed near the end of a filtering rule.
pass out on $ext_if proto TCP all keep state
To keep memory usage under control, information about connections is removed from the state table after connections are closed or after they time out.
By the way, when you use
nat/binat/rdr rules, you are
already using stateful filtering, as these rules create states
automatically.
There are two schools of thought about state creation. Some
administrators insist that only packets with the SYN flag (i.e., the
packets that initialize the connection) can create state. Others say
that any packet ought to be able to create state, because such rules
allow existing connections to create state and continue after the
state tables are flushed with pfctl -F state or after the
firewall is rebooted. Rules that create state only for packets with
the SYN flag set will not be able to create state for existing
connections.
The following rules allow all departing TCP packets to create state. As for inbound packets, only those sent to port 80 will be able to create state:
pass in proto tcp all port 80 keep state
pass out proto tcp all keep state
If you want to limit packets that can create state to those that have the
SYN flag set, add the flags S/SA condition, as in:
pass in proto tcp all port 80 flags S/SA keep state pass
out proto tcp all flags S/SA keep state
What about UDP or ICMP packets? Can pf(4)
create state for these as well? Yes, it can. With UDP packets, which
do not carry sequence numbers, the filter matches them to states using
only address and port information.
As for ICMP, these are treated differently depending on their
category. ICMP error messages that refer to TCP or UDP packets are
matched against states for connections they refer to. As such they do
not require separate rules, the packet filter will take care of this
automatically. ICMP queries (like ping(8))
may need their own separate rules, like:
pass out inet proto icmp all icmp-type echoreq keep state
Initial sequence numbers, if chosen carelessly, can be used in dangerous attacks that exploit the fact that some TCP stacks use easily predictable values for initial sequence numbers. For more information about these attacks read CERT Vulnerability Note VU#498440, or Rik Farrow's Sequence Number Attacks.
pf(4)
can prevent these attacks with the modulate state rule.
To turn it on, use modulate state instead of keep
state.
pass in proto tcp all port 80 flags S/SA keep state
pass out proto tcp all flags S/SA keep state
becomes
pass in proto tcp all port 80 flags S/SA modulate state
pass out proto tcp all flags S/SA modulate state
Remember that modulate state can only be used with TCP
connections. For other connections use keep state.
Each keep state or modulate state can have its own
set of options. These options are:
max n: maximum number
(n) of concurrent states that can be created for
this rule. See the description of the limit states
option in NAT
with pf. This option, unlike limit states,
works on a per-rule basis.timeout: timeout values for states created
with this rule. See the description of the timeout
option in NAT
with pf. This option, unlike timeout, works
on a per-rule basis.A rule using state options could look like this:
pass in proto tcp all port 80 flags S/SA \
modulate state (max 1000, tcp.established 120, tcp.closing 10)
allow-opts)?IP options are blocked by default, which is good from the point of
view of security. If you want to allow them, you explicitly state
your wish with the allow-opts keyword.
In practice there is very little need for allowing these options,
save for special application, as they may be used by attackers to mess
with your network, or with other hosts on the Internet (in such cases,
you might end up being accused of deliberate wrongdoing). IP options
have their legitimate uses, but if you don't explicitly need them,
leave them disabled. That is, do not use allow-opts.
If you're curious, read RFC791 [Postel 1981], RFC1108 [Kent 1991]. For a more detailed discussion, refer to [Stevens, Wright 1994] where you will find details of operation and implementation of IP options processing in BSD systems.
The allow-opts keyword can only be used in pass
rules.
label)Labels are used to mark rules for which pf(4)
will keep separate statistics. You can display these stats with pfctl(1).
A label is added with the label keyword followed by a
text string. Labels are placed at the end of rules:
pass in on rl0 all label "incoming"
pass out on rl0 all label "departing"
To view statistics, use:
$ sudo pfctl -s labels
incoming 85 26 2024
departing 86 56 6960
The numbers that follow the labels are the number of rule evaluations, packets, and bytes.
Labels can contain pre-defined macros:
$srcaddr: source IP address. This is the source IP
address listed after the from keyword in the rule, not
the packet's source address, so if you use from any and
label "from $srcaddr" in the same rule you'll see a
message similar to from any 86 56 6960.$dstaddr: destination IP address.$srcport: source port.$dstport: destination port.$proto: protocol name.$nr: rule number.That's enough theory. Next time, we'll add a packet filtering section to the ruleset described in More NAT, discuss some modifications to that ruleset, solve the FTP connection problems with a proxy, cover IPv6 filtering and build an invisible filtering bridge.
Jacek Artymiak started his adventure with computers in 1986 with Sinclair ZX Spectrum. He's been using various commercial and Open Source Unix systems since 1991. Today, Jacek runs devGuide.net, writes and teaches about Open Source software and security, and tries to make things happen.
Read more Securing Small Networks with OpenBSD columns.
Return to the BSD DevCenter.
Copyright © 2009 O'Reilly Media, Inc.