73c0 Pf - Telecomix Crypto Munitions Bureau


From Telecomix Crypto Munitions Bureau

Jump to: navigation, search

pf, short for packet filter, is the default firewall for the OpenBSD operating system.

If you want to know how pf works, you can go to The OpenBSD pf tutorial. This page sometimes assumes that you have read the default manual.


[edit] Note!

This is for OpenBSD 4.5 or something, which was more than two years ago. Pf has changed since then and so should this article..

[edit] Why use pf?

Because you do not trust your linux iptables-firewall. It is very difficult to set up rules for scrubbing incoming packets from weird stuff, but pf does this nicely :) Maybe think about using OpenBSD for your routers, and linux only for the servers? That way the routers can filter all incoming packets and handle VPN stuff, BGP/OSPF/RIP/whatever-routing, while you still can use linux larger flora of free software. OpenBSD is generally more difficult to use for servers and stuff, but they are better on networking than linux. Take the best from both worlds :)? You can also use FreeBSD. Or just ignore this text. It is up to you :D *omg freedom of choice!*


  1. its much easier to learn how pf works, than how linux iptables works.
  2. pf is secure by default, iptables is not.
  3. there is a good tutorial for pf, there is only crappy tutorials for iptables. the iptables man page even contains errors (!).
  4. pf has one well-defined method for updating firewall rules and all updates are done atomically (all rules are updated at once, and errors will make it abort updates without any changes). Iptables can do this too, but it seems more difficult.

[edit] What you need to think of

  • pf assumes that the different rules come in a special predefined order. Read the example below and figure it out, I have forgotten ;)

[edit] Example: Firewall cluster

(This script is old, the language used for defining pf rules has been updated slightly. You can still modify this script easily though, if you want. But maybe read the official openbsd pf tutorial instead, its really good!)

This script is for a computer that sits in a firewall cluster. There are mainly three important interfaces: $intertubes, which connects to the internets. $LAN that connects to the LAN, obviously. And, finally, $syncro that is a special cable that runs to the other firewalls in the cluster. $syncro is used to keep track of all connections that flows through the cluster, so that if one firewall goes offline the others can resume operations without you going offline. It is nice if you want to stay online even if you reboot and maintains your firewalls. The $syncro interface could be connected to a switch if there are more than two computers in the cluster, or directly to the other firewall if there is only two of them.

DO NOT DEFINE $syncro AS EQUAL TO $LAN, it would seriously damage your security if there is angry-evil ppl in your LAN that knows how to capture packets off the wires. $syncro should be a separate cable, for physical security.

For this to work, you need to set up an pfsync interface, and a ftp_proxy. See the OpenBSD pf FAQ for more information about that.

Think of this script as a helping hand if you are trying to debug anything, rather than a definitive guide. It is NOT a replacement for the pf manual.

Stuff you need to think about

  • The firewall computers each have their own IPs, but they are sharing two IPs with carp. You need to use (carp0) and (carp1) for NATing and stuff, do not use the firewalls own IP addresses.
  • When I rewrote one of my own pf.conf-files for this example (I removed my personal stuff), I might have forgotten about something. Do not trust that this works just out of the box :b
  • You need to update the interfaces named intertubes, LAN and syncro to something sane and real.
  • You can use the same script for all your firewalls, if you just change the IP-addresses and the interfaces.
  • Do not forget to take care of your /etc/hostname.IF-files. Please DO use a good password for the carp protocols.
  • I recommend that you paint a detailed picture of how your network is wired after you are done with this, it will be very difficult to recall it laters. Glue the picture to anyone of your firewalls :)
# macros -----------------------------------------------------------------------

# carp0 is used for $intertubes common IP
# carp1 is used for $LAN common IP


tcp_services="{ 22 }"

server_0_tcp="{ 1424 1333 7500:8000 }"
server_0_udp="{ 25325 }"

server_1_tcp="{ 1355 666 }"

irc_ports="{6667 6668 6669}"

# other macros -----------------------------------------------------------------
# traps to catch skript kiddies.
# max-src-conn = how many sessions are allowed from one single IP
# max-src-conn-rate = how fast an IP is allowed to connect (15/5 means 15 per 5 sec)
# overload <traplist> = IPs that exceeds the limits are put in this table
trap="(max-src-conn 100, max-src-conn-rate 15/5, overload <traplist> flush global)"
eviltrap="(max-src-conn 5, max-src-conn-rate 3/5, overload <traplist> flush global)"
irc_trap="(max-src-conn 100, max-src-conn-rate 30/600, overload <traplist> flush global)"

# runtime options / define general pf behaviour --------------------------------
set block-policy drop               # do not notify anyone of errors, just drop all strange stuff
set loginterface $intertubes        # we are logging on the most important interface :)
set skip on lo0                     # and we assume that our loopback interface is behaving

# creating some tabels that are useful -----------------------------------------
# this section only creates the tables, they are *used* later in the script

table <fucktards> persist file "/etc/pf-own/fucktards"
      # fucktards are permanently blocked IP addresses (put FRA here, use creeper.se to get their IP-blocks)

table <traplist> persist
      # ip's in the traplist are only blocked until reboot or table-flush
      # I recommend that you flush the table with cron every day or so

# scrubbing --------------------------------------------------------------------

scrub in
   # simple scrub of all packets that enter on any interface. More specific rules for
   # the $intertubes-interface just below:

scrub in on $intertubes min-ttl 255
   # sets incomming TTL to 255 to avoid letting people map the network by examining
   # which services respond at different TTLs, thus denying them the ability to examine
   # your network topology. CAUTION!!! If you have another computer that routes traffic
   # and also sets the TTL to something before sending it to the $intertubes-interface
   # you are creating a ticking bomb. It would be very simple to DoS you (and perhaps
   # your friends) if you do not think this through first: Packets that have their their
   # TTL changed can be routed forever, and *very* quickly eat up all your bandwidth,
   # thus forcing you offline.

scrub out on $intertubes max-mss 1500 random-id min-ttl 255
   # remove some identifying info, sets outgoing TTL to 255 for everything. The same
   # applies here as for the previous rule. BE CAREFUL and THINK BEFORE you just
   # copy the part about min-ttl!!!

# bandwidth allocation ---------------------------------------------------------
# We assume that we have a connection with 1Gbit/s bandwidth, just for lulz
# _Obviously_ you should change this to your actual bandwidth. It is just an
# example.

altq on $intertubes cbq bandwidth 1Gb queue { std, ssh, important } 
  queue std        on $intertubes bandwidth 88% priority 0 cbq(default)
  queue ssh        on $intertubes bandwidth 2%  priority 1 cbq(borrow)
  queue important  on $intertubes bandwidth 10%  priority 2 cbq(borrow)

# nat/rdr ----------------------------------------------------------------------

nat on $intertubes from -> (carp0)
       # NAT traffic from LAN to the internet via the firewalls common IP :)

nat on $LAN from -> $LAN_ip
       # NAT mirror used to access services. This can be used to bounce traffic
       # against the firewalls to reach stuff that is inside our network. It is
       # an *uglyhack* but it helps if you want to reach services inside your
       # own LAN as if you were connecting from the outside.

# FTP PROXY RULES (needed to traverse the firewall) # # # # # #
nat-anchor "ftp-proxy/*"         # used by ftp-proxy to make FTP work :)
rdr-anchor "ftp-proxy/*"         # used by ftp-proxy to make FTP work :)
rdr on $LAN proto tcp from any to any port 21 -> port 8021
                                 # ftp-proxy listens at this port
                                 # do not forget to actually start this program
                                 # or ALL of your FTP sessions will fail.

# normal redirects # # # # # # # # # # # # # # # # # # # # # # #

   # server_0 port redirections
rdr on $intertubes proto tcp from any to any port $server_0_tcp -> $server_0
rdr on $intertubes proto udp from any to any port $server_0_udp -> $server_0

   # server_1 port redirections
rdr on $intertubes proto tcp from any to any port $server_1_tcp -> $server_1

# filter rules -----------------------------------------------------------------

block in                               # default is to block from outside

pass out on $intertubes proto tcp modulate state   # randomize outgoing TCP packets
pass out keep state       # FUCKING IMPORTANT DO NOT REMOVE
                          # "keep state" *NEEDS* to be there if you want to have
                          # a stateful firewall, and not something lame. If you
                          # plan on using NATing then you must use it for the
                          # firewall to know which connection on the inside of
                          # the LAN belongs to which connection on the outside
                          # at the $intertubes interface.

~~~~~~~~~~~~~~ firewall cluster rules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# do not allow people to access the firewall clusters private network
block in quick on {$LAN $intertubes} inet from any to a.b.c.d/16
# replace a.b.c.d with the network you use for the firewall cluster.

# firewall cluster rules. Needed to make the firewall servers talk to each other
# about which connections are up and running. If one of the firewalls go down,
# then the other can instantly replace the other, but it needs to know the state
# of *all* connections at all times. the $syncro interface is used just for that.
pass quick on { $syncro } proto pfsync keep state (no-sync)         # UNENCRYPTED
pass quick on { $intertubes $LAN } proto carp keep state (no-sync)  # this uses SHA-1
        # no-sync does not forward the states to pfsync --^
        # the reason why you want no-sync here is because it would be weird to
        # keep track of the protocol that keeps track of connections. You do not
        # need that. Maybe it will not ever work :)?
        # It does not need to be checked by the firewall (pass quick) because it
        # uses SHA-1 to check if the traffic came from a friend or not.

# block all martians trying to enter our networks from tze intertubes
block in on $intertubes inet from to any
block in quick on $intertubes inet from to any
block in quick on $intertubes inet from to any

# blacklists
# block & log various government organisations and other tards
block in log quick on $intertubes from <fucktards> to any
# and just simply ignore the skript kiddies that got trapped
block in quick on $intertubes from <traplist> to any
# the traps were defined earlier, in the macros section.

# FTP proxy, you *NEED* this if you want to be able to use the FTP protocol
anchor "ftp-proxy/*"          # used by ftp-proxy to make FTP work :)

# look this up in The openbsd pf FAQ: www.openbsd.org/faq/pf/
antispoof quick for { lo $intertubes $LAN $syncro }

# --- the ports must pass through filtering for redirection to work --------

# server_0
pass in on {$intertubes $LAN} inet proto tcp from any to $server_0 port $server_0_tcp \
   flags S/SA synproxy state $trap queue important
pass in on {$intertubes $LAN} inet proto udp from any to $server_0 port $server_0_udp \
   queue std

pass in on {$intertubes $LAN} inet proto tcp from any to $server_1 port $server_1_tcp \
   flags S/SA synproxy state $trap queue important

# ircserver, with the special trap rule if you remember
pass in on $intertubes inet proto tcp from any to $ircserver port $irc_ports \
   flags S/SA synproxy state $irc_trap queue std

# we want some traffic to be able to reach the router too 
pass in on { $intertubes $LAN } inet proto tcp from any to any port $tcp_services \
   flags S/SA synproxy state $eviltrap queue ssh

# synproxy means that the router keeps track of the TCP handshake, and forwards it
# to the server only if it was correctly performed. This is nice, because we do not
# really trust the servers on the inside to handle this correctly.

# we trust everyone on the LAN. (but maybe you should go through which services are
# running on the router anyways.)
pass in on $LAN

[edit] Fucktards list

These are some IP-blocks i harvested from creeper.se. They contains swedish government organizations, and just plain evil companies, that are not allowed into any of my networks. Put them in a file (with the same syntax as below) and update your pf.conf to contain them in a table, that you block.

EDIT: This should really be a link to the Blocklists page.
Personal tools