PF.CONF(5)                OpenBSD Programmer's Manual               PF.CONF(5)

NAME
     pf.conf - filter rule configuration file for packet filtering

DESCRIPTION
     The pf(4) packet filter drops, passes and modifies packets according to
     the rules defined in this file.  For each packet inspected by the filter,
     the set of rules is evaluated from top to bottom, and the last matching
     rule decides what action is performed.

GRAMMAR
     Syntax for filter rules in BNF:

     rule       = action ( "in" | "out" )
                  [ "log" | "log-all" ] [ "quick" ]
                  [ "on" interface-name ] [ af ]
                  [ "proto" ( proto-name | proto-number | "{" proto-list "}" ) ]
                  hosts
                  [ flags ] ( [ icmp-type ] | [ ipv6-icmp-type ] )
                  [ "keep state" ] [ "modulate state" ]
                  [ "no-df" ] [ "min-ttl" number ] [ "allow-opts" ] .

     action     = "pass" | "block" [ return ] | "scrub" .
     return     = "return-rst" |
                  "return-icmp" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] |
                  "return-icmp6" [ "(" ( icmp-code-name | icmp-code-number ) ")" ] .

     af         = "inet" | "inet6" .
     proto-list = ( proto-name | proto-number ) [ "," proto-list ] .

     hosts      = "all" |
                  "from" ( "any" | host | "{" host-list "}" ) [ port ]
                  "to"   ( "any" | host | "{" host-list "}" ) [ port ] .

     host       = [ "!" ] address [ "/" mask-bits ] .
     host-list  = host [ "," host-list ] .
     port       = "port" ( unary-op | binary-op | "{" port-list "}" ) .
     port-list  = ( unary-op | binary-op ) [ "," port-list ] .
     unary-op   = ( "=" | "!=" | "<" | "<=" | ">" | ">=" )
                  ( port-name | port-number ) .
     binary-op  = port-number ( "<>" | "><" ) port-number .

     flags      = "flags" ( flag-set | flag-set "/" flag-set | "/" flag-set ) .
     flag-set   = [ "F" ] [ "S" ] [ "R" ] [ "P" ] [ "A" ] [ "U" ] .

     icmp-type  = "icmp-type" ( icmp-type-code | "{" icmp-list "}" ) .
     ipv6-icmp-type = "ipv6-icmp-type" ( icmp-type-code | "{" icmp-list "}" ) .
     icmp-type-code = ( icmp-type-name | icmp-type-number )
                      [ "code" ( icmp-code-name | icmp-code-number ) ] .
     icmp-list  = icmp-type-code [ "," icmp-list ] .


FILTER RULES
     Filter rules are typically manipulated using pfctl(8). Filter rules are
     loaded from a text file into the kernel using

     # pfctl -R file

     which replaces the active rule set with the new one.  The active rule set
     can be displayed using

     # pfctl -s r

     For each packet processed by the packet filter, the filter rules are
     evaluated in sequential order, from first to last.  Each rule either
     matches the packet or doesn't.  The last matching rule decides what ac-
     tion is taken.

     If no rule matches the packet, the default action is pass.

     To block everything by default and only pass packets that match explicit
     rules, one uses

     block in all
     block out all

     as the first two rules.

ACTIONS
     pass        The packet is passed.

     block       The packet is blocked.  Optionally, the filter can return a
                 TCP RST or ICMP UNREACHABLE packet to the sender, where ap-
                 plicable.

     scrub       The packet is run through normalization/defragmentation.
                 Scrub rules are not considered last matching rules.  IPv6
                 packets are not defragmented.

LOGGING
     log         In addition to the action specified, a log message is gener-
                 ated.

     log-all     Used with `keep state' or `modulate state' rules.  Not only
                 the packet that creates state is logged, but all packets of
                 the connection.

     The logged packets are sent to the pflog0 interface.  This interface is
     monitored by the pflogd(8) logging daemon which dumps the logged packets
     to the file /var/log/pflog in tcpdump(8) binary format.  The log files
     can be read using tcpdump:

     # tcpdump -n -e -ttt -r /var/log/pflog

QUICK
     If a packet matches a rule which has the `quick' option set, this rule is
     considered the last matching rule, and evaluation of subsequent rules is
     skipped.

PARAMETERS
     The rule parameters specify for what packets a rule applies.  A packet
     always comes in on or goes out through one interface.  Most parameters
     are optional.  If a parameter is specified, the rule only applies to
     packets with matching attributes.  Certain parameters can be expressed as
     lists, in which case pfctl generates all needed rule combinations.

   in or out
     The rule applies to incoming or outgoing packets.  Either in or out must
     be specified.  To cover both directions, two rules are needed.

   on <interface>
     The rule applies only to packets coming in on or going out through this
     particular interface.

   <af>
     The rule applies only to packets of this address family.  Supported val-
     ues are inet and inet6.

   proto <protocol>
     The rule applies only to packets of this protocol.  Common protocols used
     here are tcp, udp, icmp and ipv6-icmp.

   from <source> port <source> to <dest> port <dest>
     The rule applies only to packets with the specified source and destina-
     tion addresses/ports.

     Addresses can be specified in CIDR notation (matching netblocks), as sym-
     bolic host names or interface names.  Host name resolution and interface
     to address translation are done at rule set load-time.  When the address
     of an interface (or host name) changes (by DHCP or PPP, for instance),
     the rule set must be reloaded for the change to be reflected in the ker-
     nel.  See dhclient-script(8) or ppp(8) for information on how to automate
     this task.

     Ports can be specified using these operators

         = (equal), != (unequal), < (lesser), <= (lesser or equal), > (greater),
         >= (greater or equal), >< (range) and <> (except range).

     >< and <> are binary operators (they take two arguments), and the range
     doesn't include the limits, for instance:

     port 2000 >< 2004
                 means `all ports > 2000 and < 2004', hence ports 2001, 2002
                 and 2003.

     port 2000 <> 2004
                 means `all ports < 2000 or > 2004', hence ports 1-1999 and
                 2005-65535.

     The host and port specifications are optional, as the following examples
     show:

         pass in all
         pass in from any to any
         pass in proto tcp from any port <= 1024 to any
         pass in proto tcp from any to any port = 25
         pass in proto tcp from 10.0.0.0/8 port > 1024 to ! 10.1.2.3 port != 22

   flags <a> | <a>/<b> | /<b>
     The rule only applies to TCP packets that have the flags <a> set out of
     set <b>.  Flags not specified in <b> are ignored.  Possible flags are F
     (FIN), S (SYN), R (RST), P (PUSH), A (ACK) and U (URG).

     flags S/S   Flag SYN is set.  The other flags are ignored.

     flags S/SA  Of SYN and ACK, exactly SYN is set.  SYN, SYN+PSH, SYN+RST
                 match, but SYN+ACK, ACK and ACK+RST don't.  This is more re-
                 strictive than the previous example.

     flags S     If the second set is not specified, it defaults to FSRPAU.
                 Hence, only packets with SYN set and all other flags unset
                 match this rule.  This is more restrictive than the previous
                 example.

     flags /SFRA
                 If the first set is not specified, it defaults to none.  All
                 of SYN, FIN, RST and ACK must be unset.

   icmp-type <type> code <code> and ipv6-icmp-type <type> code <code>
     The rule only applies to ICMP or ICMPv6 packets with the specified type
     and code.  This parameter is only valid for rules that cover protocols
     icmp or ipv6-icmp.  The protocol and the icmp type indicator (icmp-type
     or ipv6-icmp-type) must match.

   allow-opts
     By default, packets which contain IP options are blocked.  When allow-
     opts is specified for a pass rule, packets that pass the filter based on
     that rule (last matching) do so even if they contain IP options.  For
     packets that match state, the rule that initially created the state is
     used.  The implicit pass rule that is used when a packet doesn't match
     any rules does not allow IP options.

MACROS
     pfctl supports macro definition and expansion like:

         ext_if = "kue0"
         pass out on $ext_if from any to any           keep state
         pass in  on $ext_if from any to any port = 25 keep state

     Macro names must start with a letter and may contain letters, digits and
     underscores.  Macros are not expanded recursively.

STATEFUL INSPECTION
     pf is a stateful packet filter, which means it can track the state of a
     connection.  Instead of passing all traffic to port 25, for instance, one
     can pass only the initial packet and keep state.

     If a packet matches a pass ... keep state rule, the filter creates a
     state for this connection and automatically lets pass all following pack-
     ets of that connection.

     Before any rules are evaluated, the filter checks whether the packet
     matches any state.  If it does, the packet is passed without evaluation
     of any rules.

     States are removed after the connection is closed or has timed out.

     This has several advantages.  Comparing a packet to a state involves
     checking its sequence numbers.  If the sequence numbers are outside the
     narrow windows of expected values, the packet is dropped.  This prevents
     spoofing attacks, where the attacker sends packets with a fake source ad-
     dress/port but doesn't know the connection's sequence numbers.

     Also, looking up states is usually faster than evaluating rules.  If one
     has 50 rules, all of them are evaluated sequentially in O(n).  Even with
     50'000 states, only 16 comparisons are needed to match a state, since
     states are stored in a binary search tree that allows searches in O(log2
     n).

     For instance:

         block out all
         block in  all
         pass out proto tcp from any to any           flags S/SA keep state
         pass in  proto tcp from any to any port = 25 flags S/SA keep state

     This rule set blocks everything by default.  Only outgoing connections
     and incoming connection to port 25 are allowed.  The inital packet of
     each connection has the SYN flag set, will be passed and creates state.
     All further packets of these connections are passed if they match a
     state.

     Specifying flags S/SA restricts state creation to the initial SYN packet
     of the TCP handshake.  One can also be less restrictive, and allow state
     creation from intermediate (non-SYN) packets.  This will cause pf to syn-
     chronize to existing connections, for instance if one flushes the state
     table.

     For UDP, which is stateless by nature, keep state will create state as
     well.  UDP packets are matched to states using only host addresses and
     ports.
     ICMP messages fall in two categories: ICMP error messages, which always
     refer to a TCP or UDP packet, are matched against the refered to connec-
     tion.  If one keeps state on a TCP connection, and an ICMP source quench
     message refering to this TCP connection arrives, it will be matched to
     the right state and get passed.

     For ICMP queries, keep state creates an ICMP state, and pf knows how to
     match ICMP replies to states.  For example

         pass out inet proto icmp all icmp-type echoreq keep state

     lets echo requests (pings) out, creates state, and matches incoming echo
     replies correctly to states.

     Note: nat/rdr rules (see nat.conf(5)) implicitly create state for connec-
     tions.

STATE MODULATION
     Much of the security derived from TCP is attributable to how well the
     initial sequence numbers (ISNs) are chosen.  Some popular stack implemen-
     tations choose very poor ISNs thus are normally susceptible to ISN pre-
     diction exploits.  By applying a "modulate state" rule to a TCP connec-
     tion, pf will create a high quality random sequence number for each con-
     nection endpoint.

     The "modulate state" directive implicitly keeps state on the rule and is
     only applicable to TCP connections.

     For instance:

         block out all
         block in  all
         pass out proto tcp from any to any                      modulate state
         pass in  proto tcp from any to any port = 25 flags S/SA modulate state

     Caveat:  If pf picks up an already established connection (the firewall
     was rebooted, the state table was flushed, ...) it will not randomize the
     sequence number and it will fall back to operating as if "keep state" was
     specified for that connection.

     Caveat:  If the state table is flushed or the firewall is rebooted, cur-
     rently established modulated connections can not be continued or picked
     up again by the firewall.  The sequence numbers will be out of sync with-
     out the modulator.

NORMALIZATION
     Packet normalization is invoked via the scrub directive.  Normalization
     is used to sanitize packet content in such a way that there are no ambi-
     guities in packet interpretation on the receiving side.

     The normalizer does full IP fragment reassembly to prevent attacks that
     confuse intrusion detection systems by sending overlapping IP fragments.

   no-df
     Clears the dont-fragment bit from a matching ip packet.

   min-ttl <number>
     Enforces a minium ttl for matching ip packets.

EXAMPLES
     # The external interface is kue0 (157.161.48.183, the only routable address)
     # and the private network is 10.0.0.0/8, for which we are doing NAT.

     # use a macro for the interface name, so it can be changed easily
     ext_if = "kue0"

     # normalize all incoming traffic
     scrub in on $ext_if all

     # block and log everything by default
     block             out log on $ext_if           all
     block             in  log on $ext_if           all
     block return-rst  out log on $ext_if proto tcp all
     block return-rst  in  log on $ext_if proto tcp all
     block return-icmp out log on $ext_if proto udp all
     block return-icmp in  log on $ext_if proto udp all

     # block and log outgoing packets that don't have our address as source,
     # they are either spoofed or something is misconfigured (NAT disabled,
     # for instance), we want to be nice and don't send out garbage.
     block out log quick on $ext_if from ! 157.161.48.183 to any

     # silently drop broadcasts (cable modem noise)
     block in quick on $ext_if from any to 255.255.255.255

     # block and log incoming packets from reserved address space and invalid
     # addresses, they are either spoofed or misconfigured, we can't reply to
     # them anyway (hence, no return-rst).
     block in log quick on $ext_if from { 10.0.0.0/8, 172.16.0.0/12, \
             192.168.0.0/16, 255.255.255.255/32 } to any

     # ICMP

     # pass out/in certain ICMP queries and keep state (ping)
     # state matching is done on host addresses and ICMP id (not type/code),
     # so replies (like 0/0 for 8/0) will match queries
     # ICMP error messages (which always refer to a TCP/UDP packet) are
     # handled by the TCP/UDP states
     pass out on $ext_if inet proto icmp all icmp-type 8 code 0 keep state
     pass in  on $ext_if inet proto icmp all icmp-type 8 code 0 keep state

     # UDP

     # pass out all UDP connections and keep state
     pass out on $ext_if proto udp all keep state

     # pass in certain UDP connections and keep state (DNS)
     pass in on $ext_if proto udp from any to any port = domain keep state

     # TCP

     # pass out all TCP connections and modulate state
     pass out on $ext_if proto tcp all modulate state

     # pass in certain TCP connections and keep state (SSH, SMTP, DNS, IDENT)
     pass in on $ext_if proto tcp from any to any port { ssh, smtp, domain, \
             auth } keep state

FILES
     /etc/pf.conf
     /etc/services

SEE ALSO
     pf(4), nat.conf(5), services(5), pfctl(8), pflogd(8)

HISTORY
     The pf.conf file format appeared in OpenBSD 3.0.

OpenBSD 3.0                      July 8, 2001                                6
