Changes in pf: Packet Filtering
Pages: 1, 2, 3, 4, 5, 6
Will you use stateful filtering? (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:
- makes packet processing faster
- makes writing rulesets easier
- makes connections safer
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 thelimit statesoption in NAT with pf. This option, unlikelimit states, works on a per-rule basis.timeout: timeout values for states created with this rule. See the description of thetimeoutoption in NAT with pf. This option, unliketimeout, 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)
Will IP options be allowed or blocked (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.
Labels (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 thefromkeyword in the rule, not the packet's source address, so if you usefrom anyandlabel "from $srcaddr"in the same rule you'll see a message similar tofrom 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.
-
Good Article, Thank You
2003-07-26 14:39:14 anonymous2 [View]
-
modulate state
2003-06-29 13:09:22 anonymous2 [View]
-
modulate state
2003-07-03 04:02:26 Jacek Artymiak | [View]