Packet Filter

PF is the new OpenBSD native firewall utility

PF is an IP firewall in that it operates on TCP/IP packets by looking at values in the network layer (IP) and transport layer (e.g. TCP) headers of each packet. Decisions about the fate of each packet are made based on matching the header values with specific rules that allow or deny the packets.

Configure with the /etc/pf.conf file

Control and view with 'pfctl' command

Great References:


Packet Filter setup

Of course IP Forwarding must be on in /etc/sysctl.conf:

    net.inet.ip.forwarding=1

And turned on PF in /etc/rc.conf:

    pf=YES

PF operates by the last-match-wins method

Firewalling falls into two main categories with respect to how they treat their rulesets. One method is first match wins, in which the first rule that matches a given IP packet will determine that packets fate. last match wins firewalling has quite naturally the exact opposite behavior where the last rule to match the packet will determine its fate.


The pfctl command

Use 'pfctl -R -f file' to load a rules file

   % sudo pfctl -R -f /etc/pf.conf

Use 'pfctl -e' to enable the firewall rules

Use 'pfctl -d' to disable the firewall rules

Use 'pfctl -F rules' to flush the active ruleset

   % sudo pfctl -F r

Use 'pfctl -s rules' to show the active ruleset

Use 'pfctl -s info' to show some statistics


PF - Logging

Packets are logged if they match a rule that specifies logging

Logged packets are sent to the /dev/pflog0 interface

The 'pflogd' daemon monitors the pflog0 interface


PF - Syntax

Best described by the BNF given in the pf.conf(5) manpage

Each rule is one of several Actions

Note that the rules must also appear in the following order if they appear.

Timing options

These options control various protocol timeout values Examples from the manual page:

  set timeout tcp.established 3600
  set timeout { tcp.opening 30, tcp.closing 900 }

Statistics logging

You can turn on statistics logging per network interface. Statistics include packet and byte counts.

  set loginterface dc0

Resource limits

Set limits on memory usage for session state information or fragment re-assembly. Example:

  set limit { states 20000, frags 20000 }

Optimization

The various optimization values change how quickly sessions timeout from the state table.

  set optimization aggressive

Packet scrubbing

Nat rules

See http://bio3d.colorado.edu/tor/sadocs/tcpip/nat.html

Filter rules - pass or block

blocking rules may be optionally modified by a <return> clause:

     return-rst     for TCP connections
     return-icmp    an ICMP UNREACHABLE by default

Logging may be specified using the 'log' keyword

The 'quick' keyword short-circuits last-match-wins behavior

The rule may be applied to a specific interface

    on <intfc>      e.g.  on fxp0

The rule may match only a specific ``address family''

So far, the syntax looks something like this:

   <action>  <dir>  <log>  <quick>  <interface>  <af>

The remaining clauses look like this:

 ..  <proto>  <hosts>  <flags>  <icmp>  <state>  <misc>

<proto> clause used to match specific IP protocol types

IP Protocols may be specified by name or by number

The <hosts> clause looks like this:

   from <host> port <port>   to <host> port <port>

<host> specifications may be:

<port> specifications express a RANGE of Port numbers

Binary <port> specifications - cont.

    port  N  ><  M

The <flags> clause only applies to TCP packets

The basic syntax of the <flags> clause is:

    flags  <a>/<b>

The <icmp> clause only applies to ICMP packets

Stateful Inspection is turned on using the <state> clause

The <misc> clause comprises several optional items


One final feature: macros

Macros are just variables


Constructing a firewall

The first rules express your default policy

Here is an important outgoing, stateful, rule:

  pass out log on $ext proto tcp \ 
          from any to any keep state

Be sure to block bogus incoming source IP addrs:

  block in log quick on $ext from { \ 
           10.0.0.0/8,            \ 
           172.16.0.0/12,         \ 
           192.168.0.0/16,        \ 
           localhost,             \ 
           0.0.0.0/32,            \ 
           255.255.255.255/32     \ 
 } to any

Now add holes in the firewall to allow certain services

Here is an ICMP rule:

  pass in on $ext inet proto icmp all \ 
         icmp-type { echorep, timex, unreach }

Here is a UDP rule:

  pass in on $ext inet proto udp from any to any \ 
         port { = domain, = 1053 }

And finally, here is a TCP rule:

  pass in on $ext inet proto tcp from any to any \ 
      port { = smtp, = http, = https, = ssh }


Optimization

PF parser will SKIP unnecessary rules when matching