What is PF?
PF, or Packet Filter, is a filtering mechanism which lives
in the kernel, has a userland interface (/dev/pf
) and tools (pfctl
)
for manipulating rules, table entries and gathering statistics.
What can you do with PF?
- Filtering based on any number of connection or packet properties.
- Redirection (send this packet to this host).
- Bandwidth control (via queues)
- Direct traffic to external applications.
.. Much more!
Basic Concepts
Macros
Can be thought of as variables, but they allow you to specify lists of items as well.
ext_if = "em0"
all_ifs = "{" $ext_if lo0 "}"
Tables
Are collections of addresses or networks.
table <goodhosts> { 10.0.1.2, 10.0.1.3 }
table <badhosts> file "/etc/pf/bads.list"
Rules
Define what should be done with packets that match a specific criteria.
block on $ext_if from <badhosts>
pass in on $ext_if proto tcp from any to $ext_if port www
…Basic Concepts
pfctl
a command run to enable / disable pf, load config changes, change states and view statistics.
Enabling:
pfctl -e
Disabling:
pfctl -d
Showing All Stats:
pfctl -s all
…Basic Concepts
Reload config:
pfctl -f /etc/pf.conf # you can use -n to do a syntax check
Modify State:
pfctl -k 0.0.0.0/0 -k host1 # kill all states going to host1
Filtering
Using the basic syntax listed in the previous slide, we can define some simple filtering rules
# do not filter any packets on lo
set skip on lo
# block packets and return TCP RST for TCP and ICMP UNREACHABLE
# for other packets.
block return
# pass packets
pass
# send TCP RST / ICMP UNREACHABLE for packets that hit
# interfaces that are NOT lo0 and are between port 6000 and 6010
block return in on ! lo0 proto tcp to port 6000:6010
…Filtering Example
I call this config the “Go away”. This is probably the most minimal ruleset you can have.
It blocks all inbound connections while allowing and keeping state* for any outbound connections.
block in all
pass out all
*Note since OpenBSD 4.1, state is implicit. Prior to 4.1 your pass
line would look like:
pass out all keep state
…Complex Filtering Example
pass in on $ext_if proto tcp from any to $ext_if port ssh rdr-to \
$ssh_host port ssh flags S/SFRA synproxy state (max 5, \
source-track rule, max-src-states 5, max-src-nodes 5, \
max-src-conn-rate 5/60 overload <tmpblock> flush global )
This lengthy example is doing a lot of things, but basically, when someone connects to $ext_if
on port 22
(ssh) PF redirects the traffic to $ssh_host
assuming the subsequent
rulesets have not been hit.
Complex rule breakdown
flags S/SFRA
- this rule applies to (S)YN TCP packets that have flags in (S)YN, (F)IN, (R)ST and (A)CK and is there to prevent ACK storms.synproxy state
- this rule causes pf(4) to complete the tcp handshake process and forward packets between endpoints. This is used to prevent SYN floods.max 5
- Limits concurrent states the rule can create to 5.source-track rule
- tells PF to track the number of states per source IP. The number allowed will be defined bymax-src-states
andmax-src-nodes
max-src-{states,nodes} 5
tells oursource-track rule
directive to limit the state table entries to 5.
…Complex rule breakdown
max-src-conn-rate 5/60
- Limit the rate of new connections to N/Seconds (5 connections per 60 seconds)<tmpblock>
- the table where connections that hit our limits will be addedflush global
kills states for the hosts that exceed the matching rules.
What does that all mean?!
The entire rule is essentially limiting ssh connections to 5, and temporarily blocking any connections that try to make more than 5 connections in 60 seconds.
NAT example
antispoof quick for { lo $int_if }
match out on egress inet from !(egress:network) to any \
nat-to (egress:0)
pass in on egress inet proto tcp from any to (egress) \
port $tcp_services
antispoof
blocks all traffic with a source IP from the netowrk that is on the interface(s) defined.- Can you figure out what the rest of the rules are doing?
Blocking Windows™
Passive OS Fingerprinting is a method for determining an OS by inspecting slight differences in a TCP connection’s SYN packet.
To list fingerprints run:
pfctl -so
A rule that would block traffic from a Windows box would look something like this:
block return in on $ext_if proto tcp from any os "Windows"
More Info
Awesome Books
- Book of PF 3rd Edition - currently only available as early access.
- Book of PF 2nd Edition - ebook only due to high demand!