Colorado BSD Users Group

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?

  1. Filtering based on any number of connection or packet properties.
  2. Redirection (send this packet to this host).
  3. Bandwidth control (via queues)
  4. 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


…Complex rule breakdown

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

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

Man pages

Other Utilities