<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN"[
]>
<book>
    <bookinfo>
  <title>
Building the Network You Need with OpenBSD's PF
  </title>
    <keywordset>
      <keyword>firewall</keyword>
      <keyword>firewalls</keyword>
      <keyword>firewalling</keyword>
      <keyword>OpenBSD</keyword>
      <keyword>firewalling</keyword>
      <keyword>packet filter</keyword>
      <keyword>PF</keyword>
      <keyword>network</keyword>
      <keyword>networking</keyword>
      <keyword>network firewall</keyword>
      <keyword>network firewalling</keyword>
      <keyword>network security</keyword>
      <keyword>internet firewall</keyword>
      <keyword>internet protocol</keyword>
      <keyword>internet security</keyword>
    </keywordset>
<subtitle>BSDCan, Ottawa May 6th, 2009</subtitle>

<!--<mediaobject>
      <imageobject>
	<imagedata align="center" fileref="pf_cov.jpg"> 
      </imageobject>
    </mediaobject>-->
    <author>
      <firstname>Peter</firstname>
      <othername>N. M.</othername>
      <surname>Hansteen</surname>
    <authorblurb>
	<para>Free Software Consultant</para>
    </authorblurb>
      <affiliation>
	<orgname>FreeCode AS</orgname>
	<address><email>peter.hansteen@freecode.no</email>, <email>peter@bsdly.net</email></address>
      </affiliation>
    </author>
    <copyright>
      <year>2005 - 2009</year>
      <holder>Peter N. M. Hansteen</holder>
    </copyright>
    <legalnotice>
      <para>This document uses an adaptation of <ulink url="http://ourworld.compuserve.com/homepages/hoenicka_markus/">Markus Hoenickas</ulink> dbslide stylesheet, which is published under the license
	stated in the file <filename>COPYING</filename>, and adaptations of the <ulink url="http://www.freebsd.org">FreeBSD</ulink> project's CSS stylesheet, which is published under the BSD license (see <filename>docbook.css</filename>). </para>
    </legalnotice>
  </bookinfo>
<chapter id="unhowto">
<title>
This is not a HOWTO
</title>
<screen>
The Pledge of the Network Admin

This is my network. 

It is mine 
or technically my employer's, 
it is my responsibility 
and I care for it with all my heart

there are many other networks a lot like mine,

but none are just like it.

I solemnly swear 

that I will not mindlessly paste from HOWTOs.
</screen>
</chapter>
  <chapter id="warmup-minifaq">
    <title>You're wondering ...</title>
    <itemizedlist>
      <listitem>
	<para>
<emphasis>PF Looks Really Cool. Can I Run PF on My Linux Machine?</emphasis>
       </para>
      </listitem>
      <listitem>
	<para>
<emphasis>I Know Some Linux, but I Need to Learn Some BSD. Any Pointers?</emphasis>
       </para>
      </listitem>
      <listitem>
	<para>
<emphasis>Can You Recommend a GUI Tool for Managing My PF Rule Set?</emphasis>
       </para>
      </listitem>
      <listitem>
	<para>
<emphasis>Is There a Tool I Can Use to Convert My OtherProduct® Setup to a PF
Configuration? </emphasis>
       </para>
      </listitem>
      <listitem>
	<para>
<emphasis>Where Can I Find Out More?</emphasis>
       </para>
      </listitem>
    </itemizedlist>
  </chapter>
  <chapter id="runonlinux">
    <title>You're wondering ... Linux?</title>
<para>
<emphasis>PF Looks Really Cool. Can I Run PF on My Linux Machine?</emphasis>
</para>
<para>
You need a BSD. Preferably OpenBSD
</para>
    <para>
<emphasis>Cool, new features:</emphasis> always in OpenBSD first
</para>
<para>
Porting to non-BSD takes major effort, no reports of completed Linux port (but a few have started)
</para>
</chapter>

<chapter id="learnbsd">
    <title>You're wondering ... Learn BSD?</title>
    <para><emphasis>I Know Some Linux, but I Need to Learn Some BSD. Any Pointers?
</emphasis></para>
<itemizedlist>
<listitem>
<para>
Network interface name equals <emphasis>driver name</emphasis> + sequence number, such as <filename>xl0</filename> (3Com), <filename>em0</filename>, <filename>fxp0</filename> (Intel), and so on
</para>
</listitem>
<listitem>
<para>
Configuration centralized in <filename>/etc/rc.conf</filename>, on OpenBSD you create, edit <filename>/etc/rc.conf.local</filename> to override <filename>rc.conf</filename> defaults
</para>
</listitem>
<listitem>
<para>
PF is configured via <filename>/etc/pf.conf</filename> and command line - <application>pfctl</application>(8)
</para>
</listitem>
</itemizedlist>

</chapter>

<chapter id="guitool">
<title>You're wondering ... GUI tools?</title>
<para>
<emphasis>Can You Recommend a GUI Tool for Managing My PF Rule Set?</emphasis>
</para>
    <para><emphasis>Yes</emphasis>, GUI tools do exist.</para>
    <para><emphasis>No</emphasis>, this tutorial is taken in without them</para>
    <para><emphasis>Learn</emphasis> to understand <filename>pf.conf</filename> first, then make <emphasis>informed</emphasis> decision</para>
<para>Keep your <filename>pf.conf</filename> readable, already!</para>
<para>(<filename>$EDITOR</filename> + <parameter>pf.conf</parameter> is faster anyway)</para>
</chapter>

  <chapter id="autoconvert">
    <title>You're wondering ... Automatic conversion?</title>
<para>
<emphasis>Is There a Tool I Can Use to Convert My OtherProduct® Setup to a PF
Configuration? </emphasis>
</para>
    <para>Some tools claim to do it, DON'T trust them</para>
    <para>OtherProduct&trade; features and approaches probably different from PF</para>
    <para><emphasis>Recommendation:</emphasis> Evaluate your needs, write a good spec, implement as fresh PF config</para>
  </chapter>


  <chapter id="learnmore">
    <title>You're wondering ... More info?</title>
	<para>
<emphasis>Where Can I Find Out More?</emphasis>
       </para>
    <para>You're here.</para>
    <para>man pages, PF FAQ </para>
    <para>Books, other resources (see <ulink url="references.html">references</ulink>)</para>
  </chapter>

<chapter id="pfhaiku">
<title>
PF - Haiku
</title>
<screen>
Compared to working with iptables, PF is like this haiku:

A breath of fresh air,
floating on white rose petals,
eating strawberries.

Now I'm getting carried away:

Hartmeier codes now,
Henning knows not why it fails,
fails only for n00b.

Tables load my lists,
tarpit for the asshole spammer,
death to his mail store.

CARP due to Cisco,
redundant blessed packets,
licensed free for me.
</screen>
<para>
Jason Dixon, May 20th 2004 (<ulink url="http://marc.info/?l=openbsd-pf&amp;m=108507584013046&amp;w=2">http://marc.info/?l=openbsd-pf&amp;m=108507584013046&amp;w=2</ulink>)
</para>
</chapter>

<chapter id="intro">
<title>
What PF is
</title>
<para>
Default packet filter (aka <emphasis>firewall</emphasis> with <emphasis>NAT</emphasis>) from OpenBSD 3.0 (December 2001)
</para>
<para>
Replaced IPFilter, which had to be removed due to licensing issues
(which in turn lead to a <emphasis>license audit</emphasis> of the
entire OpenBSD source tree)
</para>
<para>
Based on new code by Daniel Hartmeier (June 2001 ->), since hacked on by several others
</para>
<para>
<emphasis>High performance</emphasis> (see <ulink url="http://www.benzedrine.cx/pf-paper.html"><citetitle>http://www.benzedrine.cx/pf-paper.html</citetitle></ulink>), <emphasis>low maintenance</emphasis> 
</para>
</chapter>

<chapter id="concepts">
<title>
Packet filter? Firewall? 
</title> 
<para>
Packet filter: 
</para>
<itemizedlist>
<listitem>
<para>
Kernel level code (module + admin software) 
which determines network packets' paths
</para>
<para>'the world consists of packets, protocols,
connections and ports'</para>
</listitem>
<listitem>
<para>
Important feature: Stopping undesirable traffic, 'firewall'
</para>
<para>A flexible <emphasis>tool</emphasis>, for <emphasis>taking control</emphasis> of your network traffic</para>
</listitem>
</itemizedlist>
<para></para>
</chapter>
<chapter id="NAT">
<title>
NAT?
</title>
<para>
Network Address Translation
</para>
<itemizedlist>
<listitem>
<para><emphasis>Why:</emphasis> Internet commercialization (early 1990s)</para>
</listitem>
<listitem>
<para>
Predicted shortage of official IP-adresses 
</para>
</listitem>
<listitem>
<para>
Long term solution: IPv6 (128 bit addresses)
</para>
</listitem>
<listitem>
<para>
Shorter term solutions: translation logic (RFC 1631, 1994) and 
private (non routable) adresses (RFC 1918, 1996)
</para>
</listitem>
</itemizedlist>
<para>
When official addresses are not
</para>
<itemizedlist>
<listitem>
<para>
available
</para>
</listitem>
<listitem>
<para>
practical
</para>
</listitem>
</itemizedlist>
</chapter>

<chapter id="pftoday">
<title>
PF today
</title>
<para>
Packet filter with
</para>
<itemizedlist>
<listitem>
<para>
Filtrering on protocol, port, packet type, address, operating system
</para>
</listitem>
<listitem>
<para>
Redirection (to other port, local daemon, other machine etc)
</para>
</listitem>
<listitem>
<para>
NAT
</para>
</listitem>
<listitem>
<para>
traffic shaping (altq)
</para>
</listitem>
<listitem>
<para>
Human readable configuration
</para>
</listitem>
</itemizedlist>
<para>
In the base systems of OpenBSD, FreeBSD, NetBSD and DragonFlyBSD
</para>
</chapter>

<chapter id="simplestconfig">
<title>
Simplest possible setup 
</title>
<para>
<filename>/etc/rc.conf[.local]</filename>
</para>
<programlisting>
pf=YES                # enable pf
pf_rules=/etc/pf.conf # specify which file contains your rules
</programlisting>
<para>
enable with
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -e</userinput>
</screen>
<para>
<emphasis>Note</emphasis> Rebooting loads the <filename>rc</filename> script's default rule set
</para>

</chapter>

<!-- insert other BSDs basic config here -->
<chapter id="simplestfreebsd">
<title>
Simplest possible setup (FreeBSD)
</title>
<para>
<filename>/etc/rc.conf</filename>
</para>
<programlisting>
pf_enable="YES"                 # Enable PF (load module if required)
pf_rules="/etc/pf.conf"         # rules definition file for pf
pf_flags=""                     # additional flags for pfctl startup
pflog_enable="YES"              # start pflogd(8)
pflog_logfile="/var/log/pflog"  # where pflogd should store the logfile
pflog_flags=""                  # additional flags for pflogd startup
</programlisting>
<para>
Fortunately most of these are the defaults, you need only add
</para>
<programlisting>
pf_enable="YES"                 # Enable PF (load module if required)
pflog_enable="YES"              # start pflogd(8)
</programlisting>
<para>
enable with
</para>
<screen>
<computeroutput>FreeBSD:~$</computeroutput> <userinput>sudo pfctl -ef /etc/pf.conf</userinput>
</screen>
<para>or</para>
<para>
<computeroutput>$</computeroutput> <userinput><application>sudo</application> <application>/etc/rc.d/pf</application> start</userinput>
</para>

</chapter>

<chapter id="netbsdbasics">
<title>
Simplest possible setup (NetBSD)
</title>
<para>
NetBSD from 2.0 - available via packages <filename>security/pflkm</filename>.  
</para>
<para>
From NetBSD 3.0 on, PF is in the base system
</para>
<para>
Kernel configuration file:
</para>
<programlisting>
pseudo-device  pf		# PF packet filter
pseudo-device  pflog		# PF log interface
</programlisting>
<para>
<filename>/etc/rc.conf</filename>:
</para>
<programlisting>
pf=YES 
pflogd=YES
</programlisting>
<screen>
<computeroutput>NetBSD$</computeroutput> <userinput><application>sudo</application> <application>modload</application> /usr/lkm/pf.o</userinput>; 
</screen>
<para>
or
</para>
<screen>
<computeroutput>NetBSD$</computeroutput> <userinput><application>sudo</application> <application>pfctl</application> -e</userinput>
</screen>
<para>
<screen><computeroutput>NetBSD$</computeroutput> <userinput><application>sudo</application> /etc/rc.d/pf start</userinput> ; <userinput><application>sudo</application> /etc/rc.d/pflogd start</userinput>
</screen></para>
<para>
in <filename>/etc/lkm.conf</filename>:
</para>
<programlisting>
/usr/lkm/pf.o - - - - AFTERMOUNT
</programlisting>
</chapter>

<chapter id=minimal-ruleset>
<title>First rule set - single machine</title>
<para>
<filename>/etc/pf.conf</filename>
</para>

<programlisting>
block in all
pass out all keep state
</programlisting>
    <para><emphasis>OpenBSD 4.1 onwards:</emphasis></para>
<programlisting>
# minimal rule set, OpenBSD 4.1 and newer keeps state by default
block in all
pass out all
</programlisting>

<para>
enable with
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -ef /etc/pf.conf</userinput>
</screen>
</chapter>
  <chapter id="test.rules.1">
    <title>Testing your first rule set</title>
    <para>
<emphasis>You need to test your work</emphasis>
</para>
    <itemizedlist>
      <listitem>
	<para>
Name resolution: <computeroutput>$ </computeroutput><userinput>host openbsd.org</userinput> should work
</para>
      </listitem>
      <listitem>
	<para>
Remote login:  <computeroutput>$ </computeroutput><userinput>ssh myotherbox.com</userinput> should work
</para>
      </listitem>
      <listitem>
	<para>
Surf the web: <computeroutput>$ </computeroutput><userinput>lynx http://www.openbsd.org</userinput> should work
</para>
      </listitem>
    </itemizedlist>
    <para>Connections from you to elsewhere should work</para>
    <para>Connections from elsewhere to you should <emphasis>NOT</emphasis> work</para>
  </chapter>
<chapter id="stricter">
<title>
Slightly stricter
</title>
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
udp_services = "{ domain }"

block all
pass out proto tcp to any port $tcp_services 
pass proto udp to any port $udp_services 
</programlisting>
    <para>
<emphasis>NOTE: </emphasis>Default to deny, enable only the stuff we need
</para>
<para>
- load your new rules
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -f /etc/pf.conf</userinput>
</screen>
<para>
for syntax check only:
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -nf /etc/pf.conf</userinput>
</screen>
<para>
Note: only valid rule sets load, flushing rarely makes sense
</para>
</chapter>

  <chapter id="test.rules.2">
    <title>Testing your rule set</title>
    <para>
<emphasis>You need to test your work, again</emphasis>
</para>
    <itemizedlist>
      <listitem>
	<para>
Name resolution: <computeroutput>$ </computeroutput><userinput>host netbsd.org</userinput> should work (different domain, don't let the cache fool you)
</para>
      </listitem>
      <listitem>
	<para>
Remote login:  <computeroutput>$ </computeroutput><userinput>ssh myotherbox.com</userinput> should work
</para>
      </listitem>
      <listitem>
	<para>
Surf the web: <computeroutput>$ </computeroutput><userinput>lynx http://www.openbsd.org</userinput> should work
</para>
      </listitem>
    </itemizedlist>
    <para>Connections from you to <userinput>ssh, smtp, domain, www, pop3, auth, pop3s</userinput> elsewhere should work</para>
    <para>All other connections from you should FAIL</para>
    <para>Connections from elsewhere to you should <emphasis>NOT</emphasis> work</para>
  </chapter>


<chapter id="pfctlstats">
<title>
Statistics from pfctl
</title>
<para>
</para>
<screen>
<computeroutput>peter@skapet:~$</computeroutput> <userinput>sudo pfctl -s info</userinput>
<computeroutput>Status: Enabled for 17 days 00:24:58          Debug: Urgent

Interface Stats for ep0               IPv4             IPv6
  Bytes In                      9257508558                0
  Bytes Out                      551145119              352
  Packets In
    Passed                         7004355                0
    Blocked                          18975                0
  Packets Out
    Passed                         5222502                3
    Blocked                             65                2

State Table                          Total             Rate
  current entries                       15               
  searches                        19620603           13.3/s
  inserts                           173104            0.1/s
  removals                          173089            0.1/s
Counters
  match                             196723            0.1/s
  bad-offset                             0            0.0/s
  fragment                              22            0.0/s
  short                                  0            0.0/s
  normalize                              0            0.0/s
  memory                                 0            0.0/s
  bad-timestamp                          0            0.0/s
  congestion                             0            0.0/s
  ip-option                             28            0.0/s
  proto-cksum                          325            0.0/s
  state-mismatch                       983            0.0/s
  state-insert                           0            0.0/s
  state-limit                            0            0.0/s
  src-limit                             26            0.0/s
  synproxy                               0            0.0/s</computeroutput>
</screen>

</chapter>

<chapter id="gwpitfalls">
<title>
A gateway 
</title>
<para>
Single machine: <emphasis>Me vs the network</emphasis>
</para>
    <itemizedlist>
      <listitem>
<para>
<userinput>in</userinput> from the Internet to me
</para>
      </listitem>
      <listitem>
<para>
<userinput>out</userinput> from me to the Internet
</para>
      </listitem>
    </itemizedlist>
<para>
Gateway: <emphasis>I decide what passes through me</emphasis>
</para>
    <itemizedlist> 
      <listitem>
<para>
<userinput>in</userinput> from the one or more networks to me
</para>
      </listitem>
      <listitem>
<para>
<userinput>out</userinput> from me one or more networks
</para>
      </listitem>
     <listitem>
<para>
<emphasis>hey, there's a network behind you!</emphasis>
</para>
      </listitem>
    </itemizedlist>

</chapter>
<chapter id="gwpitfalls2">
<title>
Pitfalls: in, out, on
</title>
<para>
If you write
</para>
<programlisting>
pass in inet proto tcp on re1 from re1:network to re0:network \
     port $ports keep state
</programlisting>
<para>
then you also need
</para>
<programlisting>
pass out inet proto tcp on re0 from re1:network to re0:network \
     port $ports keep state
</programlisting>
<para>
but do you actually mean
</para>
<programlisting>
pass inet proto tcp from re1:network to any port $ports keep state
</programlisting>
</chapter>
<chapter id="whatsyourlocalnet">
<title>
What is your local network, anyway?
</title>
<para>
<userinput>interface:network</userinput> - the <emphasis>network</emphasis> connected to <emphasis>interface</emphasis>
</para>
<para>
Your local net could be
</para>
<programlisting>
localnet = $int_if:network
</programlisting>
<para>
or network as <userinput>192.168.100.0/24</userinput>, or
<userinput>fec0:dead:beef::/64</userinput> or a list of networks -
</para>
<para>
sample filtering rule:
</para>
<programlisting>
pass inet proto tcp from $localnet to any port $ports keep state
</programlisting>


</chapter>
<chapter id="basicgw">
<title>
Simple gateway (with NAT if you need to)
</title>
<para>
Enable gatewaying
</para>
<para>
<emphasis>For IPv4</emphasis>: <computeroutput>#</computeroutput> <userinput>sysctl net.inet.ip.forwarding=1</userinput>
</para>
<para>
<emphasis>For IPv6</emphasis>: <computeroutput>#</computeroutput> <userinput>sysctl net.inet6.ip6.forwarding=1</userinput>
</para>
<para>
Make permanent, <filename>/etc/sysctl.conf</filename>
</para>
<programlisting>
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
</programlisting>
<para>
On FreeBSD, <filename>/etc/rc.conf</filename>
</para>
<programlisting>
gateway_enable="YES" #for ipv4
ipv6_gateway_enable="YES" #for ipv6
</programlisting>
</chapter>

<chapter id="basicgw2">
<title>
Simple gateway with NAT (cont'd.)
</title>
<para>
Check interface status with <userinput>ifconfig -a</userinput>
</para>
<screen>$ ifconfig -a
lo0: flags=8049&lt;UP,LOOPBACK,RUNNING,MULTICAST&gt; mtu 33208
        groups: lo
        inet 127.0.0.1 netmask 0xff000000
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x5
xl0: flags=8843&lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&gt; mtu 1500
        lladdr 00:50:da:21:e4:af
        groups: egress
        media: Ethernet autoselect (100baseTX full-duplex)
        status: active
        inet 213.187.179.198 netmask 0xfffffffc broadcast 213.187.179.199
        inet6 fe80::250:daff:fe21:e4af%xl0 prefixlen 64 scopeid 0x2
xl1: flags=8843&lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&gt; mtu 1500
        lladdr 00:50:da:3f:b2:86
        media: Ethernet autoselect (100baseTX full-duplex)
        status: active
        inet 192.168.103.1 netmask 0xffffff00 broadcast 192.168.103.255
        inet6 fe80::250:daff:fe3f:b286%xl1 prefixlen 64 scopeid 0x3
enc0: flags=0&lt;&gt; mtu 1536
pflog0: flags=141&lt;UP,RUNNING,PROMISC&gt; mtu 33208
        groups: pflog
</screen>
</chapter>

<chapter id="basicgw2b">
<title>
Simple gateway with NAT (cont'd.)
</title>
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
ext_if = "re0" # macro for external interface - use tun0 for PPPoE
int_if = "re1" # macro for internal interface
# ext_if IP address is (may be) dynamic
nat on $ext_if from $localnet to any -&gt; ($ext_if) 
block all
pass inet proto tcp from { lo0, $int_if:network } to any keep state
</programlisting>
</chapter>

<chapter id="basicgw3">
<title>
Simple gateway with NAT (cont'd.)
</title>
<para>
or perhaps
</para>
<programlisting>
client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, \
             https, 446, cvspserver, 2628, 5999, 8000, 8080 }"
udp_services = "{ domain, ntp }"

pass quick inet proto { tcp, udp } to any port $udp_services keep state

pass inet proto tcp from $int_if:network to any port $client_out \
                flags S/SA keep state

pass in inet proto tcp from any to any port ssh
</programlisting>
<para>
Rule evaluations is top to bottom, <emphasis>last</emphasis> matching rule wins.  
</para>
<para>
The <emphasis>quick</emphasis> keyword exits rule evaluation when current rule matches (quick rule always wins)
</para>
</chapter>

  <chapter id="test.rules.basicgateway">
    <title>Testing your rule set</title>
    <para>
<emphasis>You need to test your work, again</emphasis>
</para>
    <itemizedlist>
      <listitem>
	<para>
Name resolution: <computeroutput>$ </computeroutput><userinput>host freebsd.org</userinput> should work from the gateway and any host in your local net (check a different domain, don't let the cache fool you)
</para>
      </listitem>
      <listitem>
	<para>
Remote login:  <computeroutput>$ </computeroutput><userinput>ssh myotherbox.com</userinput> should work from the gateway and any host in your local net
</para>
      </listitem>
      <listitem>
	<para>
Surf the web: <computeroutput>$ </computeroutput><userinput>lynx http://www.openbsd.org</userinput> should work from the gateway and any host in your local net
</para>
      </listitem>
    </itemizedlist>
    <para>Connections from your net to <userinput>$client_out</userinput> elsewhere should work</para>
    <para>All other connections from your net should FAIL</para>
    <para>Connections from elsewhere to your net should <emphasis>NOT</emphasis> work</para>
  </chapter>

  <chapter id="hostsanddomains">
    <title>Domain names and host names?</title>
    <para>
Yes, you can use <userinput>pass from self to myotherbox.mydomain.com</userinput>, but - 
</para>
    <para>Your rules will then be valid only after you have name resolution up and running</para>
    <para>Possible workaraound: load default rule set, run script from <filename>rc.local</filename> to check DNS, then load real rule set</para>
  </chapter>

<chapter id="ftpproblem">
<title>
That old and sad FTP thing
</title>
<para>
Old and weird protocol (older than TCP/IP, topic of &gt; 50 RFCs!)
</para>
<itemizedlist>
<listitem>
<para>
Passwords transferred as clear text (no encryption)
</para>
</listitem>
<listitem>
<para>
Uses at least two connections
</para>
</listitem>
<listitem>
<para>
Data transferred on randomly chosen port
</para>
</listitem>
</itemizedlist>
<para>
Recommendation: use something else
</para>
</chapter>

<chapter id="ftpnewproxy">
<title>
If we have to: <application>ftp-proxy</application> with redirection
</title>
<para>
In the base system, load the daemon if you need it
</para>
<para>
<filename>/etc/rc.conf[.local]</filename>
</para>
<programlisting>
ftpproxy_flags=""
</programlisting>
<para>
<filename>/etc/pf.conf</filename>
</para>
<para>
NAT section anchors
</para>
<programlisting>
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
</programlisting>
<para>
the redirection 
</para>
<programlisting>
rdr pass on $int_if proto tcp from any to any port ftp -&gt; 127.0.0.1 \
         port 8021
</programlisting>
<para>
in your filtering section
</para>
<programlisting>
anchor "ftp-proxy/*"
</programlisting>
<programlisting>
pass out proto tcp from $proxy to any port 21 keep state
</programlisting>
</chapter>

<chapter id="ftp-proxy">
<title>
This will become historical: pre-3.8 FTP proxies
</title>
<para>
ftp over nat: <application>ftp-proxy</application> (OpenBSD 3.8 and earlier <emphasis>equivalents</emphasis> such as NetBSD, FreeBSD pre-7.0)
</para>
<para>
<filename>/etc/inetd.conf</filename>
</para>
<programlisting>
127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy -n
</programlisting>
<para>
- restart inetd
</para>
<screen>
<computeroutput>FreeBSD+NetBSD$</computeroutput> <userinput>sudo /etc/rc.d/inetd restart</userinput>
</screen>
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
 rdr on $int_if proto tcp from any to any port ftp -&gt; 127.0.0.1 \
                port 8021
 # [...]
 pass in on $ext_if inet proto tcp from port ftp-data to ($ext_if) \
    user proxy flags S/SA keep state
</programlisting>
<para>
- load your new rules
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -f /etc/pf.conf</userinput>
</screen>
</chapter>

<chapter id="ftpsesame">
<title>
Other historical ftp solutions: ftpsesame, pftpx
</title>
<para>
For official addresses on the inside: <application>ftpsesame</application> (OpenBSD + others), fetchable from
</para>
<para>
<ulink url="http://www.sentia.org/projects/ftpsesame/">http://www.sentia.org/projects/ftpsesame/</ulink> (on FreeBSD: - <filename>ftp/ftpsesame</filename>)
</para>
<para>
configured via an anchor (sub ruleset), cut and paste from <userinput>man ftpsesame</userinput>
</para>
<para>
pftpx, the next generation ftp-proxy 
</para>
<para>
<ulink url="http://www.sentia.org/downloads/pftpx-0.8.tar.gz">http://www.sentia.org/downloads/pftpx-0.8.tar.gz</ulink>, (on FreeBSD - <filename>ftp/pftpx</filename>) cut and paste from <userinput>man pftpx</userinput>
</para>
</chapter>

<chapter id="tables">
<title>
Tables make your life easier
</title>
<programlisting>
table &lt;clients&gt; { 192.168.2.0/24, !192.168.2.5 }
</programlisting>
<para>
the file <filename>/etc/clients</filename>
</para>
<programlisting>
192.168.2.0/24
!192.168.2.5
</programlisting>
<para>
in <filename>/etc/pf.conf</filename>
<programlisting>
table &lt;clients&gt; persist file /etc/clients

pass inet proto tcp from &lt;clients&gt; to any port $client_out 
</programlisting>
</para>
</chapter>

<chapter id="tablescommands">
<title>
Table commands 
</title>
<para>
Command line tables manipulation:
</para>
<para>
Add a table entry
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -t clients -T add 192.168.1/16</userinput>
</screen>
<para>
Delete a table entry
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -t clients -T delete 192.168.1.116</userinput>
</screen>
<para>
Show table contents
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -t clients -T show &gt;/etc/clients</userinput>
</screen>
<para>
Replace table contents from a file
</para>
<screen>
<computeroutput>$</computeroutput> <userinput>sudo pfctl -t clients -T replace -f /etc/clients</userinput>
</screen>
<para>
Commonly used commands - likely scripting candidates 
</para>
<para>
<emphasis>Tip</emphasis>: look into cron(8) jobs
</para>
    <para>Worth noting: several apps including <application>dhcpd</application> and <application>bgpd</application> can interact with PF via tables</para>
</chapter>

  <chapter id="filter4services">
    <title>Filtering for services</title>
    <para>We introduce servers in the network</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="simple-network-with-servers.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
  </chapter>

  <chapter id="filter4services2">
    <title>Filtering for services (cont)</title>
    <para>The obvious macros</para>
    <programlisting>
webserver = "192.0.2.227"
webports = "{ http, https }"
emailserver = "192.0.2.225"
email = "{ smtp, pop3, imap, imap3, imaps, pop3s }"
nameservers = "{ 192.0.2.221, 192.0.2.223 }"
</programlisting>
    <para>
and rules that use them
</para>
    <programlisting>
pass proto tcp from any to $webserver port $webports synproxy state
pass proto tcp from any to $emailserver port $email synproxy state
pass log proto tcp from $emailserver to any port smtp synproxy state
pass inet proto { tcp, udp } from any to $nameservers port domain
</programlisting>
  </chapter>

<chapter id="spamdprep">
<title>
Giving spammers a hard time: you're not alone
</title>
<para>
Spammers are a pain. How do we deal?
</para>
<itemizedlist>
<listitem>
<para>
Spammers send <emphasis>large</emphasis> numbers of messages; you are probably not the first recipient
</para>
<para>
- &gt; Known spam senders (hijacked machines) are added to blacklists
</para>
</listitem>
<listitem>
<para>
Spammers tend not to obey RFCs (RFC1123, RFC2821/RFC5321)
</para>
<para>
- &gt; Greylisting (<ulink url="http://www.greylisting.org">www.greylisting.org</ulink>) - with 45n temporary error <emphasis>still</emphasis> works!
</para>
</listitem>
</itemizedlist>
</chapter>

<chapter id="spamdmore">
<title>
Giving spammers a hard time (cont'd)
</title>
<para>
<application>spamd</application>
</para>
<itemizedlist>
<listitem>
<para>
tarpit where black listed hosts get stuck - answers 1 byte at the time, tunable interval (-s option)
</para>
</listitem>
<listitem>
<para>
Grey-lists unknowns using 45n (temporary local error), well behaved ones are let through within a reasonable time
</para>
</listitem>
</itemizedlist>
<para>
Introduced in OpenBSD 3.3 (May 2003)
</para>
<para>
Since OpenBSD 4.1, <application>spamd</application> runs in greylisting mode by default
</para>
</chapter>

<chapter id="spamd">
<title>
Giving spammers a hard time: The rules
</title>
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
table &lt;spamd&gt; persist
table &lt;spamd-white&gt; persist
rdr pass on $ext_if inet proto tcp from &lt;spamd&gt; to \
  { $ext_if, $int_if:network } port smtp -&gt; 127.0.0.1 port 8025
rdr pass on $ext_if inet proto tcp from !&lt;spamd-white&gt; to \
  { $ext_if, $int_if:network } port smtp -&gt; 127.0.0.1 port 8025
</programlisting>
<para>
Essential data in the spamd and spamd-white tables
</para>
</chapter>

<chapter id="spamdconfig">
<title>
Setting up spamd
</title>
<para>
Edit <filename>spamd.conf</filename> to specify blacklists and whitelists
</para>
<programlisting>
all:\
:uatraps:whitelist:
</programlisting>
<programlisting>
uatraps:\
        :black:\
        :msg="SPAM. Your address %A has sent spam within the last 24 hours":\
        :method=http:\
        :file=www.openbsd.org/spamd/traplist.gz
</programlisting>
<programlisting>
whitelist:\
        :white:\
        :method=file:\
        :file=/var/mail/whitelist.txt
</programlisting>
</chapter>

<chapter id="spamdconfig.freebsd">
<title>
Setting up spamd - FreeBSD
</title>
<para>
On FreeBSD, <application>spamd</application> is a port,
<filename>mail/spamd/</filename>
</para>
<para>
Needs a <ulink
url="http://www.freebsd.org/cgi/man.cgi?query=fdescfs&amp;sektion=5">fdescfs(5)</ulink>
mounted on <filename>/dev/fd/</filename> (see the package message)
</para>

</chapter>

<chapter id="spamd.greylist">
    <title>Greylisting: See the RFC</title>
<para>
<emphasis>greylisting</emphasis>: you need to behave
</para>
<!-- RFC2821 superseded by RFC5321 -->
<para>
RFC5321 (Oct 2008, supersedes RFC2821), section 4.5.4.1, "Sending Strategy":
</para>
<blockquote><para>
   "In a typical system, the program that composes a message has some
    method for requesting immediate attention for a new piece of
    outgoing mail, while mail that cannot be transmitted immediately
    MUST be queued and periodically retried by the sender."
</para>
</blockquote>
<para>
and
</para>
<blockquote>
<para>
   "The sender MUST delay retrying a particular destination after one
    attempt has failed.  In general, the retry interval SHOULD be at
    least 30 minutes; however, more sophisticated and variable 
    strategies will be beneficial when the SMTP client can determine 
    the reason for non-delivery."
</para>
</blockquote>
<para>
RFC5321 goes on to state that
</para>
<blockquote>
<para>
   "Retries continue until the message is transmitted or the sender gives
    up; the give-up time generally needs to be at least 4-5 days."
</para>
</blockquote>
</chapter>

<chapter id="spamd.greylist2">
<title>
Greylisting: My admin told me not to talk to strangers
</title>
<para>
<emphasis>greylisting</emphasis>: a white lie
</para>
<para>
<emphasis>&ldquo;my admin told me not to talk to strangers&rdquo;</emphasis>
</para>
<para>
Well intended senders will come back within a reasonable time.
</para>
<para>
It's pure pedantry; false positives are rare.
</para>
<para>
Shifts the load back to the sender
</para>
</chapter>

<chapter id="spamdconfig.rcconf">
<title>
Setting up spamd
</title>
<para>
Enter spamd lines in <filename>rc.conf[.local]</filename>
</para>
<programlisting>
spamd_flags="-v -G 2:4:864" # for normal use: "" and see spamd-setup(8)
</programlisting>
<para>
NOTE: Greylisting is enabled by default. Use
<userinput>spamd_black</userinput> if you want to enable blacklist-only mode.
</para>
<para>
Maintenance handled with <application>spamd-setup</application>(8), fetches the lists you specified
</para>
<para>
Tables automatically updated, use <application>spamdb</application>(8)
</para>
<para>
In addition, you need rules to let legitimate email through
</para>
    <para>Other interesting options: <userinput>-s</userinput> # of seconds between bytes, <userinput>-w</userinput> window size # of bytes</para>
</chapter>

  <chapter id="spamdconfig.spamlogd">
    <title>Track real SMTP connections: spamdlogd</title>
    <para> </para>
    <programlisting>
emailserver = "192.0.2.225"
pass log proto tcp from any to $emailserver port $email synproxy state
pass log proto tcp from $emailserver to any port smtp synproxy state
</programlisting>
    <para>or log to separate pflog interface</para>
    <programlisting>pass log (to pflog1) proto tcp from any to $emailserver port $email
pass log (to pflog1) proto tcp from $emailserver to any port smtp</programlisting>
  </chapter>

<chapter id="spamdmore2">
<title>
Giving spammers a hard time (cont'd)
</title>
<para>
<application>spamd</application> in use
</para>
<para>
Typical log entries (with -v):
</para>
<programlisting>
Oct  2 19:55:05 delilah spamd[26905]: (GREY) 83.23.213.115: &lt;gilbert@keyholes.net&gt; -&gt; &lt;wkitp98zpu.fsf@datadok.no&gt; 
Oct  2 19:55:05 delilah spamd[26905]: 83.23.213.115: disconnected after 0 seconds.
Oct  2 19:55:05 delilah spamd[26905]: 83.23.213.115: connected (2/1)
Oct  2 19:55:06 delilah spamd[26905]: (GREY) 83.23.213.115: &lt;gilbert@keyholes.net&gt; -&gt; &lt;wkitp98zpu.fsf@datadok.no&gt;
Oct  2 19:55:06 delilah spamd[26905]: 83.23.213.115: disconnected after 1 seconds.
Oct  2 19:57:07 delilah spamd[26905]: (BLACK) 65.210.185.131: &lt;bounce-3C7E40A4B3@branch15.summer-bargainz.com&gt; -&gt; &lt;adm@dataped.no&gt;
Oct  2 19:58:50 delilah spamd[26905]: 65.210.185.131: From: Auto lnsurance Savings &lt;noreply@branch15.summer-bargainz.com&gt;
Oct  2 19:58:50 delilah spamd[26905]: 65.210.185.131: Subject: Start SAVlNG M0NEY on Auto lnsurance
Oct  2 19:58:50 delilah spamd[26905]: 65.210.185.131: To: adm@dataped.no
Oct  2 20:00:05 delilah spamd[26905]: 65.210.185.131: disconnected after 404 seconds. lists: spews1
Oct  2 20:03:48 delilah spamd[26905]: 222.240.6.118: connected (1/0)
Oct  2 20:03:48 delilah spamd[26905]: 222.240.6.118: disconnected after 0 seconds.
Oct  2 20:06:51 delilah spamd[26905]: 24.71.110.10: connected (1/1), lists: spews1
Oct  2 20:07:00 delilah spamd[26905]: 221.196.37.249: connected (2/1)
Oct  2 20:07:00 delilah spamd[26905]: 221.196.37.249: disconnected after 0 seconds.
Oct  2 20:07:12 delilah spamd[26905]: 24.71.110.10: disconnected after 21 seconds. lists: spews1
</programlisting>
<para>
Stops a lot of spam. Error rate depends on black lists used.
</para>
</chapter>

<chapter id="spamdbest">
<title>
Giving spammers a hard time (cont'd)
</title>
<para>
This used to be my best log:
</para>
<screen>Dec 11 23:57:24 delilah spamd[32048]: 69.6.40.26: connected (1/1), 
lists: spamhaus spews1 spews2
Dec 12 00:30:08 delilah spamd[32048]: 69.6.40.26: disconnected after 
1964 seconds. lists: spamhaus spews1 spews2
</screen>
<para>
A sender at wholesalebandwidth.com tried a total of 13 times from December 9th through
12th, giving up after one last attempt which lasted 32 minutes, 44 seconds without 
delivering a message.</para>
</chapter>
<chapter id="spamdbest2">
<title>
Giving spammers a hard time (cont'd)
</title>
<para>
But the record did not stand for long:
</para>
    <screen>
<computeroutput>peter@delilah:~$</computeroutput> <userinput>grep disconnected /var/log/spamd | awk '{print $9}' | sort -rn | uniq -c | head</userinput>
<computeroutput>   1 42673
   1 36099
   1 14714
   1 10170
   1 5966
   1 5878
   1 5866
   1 5845
   1 5709
   1 5707
</computeroutput>
</screen>
<para>
42673 seconds = almost twelve hours! (others have reported >60K seconds)
</para>
<screen>
Dec 21 14:22:44 delilah spamd[29949]: 85.152.224.147: connected (5/2)
Dec 21 14:22:46 delilah spamd[29949]: 85.152.224.147: connected (6/2)
Dec 21 14:22:47 delilah spamd[29949]: 85.152.224.147: disconnected
after 3 seconds.
Dec 22 02:13:59 delilah spamd[29949]: 85.152.224.147: disconnected
after 42673 seconds.
</screen>
</chapter>

<chapter id="spamd-connlengths">
<title>
Connection lengths
</title>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="left" fileref="connection-lengths.jpg" scale="55">
	</imageobject>
      </mediaobject>
    </informalfigure>
</chapter>
<chapter id="spamd.greytrapping">
<title>
Beating'em up some more: spamdb and greytrapping
</title>
<para>
<application>spamdb</application> database tool - essential for whitelisting, deleting, etc
</para>
<para>
<application>spamlogd</application> whitelist updater </para>
<para>
- Started and handled automatically from the RC scripts, easy to
forget the first time if you're doing this by hand and don't want to
reboot.
</para>

</chapter>
<chapter id="spamd.greytrapping.practice">
<title>
spamdb and greytrapping
</title>
<para>
Enter obviously bogus addresses into your blacklist with <application>spamdb</application> -T
</para>
<screen>
<computeroutput>peter@delilah:~$</computeroutput><userinput> spamdb -T -a "&lt;wkitp98zpu.fsf@datadok.no&gt;"</userinput>
</screen>
<para>
other useful options: <userinput>-t</userinput> enter as TRAPPED, <userinput>-d</userinput> delete entries
</para>

</chapter>
<chapter id="spamd.greytrapping.practice.result">
<title>
Greytrapping - the result
</title>
<para>
Sure enough, the spammers thought that address was just as usable as almost two years earlier:
</para>
<programlisting>
Nov  6 09:50:25 delilah spamd[23576]: 210.214.12.57: connected (1/0)
Nov  6 09:50:32 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov  6 09:50:40 delilah spamd[23576]: (GREY) 210.214.12.57: 
&lt;gilbert@keyholes.net&gt; -&gt; &lt;wkitp98zpu.fsf@datadok.no&gt;
Nov  6 09:50:40 delilah spamd[23576]: 210.214.12.57: disconnected 
after 15 seconds.
Nov  6 09:50:42 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov  6 09:50:45 delilah spamd[23576]: (GREY) 210.214.12.57: 
&lt;bounce-3C7E40A4B3@branch15.summer-bargainz.com&gt; -&gt; 
&lt;adm@dataped.no&gt;
Nov  6 09:50:45 delilah spamd[23576]: 210.214.12.57: disconnected 
after 13 seconds.
Nov  6 09:50:50 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov  6 09:51:00 delilah spamd[23576]: (GREY) 210.214.12.57: 
&lt;gilbert@keyholes.net&gt; -&gt; &lt;wkitp98zpu.fsf@datadok.no&gt;
Nov  6 09:51:00 delilah spamd[23576]: 210.214.12.57: disconnected 
after 18 seconds.
Nov  6 09:51:02 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov  6 09:51:02 delilah spamd[23576]: 210.214.12.57: disconnected 
after 12 seconds.
Nov  6 09:51:02 delilah spamd[23576]: 210.214.12.57: connected (2/0)
Nov  6 09:51:18 delilah spamd[23576]: (GREY) 210.214.12.57: 
&lt;gilbert@keyholes.net&gt; -&gt; &lt;wkitp98zpu.fsf@datadok.no&gt;
Nov  6 09:51:18 delilah spamd[23576]: 210.214.12.57: disconnected 
after 16 seconds.
Nov  6 09:51:18 delilah spamd[23576]: (GREY) 210.214.12.57: 
&lt;bounce-3C7E40A4B3@branch15.summer-bargainz.com&gt; -&gt; 
&lt;adm@dataped.no&gt;
Nov  6 09:51:18 delilah spamd[23576]: 210.214.12.57: disconnected 
after 16 seconds.
Nov  6 09:51:20 delilah spamd[23576]: 210.214.12.57: connected (1/1), 
lists: spamd-greytrap
Nov  6 09:51:23 delilah spamd[23576]: 210.214.12.57: connected (2/2), 
lists: spamd-greytrap
Nov  6 09:55:33 delilah spamd[23576]: (BLACK) 210.214.12.57: 
&lt;gilbert@keyholes.net&gt; -&gt; &lt;wkitp98zpu.fsf@datadok.no&gt;
Nov  6 09:55:34 delilah spamd[23576]: (BLACK) 210.214.12.57: 
&lt;bounce-3C7E40A4B3@branch15.summer-bargainz.com&gt; -&gt; 
&lt;adm@dataped.no&gt;
</programlisting>

</chapter>

  <chapter id="spamdsync">
    <title>Keeping several spamds in sync</title>
    <para>Starting with OpenBSD 4.1, you can sync greylists</para>
    <para><application>spamd </application>command line flags:</para>
    <para>-Y <emphasis>sync target</emphasis></para>
    <para>-y <emphasis>sync listener</emphasis></para>
    <para>on <emphasis>mainoffice-gw.example.com</emphasis></para>
    <screen>
-Y minorbranch-gw.example.com -y re0
</screen>
    <para>on <emphasis>minorbranch-gw.example.com</emphasis></para>
    <screen>
-Y mainoffice-gw.example.com -y re0
</screen>
  </chapter>

<chapter id="downsides-compensate">
<title>
Some people really do not get it
</title>
<para>
Greylisting inevitably means delay for the
<emphasis>initial</emphasis> message from a new correspondent.
</para>
<para>
Some sites are misconfigured; do not retry or retry way too fast (seconds)
</para>
<para>
Others have many outgoing MXes and random selection for retry
</para>
<para>
Some people are simply too impatient
</para>
</chapter>

<chapter id="downsides-compensate-fixit">
<title>
Fixing for the people who really do not get it
</title>
<para>
For the impatient:
</para>
<programlisting>
table &lt;localwhite&gt; file "/etc/mail/whitelist.txt"
</programlisting>
<para>
Disable <userinput>rdr</userinput> by putting this at the top of the
<userinput>rdr</userinput> block:
</para>
<programlisting>
no rdr proto tcp from &lt;localwhite&gt; to $mailservers port smtp
</programlisting>
<para>
Edit <filename>whitelist.txt</filename>, reload rule set or replace
<userinput> &lt;localwhite&gt;</userinput> table contents using
<application>pfctl</application>; all table options available.
</para>
</chapter>

<chapter id="spamdsum">
<title>
Giving spammers a hard time: Conclusion
</title>
<para>
Summing up:
</para>
<itemizedlist>
<listitem>
<para>
High precision
</para>
</listitem>
<listitem>
<para>
Good effect, minimal load
</para>
</listitem>
<listitem>
<para>
Blacklisting is never better than poorest data source used
</para>
<para>
We ended up using Bob Beck's traplist (greytrapping generated) at <ulink url="http://www.openbsd.org/spamd/traplist.gz ">http://www.openbsd.org/spamd/traplist.gz</ulink> - as far as we know no false positives.  (<ulink url="hosts-in-uatraps.jpg">graph</ulink>)
</para>
</listitem>
<listitem>
<para>
Prime example: <ulink
url="http://marc.info/?l=openbsd-misc&amp;m=116136841831550&amp;w=2">Steve
Williams' October 20th, 2006 message to the OpenBSD-misc mailing
list</ulink> - got rid of more than 95% of spam using <application>spamd</application> in pure greylisting mode
</para>
</listitem>
      <listitem>
	<para>Greytrapping is fun and effective: See <ulink url="http:/bsdly.blogspot.com/">bsdly.blogspot.com</ulink></para>
      </listitem>
</itemizedlist>
</chapter>


<chapter id="bruteforce">
<title>Turning away the brutes</title>
<para>
You have all seen this:
</para>
<programlisting>
Sep 26 03:12:34 skapet sshd[25771]: Failed password for root from 
200.72.41.31 port 40992 ssh2
Sep 26 03:12:34 skapet sshd[5279]: Failed password for root from 
200.72.41.31 port 40992 ssh2
Sep 26 03:12:35 skapet sshd[5279]: Received disconnect from 
200.72.41.31: 11: Bye Bye
Sep 26 03:12:44 skapet sshd[29635]: Invalid user admin from 
200.72.41.31
Sep 26 03:12:44 skapet sshd[24703]: input_userauth_request: 
invalid user admin
Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user 
admin from 200.72.41.31 port 41484 ssh2
Sep 26 03:12:44 skapet sshd[29635]: Failed password for invalid user 
admin from 200.72.41.31 port 41484 ssh2
Sep 26 03:12:45 skapet sshd[24703]: Connection closed by 200.72.41.31
Sep 26 03:13:10 skapet sshd[11459]: Failed password for root from 
200.72.41.31 port 43344 ssh2
</programlisting>

</chapter>

<chapter id="bruteforcerules">
<title>Turning away the brutes: The rules</title>
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
table &lt;bruteforce&gt persist

block quick from &lt;bruteforce&gt;

pass inet proto tcp from any to $int_if:network port $tcp_services \
        flags S/SA keep state \
	(max-src-conn 100, max-src-conn-rate 15/5, \
         overload &lt;bruteforce&gt; flush global)
</programlisting>
<para>
<firstterm>max-src-conn</firstterm>: # of connections from one host
</para>
<para>
<firstterm>max-src-conn-rate</firstterm>: rate of new
connections: 15 connections per 5 seconds.
</para>
<para>
<firstterm>overload</firstterm>
<computeroutput>&lt;bruteforce&gt;</computeroutput>: offenders go to the blocked table
</para>
<para>
 <firstterm>flush</firstterm> <firstterm>global</firstterm> : kill all connections
</para>
</chapter>

<chapter id="bruteforcetoo">
<title>Turning away the brutes (cont'd)</title>

<para>
Tighten a bit for <application>ssh</application>, differentiate:
</para> 
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
table &lt;bruteforce&gt persist

block quick from &lt;bruteforce&gt;

# tighter for ssh
pass quick proto tcp from any to any port ssh \
        flags S/SA keep state \
        (max-src-conn 15, max-src-conn-rate 5/3, \
        overload &lt;bruteforce&gt; flush global)

pass inet proto tcp from any to $int_if:network port $tcp_services \
        flags S/SA keep state \
	(max-src-conn 100, max-src-conn-rate 15/5, \
         overload &lt;bruteforce&gt; flush global)
</programlisting>
</chapter>

<chapter id="bruteforcethree">
<title>Turning away the brutes (cont'd)</title>

<para>
You may not need to <userinput>block</userinput> all of your <userinput>overload</userinput>ers
</para> 
<para>
Eg mail or web service - 
</para>
    <itemizedlist>
      <listitem>
	<para>
	put overloaders in a minimal-bandwidth queue (ALTQ)
	</para>
      </listitem>
      <listitem>
	<para>
        rdr overloaders to specific site
	</para>
      </listitem>
    </itemizedlist>
</chapter>

<chapter id="expire-pfctl">
<title>
Expiring table entries with <application>pfctl</application>
</title>
<para>
These tables grow; waste memory
</para>
<para>
Table contents could become less useful over time (DHCP leases expire, etc)
</para>
<para> 
In <emphasis>OpenBSD 4.1 and newer</emphasis>, <application>pfctl</application> can expire table entries:
</para>
<screen>
# pfctl -t bruteforce -T expire 86400
</screen>
</chapter>

<chapter id="expiretable">
<title><application>expiretable</application> tidies your tables</title>
<para>
Henrik Gustafsson's <application>expiretable</application>
</para>
<para>
Remove <userinput>&lt;bruteforce&gt;</userinput> table entries older
than 24 hours - add to <filename>/etc/rc.local</filename>:
</para>
<programlisting>
/usr/local/sbin/expiretable -v -d -t 24h bruteforce
</programlisting>
<para>
Get it from ports/packages or <ulink
url="http://expiretable.fnord.se/">http://expiretable.fnord.se/</ulink>
</para>
</chapter>

  <chapter id="advanced.statetracking">
    <title>Advanced state tracking</title>
    <para>
	<userinput>source-track rule</userinput> - your limits apply per rule
</para>
<para>
 vs 
</para>
<para><userinput>source-track global</userinput> this rule counts towards the global values</para> 
  </chapter>

  <chapter id="advanced.statetracking.floods">
    <title>State tracking (cont)</title>
    <para>
Prevent floods: 
</para>
<programlisting>
pass inet proto tcp from any to $webserver port www \
        flags S/SA keep state \
	(max-src-conn-rate 15/5, \
         max-src-nodes 250, max-src-states 100, source-track rule)
</programlisting>
<para>
	<userinput>max-src-nodes</userinput>: number of distinct hosts (IP addresses) allowed to have states
</para>
<para>
	<userinput>max-src-states</userinput>: number of states allowed per host
</para>
<para>
Others simply dropped
</para>

  </chapter>
  <chapter id="filterwithdmz">
    <title>Physical Separation: The DMZ </title>
    <para>Put the servers on a separate subnet</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="DMZ-network.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
  </chapter>

  <chapter id="filterwithdmz2">
    <title>DMZ ruleset</title>
    <para>How much damage does this do to your rule set?</para>
    <para><emphasis>Not a lot, actually</emphasis></para>
    <para>You may need to edit your <userinput>$webserver</userinput>, <userinput>$emailserver</userinput>, 
<userinput>$nameservers</userinput>, if their addresses change</para>
  </chapter>

  <chapter id="filterwithdmz3">
    <title>DMZ ruleset: tighten</title>
    <para>You may want to allow only what's needed:</para>
    <programlisting>
pass in on $ext_if proto { tcp, udp } from any to $nameservers \
     port domain
pass in on $int_if proto { tcp, udp } from $localnet to $nameservers \
     port domain
pass out on $dmz_if proto { tcp, udp } from any to $nameservers \
     port domain
pass in on $ext_if proto tcp from any to $webserver port $webports
pass in on $int_if proto tcp from $localnet to $webserver \
     port $webports
pass out on $dmz_if proto tcp from any to $webserver port $webports
pass in log on $ext_if proto tcp from any to $mailserver port smtp
pass in log on $int_if proto tcp from $localnet to $mailserver \
     port $email
pass out log on $dmz_if proto tcp from any to $mailserver port smtp
pass in on $dmz_if from $mailserver to any port smtp
pass out log on $ext_if proto tcp from $mailserver to any port smtp
</programlisting>
  </chapter>

  <chapter id="anchors-intro">
    <title>Anchors</title>
    <para>Named sub-rulesets</para>
    <para>Used by several apps for inserting on the fly rules
     (<application>ftp-proxy</application>, <application>relayd</application>, others)</para>
    <para>useful for grouping related rules</para>
    <para>yes, it's technically possible to populate anchors from the command line:</para>
    <screen># echo "block drop all" | pfctl -a baddies -f -</screen>
  </chapter>

  <chapter id="anchors-intro1">
    <title>Anchors: commands</title>
    <para>Load from file</para>
    <screen># pfctl -a baddies -f /etc/anchor-baddies</screen>
    <para>List rules in an anchor</para>
    <screen># pfctl -a baddies -s rules</screen>
  </chapter>

  <chapter id="anchors-ruleset">
    <title>Anchors: ruleset</title>
    <para>Include from file</para>
    <para>In your <filename>pf.conf</filename></para>
    <screen>anchor ssh-good
     load anchor ssh-good from "/etc/anchor-ssh-good"</screen>
    <para><filename>/etc/anchor-ssh-good</filename></para>
    <screen>table &lt;sshbuddies&gt; file "/etc/sshbuddies"
     pass inet proto tcp from &lt;sshbuddies&gt; to any port ssh</screen>
    <para><filename>/etc/sshbuddies</filename></para>
    <screen>192.168.103.84
10.11.12.13</screen>

  </chapter>

  <chapter id="anchors-structure">
    <title>Anchors: alternative structure</title>
    <para>alternative structure: common criteria</para>
<screen>anchor "dmz" on $dmz_if {
        pass out proto { tcp udp } to $nameservers port domain
	pass out proto tcp to $webservers port { www https }
	pass out proto tcp to $mailserver port smtp
	pass in log (all, to pflog1) in proto tcp from $mailserver \
                to any port smtp 
	}</screen>
  </chapter>

  <chapter id="anchors-structure1">
    <title>Anchors - tag and quick</title>
    <para><userinput>quick</userinput> with tags</para>
<screen>anchor "dmz" on $dmz_if {
        pass out proto { tcp udp } to $nameservers port domain tag GOOD
	pass out proto tcp to $webservers port { www https } tag GOOD
	pass out proto tcp to $mailserver port smtp tag GOOD
	pass in log (all, to pflog1) in proto tcp from $mailserver 
                to any port smtp tag GOOD
	block log quick ! tagged GOOD
	}</screen>
  </chapter>

  <chapter id="include-file">
    <title>Including files</title>
    <para>Starting with 4.3, you can split <filename>pf.conf</filename> into parts and include subsets:</para>
    <screen>include /etc/pf/subseta.rules
include /etc/pf/subsetb.rules</screen>
  </chapter>
<chapter id="wireless.background">
<title>
Wireless networks: background
</title>
<para>
"we're not using wires anymore" -- IEEE 802.11 security measures:
</para>
<itemizedlist>
<listitem>
<para>
First try: <emphasis>Wired Equivalent Privacy (WEP)</emphasis>
</para>
<para>
weak link level encryption - broken; deters naive attackers
</para>
</listitem>
<listitem>
<para>
Second try: <emphasis>WiFi Protected Access (WPA)</emphasis>
</para>
<para>
Flexible and complex - better on paper; "constantly improving"; support varies (supported in OpenBSD 4.4)
</para>
</listitem>
</itemizedlist>
    <para>MAC address filtering: not really useful, but if you want to, see <filename>brconfig</filename></para>
<para>
- &gt; you need SSH &amp; SSL
</para>

<para>See eg <ulink url="http://www.kjhole.com/Standards/WiFi/WiFiDownloads.html">www.kjhole.com</ulink> for references. </para>
</chapter>

<chapter id="wireless.simple">
<title>
Wireless networks made easy
</title>
<para>Check your dmesg</para>
<screen>
ath0 at pci1 dev 4 function 0 "Atheros AR5212" rev 0x01: irq 11
ath0: AR5212 5.6 phy 4.1 rf5111 1.7 rf2111 2.3, ETSI1W, address 
00:0d:88:c8:a7:c4
</screen>
<para>
 Access point, OpenBSD <filename>/etc/hostname.ath0</filename>:
</para>
<programlisting>
up media autoselect mediaopt hostap mode 11b chan 6 nwid unwiredbsd \
 nwkey 0x1deadbeef9
inet 10.168.103.1
</programlisting>
<para>From OpenBSD 4.4 onwards, we have WPA</para>
</chapter>
  <chapter id="wpasetup">
    <title>Wireless networks: WPA setup</title>
<para>From OpenBSD 4.4 onwards, we have WPA.</para>
    <para>For wpa keys, use <filename>wpa-psk</filename>:</para>
    <screen>$ wpa-psk unwiredbsd mylongpassphase
0x7579c38e59faaa3b64bd8372e94f74fe7ae2e4e91af154c956a9bfd0240ac9d0
</screen>
    <para>A WPA access point config:</para>
    <programlisting>
up media autoselect mediaopt hostap mode 11b chan 6 nwid unwiredbsd \
 wpapsk $(wpa-psk unwiredbsd mylongpassphase)
</programlisting>
  </chapter>
<chapter id="wireless.simple.client">
<title>
Wireless networks made easy (cont'd)
</title>
    <para>
Client:
</para>
    <screen>
$ sudo ifconfig ath0 up mode 11b chan 11 nwid unwiredbsd nwkey 0x1deadbeef9
$ sudo dhclient ath0
DHCPREQUEST on ath0 to 255.255.255.255 port 67
DHCPREQUEST on ath0 to 255.255.255.255 port 67
DHCPACK from 10.50.90.1
bound to 10.50.90.11 -- renewal in 1800 seconds.
</screen>
<para>
Make permanent with <filename>/etc/hostname.ath0</filename>
</para>
<programlisting>
up media autoselect mode 11b chan 6 nwid unwiredbsd nwkey 0x1deadbeef9
dhcp
</programlisting>
    <para>WPA pre-shared</para>
    <programlisting>
up media autoselect mode 11b chan 6 nwid unwiredbsd \ 
wpapsk $(wpa-psk unwiredbsd mylongpassphase)
</programlisting>
</chapter>

<chapter id="wireless.simple.firewall">
<title>
Wireless networks made easy (cont'd)
</title>
<para>
Either <userinput>$int_if</userinput> is your wireless interface, or in <filename>/etc/pf.conf</filename>, add:
</para>
    <programlisting>
air_if = "ath0"
</programlisting>
    <para>and 
</para>
<programlisting>
nat on $ext_if from $air_if:network to any -> ($ext_if) static-port
</programlisting>
<para>Similar for ftp-proxy config, and include
<userinput>$air_if</userinput> in your pass rules.
</para>

</chapter>

<chapter id="authpf">
<title>
<application>authpf</application>: per user rules
</title>
<para>
<application>authpf</application> is a <emphasis>non-interactive</emphasis> user shell.
</para>
<itemizedlist>
<listitem>
<para>
Authenticates users using any <application>ssh</application> supported method
</para>
</listitem>
<listitem>
<para>
After authentication, user's IP address is added to the
<userinput>&lt;authpf_users&gt;</userinput> table for general rules to apply; in addition,
per user and per user group rules are possible
</para>
</listitem>
<listitem>
<para>
Table entry destroyed when <application>ssh</application> session terminates; anchor updated
</para>
</listitem>
</itemizedlist>
<para>
Useful for wireless networks and wired alike.
</para>
</chapter>

  <chapter id="authpf.simple">
    <title>Basic authpf setup</title>
    <para>
You need the table
</para>
    <programlisting>
table &lt;authpf_users&gt; persist
</programlisting>
    <para>
plus these anchors
</para>
    <programlisting>
nat-anchor "authpf/*"
rdr-anchor "authpf/*"
binat-anchor "authpf/*"
anchor "authpf/*"
</programlisting>
  </chapter>

  <chapter id="authpf.simple2">
    <title>Basic authpf setup (cont)</title>
    <para>
Let users authenticate
</para>
    <programlisting>
pass quick on $int_if inet proto { tcp, udp } to $int_if port ssh
</programlisting>
    <para>
Other rules could just as easily go in <filename>authpf.rules</filename>
</para>
 <programlisting>
pass quick inet proto { tcp, udp } from &lt;authpf_users&gt; to \
     any port $udp_services
pass inet proto tcp from &lt;authpf_users&gt; to any port $client_out
</programlisting>
  </chapter>

  <chapter id="authpf.simple3">
    <title>Basic authpf setup (cont)</title>
    <para>
The macro <userinput>$user_ip</userinput> expands to logged-in user's IP address:
</para>
    <programlisting>
client_out = "{ ssh, domain, pop3, auth, nntp, http, https }"
udp_services = "{ domain, ntp }"
pass quick inet proto { tcp, udp } from $user_ip to any \
     port $udp_services
pass inet proto tcp from $user_ip to any port $client_out
</programlisting>
    <para>
  </chapter>

  <chapter id="authpf.simple4">
    <title>Per user rules</title>
    <para>
<filename>/etc/authpf/users/peter/authpf.rules</filename>
</para>
    <programlisting>
client_out = "{ domain, http, https }"
pass inet from $user_ip to 192.168.103.84 port 9000
pass quick inet proto { tcp, udp } from $user_ip to \
     any port $client_out	
</programlisting>
    <para>
<filename>/etc/authpf/users/chris/authpf.rules</filename>
</para>
    <programlisting>
pass from $user_ip os = "OpenBSD" to any
</programlisting>

  </chapter>


<chapter id="authpf.open.shut">
<title>
Wide open but actually shut
</title>
<para>
A wireless network open at network level.
</para>
<para>
Access only to authenticated users
</para>
<para>
Create an empty authpf config:
</para>
<para>
<computeroutput>#</computeroutput> <userinput>touch <filename>/etc/authpf/authpf.conf</filename></userinput>. 
</para>
</chapter>

<chapter id="vegard.authpf.pf.conf">
<title>
Open but shut: pf.conf
</title>

<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
ext_if = "re0"
int_if = "ath0"
auth_web="192.168.27.20"
dhcp_services = "{ bootps, bootpc }" # DHCP server + client
table &lt;authpf_users&gt; persist
rdr pass on $int_if proto tcp from ! &lt;authpf_users&gt; to any \
    port http -&gt; $auth_web
nat on $ext_if from $localnet to any -> ($ext_if)
nat-anchor "authpf/*"
rdr-anchor "authpf/*"
binat-anchor "authpf/*"
anchor "authpf/*"
pass quick on $int_if inet proto { tcp, udp } to $int_if \
     port dhcp_services
pass quick inet proto { tcp, udp } from $int_if:network to \
     any port domain
pass quick on $int_if inet proto { tcp, udp } to $int_if port ssh
</programlisting>
</chapter>

  <chapter id="addresspools">
    <title>Sharing the load: Address pools</title>
    <para>Your users have bookmarked your <userinput>$webserver</userinput>, load goes up.</para>
    <para>Solution: more servers and a redirection</para>
    <programlisting>
webpool = "{ 192.0.2.214, 192.0.2.215, 192.0.2.216, 192.0.2.217 }"

rdr on $ext_if from any to $webserver port $webports -> $webpool \
       round-robin sticky-address
</programlisting>
  </chapter>
  <chapter id="relayd">
    <title>relayd</title>
    <para>Problem: machines go down, rdr doesn't compensate.</para>
    <para><filename>relayd</filename> (pre-4.3: <filename>hoststated</filename>) detects host state (up/down) interacts with <emphasis>tables</emphasis>, adds/removes hosts</para>
    <para>Configured via <filename>pf.conf</filename> and <filename>relayd.conf</filename></para>
   <para>Introduced in OpenBSD 4.1 (renamed in 4.3), actively developed</para>
  </chapter>

  <chapter id="relayd.simpleconfig">
    <title>Basic relayd config</title>
    <para>
In your <filename>pf.conf</filename>
</para>
    <programlisting>
rdr-anchor "hoststated/*"
anchor "relayd/*"
</programlisting>
  </chapter>

<chapter id="relayd.simpleconfig2">
    <title>Basic relayd config (cont)</title>
    <para>
In your <filename>relayd.conf</filename>
</para>
    <programlisting>
web1="192.0.2.214"
web2="192.0.2.215"
web3="192.0.2.216"
web4="192.0.2.217"
webserver="192.0.2.227"
sorry_server="192.0.2.200"

interval 5 # check hosts every 5 seconds

table &lt;webpool&gt; { $web1, $web2, $web3, $web4, }
table &lt;sorry&gt { $sorry_server }

redirect "www" {
	 listen on $webserver port http 
	 forward to &lt;webpool&gt; check http "/status.html" code 200 timeout 300
	 forward to &lt;sorry&gt; timeout 300 check icmp 
}
</programlisting>
    <para>
enable with <filename>rc.conf.local</filename> entry
</para>
    <programlisting>
relayd_flags="" # for normal use: ""#
</programlisting>
  </chapter>

<chapter id="relayctl">
    <title>relayctl</title>
    <para><command>relayctl</command> for interactive <command>relayd</command> control</para>
    <screen>
$ <userinput>sudo relayctl show summary</userinput>
Type      Id    Name                            Avlblty Status
service    0    www                                     down
table      0    webpool                                 active (2 hosts up)
host       3    192.0.2.217                     0.00%   down
host       2    192.0.2.216                     100.00% up
host       1    192.0.2.215                     0.00%   down
host       0    192.0.2.214                     100.00% up
table      1    sorry                                   active (1 hosts up)
host       4    192.0.2.200                     100.00% up
</screen>
    <para>enable or disable hosts</para>
    <screen>$ sudo relayctl host disable 192.0.2.216</screen>
    <screen>$ sudo relayctl host enable 192.0.2.216</screen>
  </chapter>
<chapter id="backtosimplenat">
  <title>Filtering for services, the NAT version</title>
  <para>If routable addresses are not available, you</para>
    <itemizedlist>
      <listitem>
	<para>select an appropriate RFC1918 address range</para>
      </listitem>
      <listitem>
	<para>edit your <userinput>webserver</userinput>, <userinput>emailserver</userinput></para>
      </listitem>
      <listitem>
	<para>add appropriate redirections</para>
	<programlisting>
rdr on $ext_if proto tcp from any to $ext_if port \
       $webports -&gt; $webserver
rdr on $ext_if proto tcp from any to $ext_if port \
       $email -&gt; $emailserver
</programlisting>
      </listitem>
    </itemizedlist>
    <para>segment off your DMZ, introduce address pools</para>
</chapter>

<chapter id="rdr2servers">
<title>
Back to the single NATed network
</title>
<programlisting>
webserver = "192.168.2.7"
webports = "{ http, https }"
emailserver = "192.168.2.5"
email = "{ smtp, pop3, imap, imap3, imaps, pop3s }"

rdr on $ext_if proto tcp from any to $ext_if port \
       $webports -&gt; $webserver
rdr on $ext_if proto tcp from any to $ext_if port \
       $email -&gt; $emailserver

pass in on $ext_if proto tcp from any to $webserver port $webports \
   flags S/SA synproxy state
pass in on $ext_if proto tcp from any to $emailserver port $email \
   flags S/SA synproxy state
pass out on $ext_if proto tcp from $emailserver to any port smtp \
   flags S/SA synproxy state
</programlisting>
<para>
Works with or without a separate dmz, but - 
</para>
</chapter>

<chapter id="rdr2servers4localnet">
<title>
Single NAT, web &amp; mail server on the inside: from the inside
</title>
<para>
<emphasis role="strong">Problem:</emphasis> Traffic from the inside does not reach the
internal interface
</para>
<para>
<emphasis role="strong">Solutions:</emphasis> 
</para>
<itemizedlist>
<listitem>
<para>
' Split horizon' DNS, different answer for LAN and elsewhere
</para>
</listitem>
<listitem>
<para>
proxying, such as <application>nc</application> (NetCat)
</para>
</listitem>
<listitem>
<para>
Moving your servers to a separate DMZ
</para>
</listitem>
<listitem>
<para>
special case of redirection and NAT for the local net
</para>
</listitem>
</itemizedlist>
</chapter>

<chapter id="rdr2servers4localnetrules">
<title>
Single NAT, web &amp; mail server on the inside: from the inside
</title>
<para>
Add to the rule set:
</para>
<programlisting>
rdr on $int_if proto tcp from $int_if:network to $ext_if \
       port $webports -&gt; $webserver
rdr on $int_if proto tcp from $int_if:network to $ext_if \
       port $email -&gt; $emailserver
no nat on $int_if proto tcp from $int_if to $int_if:network
nat on $int_if proto tcp from $int_if:network to $webserver \
       port $webports -&gt; $int_if 
nat on $int_if proto tcp from $int_if:network to $emailserver \
       port $email -&gt; $int_if 
</programlisting>
<para>

</para>
</chapter>

  <chapter id="ifgroups">
    <title>Filtering on interface groups</title>
    <para>You can configure groups of interfaces, filter on them</para>
    <screen># ifconfig sis2 group untrusted</screen>
    <para>(or <filename>hostname.sis2</filename>)</para>
    <para>Use in your <filename>pf.conf</filename></para>
    <programlisting>
pass in on untrusted to any port $webports
pass out on egress to any port $webports
</programlisting>
  </chapter>

  <chapter id="poweroftags">
    <title>The power of tags</title>
    <para>tag packets incoming, block or pass outgoing based on tags</para>
    <para>eg in a net with several NATing access points</para>
    <programlisting>
wifi = "{ 10.0.0.115, 10.0.0.125, 10.0.0.135, 10.0.0.145 }"
pass in on $int_if from $wifi to $wifi_allowed port \
     $wifi_ports tag wifigood
     ...
pass out on $ext_if tagged wifigood
</programlisting>

    <para><emphasis>NOTE:</emphasis> tags are sticky - all matching tag rules add their tag</para>
    <programlisting>

</programlisting>
  </chapter>

<chapter id="bridge">
<title>
The filtering bridge
</title>
<para>
Bridge: machine with no IP address of its own, between the Internet and a local network
</para>
<itemizedlist>
<listitem>
<para>
Opererates on the Ethernet level
</para>
</listitem>
<listitem>
<para>
"Invisible" to the outside world
</para>
</listitem>
<listitem>
<para>
Is able to use PF for filtering and nat/rdr
</para>
</listitem>
</itemizedlist>
</chapter>
<chapter id="bridgefig">
    <title>Where does it go?</title>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="bridge-network.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
</chapter>
<chapter id="bridge.basic.config">
    <title>OpenBSD bridge setup</title>
<para>
<filename>/etc/hostname.ep0</filename>
</para>
<programlisting>
up
</programlisting>
<para>
<filename>/etc/hostname.ep1</filename>
</para>
<programlisting>
up
</programlisting>
<para>
<filename>/etc/bridgename.bridge0</filename>
</para>
<programlisting>
  add ep0 add ep1 blocknonip ep0 blocknonip ep1 up
</programlisting>
<para>
Se also bridge(4), brconfig(8)
</para>
</chapter>
  <chapter id="bridge-freebsd">
    <title>FreeBSD bridge setup</title>
    <para>
Make sure your kernel config has the bridge interface, <filename>/etc/loader.conf</filename>
</para>
    <screen>
if_bridge_load="YES"
</screen>
    <para>
Create a bridge:
</para>
    <screen>$ sudo ifconfig bridge0 create </screen>
    <para>check your new sysctls</para>
    <screen>
$ sudo sysctl net.link.bridge
net.link.bridge.ipfw: 0
net.link.bridge.pfil_member: 1
net.link.bridge.pfil_bridge: 1
net.link.bridge.ipfw_arp: 0
net.link.bridge.pfil_onlyip: 1
</screen>
    <para>Check that the interfaces are up, but otherwise unconfigured, then</para>
    <screen>$ sudo ifconfig bridge0 addm ep0 addm ep1 up0</screen>
    <para>make permanent with <filename>/etc/rc.conf</filename> entries:</para>
    <screen>ifconfig_ep0="up"
ifconfig_ep1="up"
cloned_interfaces="bridge0"
ifconfig_bridge0="addm ep0 addm ep1 up"</screen>
  </chapter>

  <chapter id="bridge2">
    <title>Bridge PF filtering config</title>
<para>
<filename>/etc/pf.conf</filename>
</para>
    <programlisting>
ext_if = ep0
int_if = ep1
localnet= "192.0.2.0/24"
webserver = "192.0.2.227"
webports = "{ http, https }"
emailserver = "192.0.2.225"
email = "{ smtp, pop3, imap, imap3, imaps, pop3s }"
nameservers = "{ 192.0.2.221, 192.0.2.223 }"
client_out = "{ ssh, domain, pop3, auth, nntp, http, https, \
                cvspserver, 2628, 5999, 8000, 8080 }"
udp_services = "{ domain, ntp }"
icmp_types = "{ echoreq, unreach }"
set skip on $int_if
block all
pass quick on $ext_if inet proto { tcp, udp } from $localnet to \
     any port $udp_services
pass log on $ext_if inet proto icmp all icmp-type $icmp_types
pass on $ext_if inet proto tcp from $localnet to any port $client_out
pass on $ext_if inet proto { tcp, udp } from any to $nameservers \
     port domain
pass on $ext_if proto tcp from any to $webserver port \
     $webports synproxy state
pass log on $ext_if proto tcp from any to $emailserver port \
     $email synproxy state
pass log on $ext_if proto tcp from $emailserver to any port \
     smtp synproxy state
</programlisting>
    <para> (knock yourself out)</para>
  </chapter>
<chapter id="unrouteables">
<title>
Handling non-routable addresses from elsewhere
</title>
<para>
Bar officially unroutable (RFC1918 et al) traffic
</para>
<programlisting>
martians = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \
              10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, \
              0.0.0.0/8, 240.0.0.0/4 }"

block drop in quick on $ext_if from $martians to any
block drop out quick on $ext_if from any to $martians
</programlisting>
    <para><emphasis>NOTE:</emphasis> could usefully be rewritten as a table</para>
</chapter>

<chapter id="altqintro">
<title>
Directing traffic with altq
</title>
<para>
ALTQ
</para>
<para>
ALternate Queueing -- uses "queues" for bandwidth allocation, traffic shaping
</para>
<itemizedlist>
<listitem>
<para>
class based (cbq) - per cent, (K,M)bytes, <emphasis>or</emphasis>
</para>
</listitem>
<listitem>
<para>
priority based (PRIQ)
</para>
</listitem>
<listitem>
<para>
hierarchical (HFSC)
</para>
</listitem>
</itemizedlist>
<para>
Syntax:
</para>
<programlisting>
altq on interface type [options ... ] main_queue { sub_q1, sub_q2 ..}
  queue sub_q1 [ options ... ]
  queue sub_q2 [ options ... ]
[...]
pass [ ... ] queue sub_q1
pass [ ... ] queue sub_q2
</programlisting>
</chapter>
  <chapter id="altqsetup.openbsd">
    <title>Setting up for ALTQ </title>
	<para><emphasis>OpenBSD</emphasis>: All relevant options are enabled in the GENERIC kernel. No further (non-<filename>pf.conf</filename>) configuration necessary</para>
</chapter>
  <chapter id="altqsetup.freebsd">
    <title>Setting up for ALTQ: FreeBSD </title>
	<para><emphasis>FreeBSD</emphasis>: The GENERIC kernel does not have ALTQ options enabled. Relevant options are</para>
	<screen>options ALTQ
options ALTQ_CBQ # Class-Based Queuing (CBQ)
options ALTQ_RED # Random Early Detection (RED)
options ALTQ_RIO # RED In/Out
options ALTQ_HFSC # Hierarchical Packet Scheduler (HFSC)
options ALTQ_PRIQ # Priority Queuing (PRIQ)
options ALTQ_NOPCC # Required for SMP buildo</screen>
	<para>
Enable the options you need in your kernel config, install the kernel
</para>
</chapter>
  <chapter id="altqsetup.netbsd">
    <title>Setting up for ALTQ: NetBSD </title>
	<para><emphasis>NetBSD</emphasis>: ALTQ available in NetBSD 4.0; The GENERIC kernel does not have ALTQ options enabled. Relevant options are</para>
	<screen>
options ALTQ # Manipulate network interfaces' output queues
options ALTQ_CBQ # Class-Based Queuing
options ALTQ_HFSC # Hierarchical Fair Service Curve
options ALTQ_PRIQ # Priority Queuing
options ALTQ_RED # Random Early Detection</screen>
	<para>
Enable the options you need in your kernel config, install the kernel
</para>
  </chapter>
  <chapter id="altq.usable.bandwidth">
    <title>What is your usable bandwidth?</title>
    <para>Interfaces report <emphasis>interface</emphasis> bandwidth, not <emphasis>line bandwidth</emphasis></para>
    <para>Overhead can be single-digit percentage (ethernet) to &gt; 20 &percnt; (ADSL)</para>
    <para>Set bandwidth to lowest value in the relevant path</para>
  </chapter>
<chapter id="altqackpri">
<title>
ALTQ - prioritizing by traffic type
</title>
<para>
Daniel Hartmeier's ADSL - prioritizing ACKs to improve up/download over asymmetric link

</para>
<programlisting>
ext_if="kue0"

altq on $ext_if priq bandwidth 100Kb queue { q_pri, q_def }
queue q_pri priority 7
queue q_def priority 1 priq(default)

pass out on $ext_if proto tcp from $ext_if to any flags S/SA \
        keep state queue (q_def, q_pri)

pass in  on $ext_if proto tcp from any to $ext_if flags S/SA \
        keep state queue (q_def, q_pri)
</programlisting>
<para>
See <ulink url="http://www.benzedrine.cx/ackpri.html">http://www.benzedrine.cx/ackpri.html</ulink>
</para>
</chapter>

<chapter id="altqbypct">
<title>
ALTQ - allocation by percentage
</title>
<para>
example swiped from unix.se:
</para>
<programlisting>
altq on $ext_if cbq bandwidth 640Kb queue { def, ftp, udp, \
    http, ssh, icmp }
    queue def bandwidth 18% cbq(default borrow red)
    queue ftp bandwidth 10% cbq(borrow red)
    queue udp bandwidth 30% cbq(borrow red)
    queue http bandwidth 20% cbq(borrow red)
    queue ssh bandwidth 20% cbq(borrow red) { ssh_interactive, \
          ssh_bulk }
          queue ssh_interactive priority 7 bandwidth 20%
          queue ssh_bulk priority 0 bandwidth 80%
    queue icmp bandwidth 2% cbq

pass log quick on $ext_if proto tcp from any to any port ssh \
    flags S/SA keep state queue (ssh_bulk, ssh_interactive)
pass in quick on $ext_if proto tcp from any to any port ftp \
    flags S/SA keep state queue ftp
pass in quick on $ext_if proto tcp from any to any port www \
    flags S/SA keep state queue http
pass out on $ext_if proto udp all keep state queue udp
pass out on $ext_if proto icmp all keep state queue icmp
</programlisting>
</chapter>

  <chapter id="queuedmz0">
    <title>Queueing for a DMZ</title>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="DMZ-network.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
    <para></para>
  </chapter>
  <chapter id="queuedmz1">
    <title>Queueing for a DMZ: rules part 1</title>
    <programlisting>
total_ext = 2Mb
total_dmz = 100Mb
altq on $ext_if cbq bandwidth $total_ext queue { ext_main, ext_web, \
        ext_udp, ext_mail, ext_ssh }
queue ext_main bandwidth 25% cbq(default borrow red) { ext_hi, ext_lo }
     queue ext_hi priority 7 bandwidth 20%
     queue ext_lo priority 0 bandwidth 80%
queue ext_web bandwidth 25% cbq(borrow red)
queue ext_udp bandwidth 20% cbq(borrow red)
queue ext_mail bandwidth 30% cbq(borrow red)
altq on $dmz_if cbq bandwidth $total_dmz queue { ext_dmz, dmz_main, \
      dmz_web, dmz_udp, dmz_mail }
queue ext_dmz bandwidth $total_ext cbq(borrow red) queue { ext_dmz_web, \
     ext_dmz_udp, ext_dmz_mail }
     queue ext_dmz_web bandwidth 40% priority 5
     queue ext_dmz_udp bandwidth 10% priority 7
     queue ext_dmz_mail bandwidth 50% priority 3
queue dmz_main bandwidth 25Mb cbq(default borrow red) queue { dmz_main_hi, \
     dmz_main_lo }
     queue dmz_main_hi priority 7 bandwidth 20%
     queue dmz_main_lo priority 0 bandwidth 80%
queue dmz_web bandwidth 25Mb cbq(borrow red)
queue dmz_udp bandwidth 20Mb cbq(borrow red)
queue dmz_mail bandwidth 20Mb cbq(borrow red)
</programlisting>
    <para></para>
  </chapter>

  <chapter id="queuedmz2">
    <title>Queueing for a DMZ: rules part 2</title>
    <programlisting>
pass in on $ext_if proto { tcp, udp } from any to $nameservers \
     port domain queue ext_udp
pass in on $int_if proto { tcp, udp } from $localnet to $nameservers \
     port domain
pass out on $dmz_if proto { tcp, udp } from any to $nameservers port \
     domain queue ext_dmz_udp
pass out on $dmz_if proto { tcp, udp } from $localnet to $nameservers \
     port domain queue dmz_udp
pass in on $ext_if proto tcp from any to $webserver port $webports \
     queue ext_web
pass in on $int_if proto tcp from $localnet to $webserver port $webports
pass out on $dmz_if proto tcp from any to $webserver port $webports \
     queue ext_dmz_web
pass out on $dmz_if proto tcp from $localnet to $webserver port $webports \
     queue dmz_web
pass in log on $ext_if proto tcp from any to $mailserver port smtp
pass in log on $ext_if proto tcp from $localnet to $mailserver port smtp
pass in log on $int_if proto tcp from $localnet to $mailserver port $email
pass out log on $dmz_if proto tcp from any to $mailserver port smtp \
     queue ext_mail
pass in on $dmz_if from $mailserver to any port smtp queue dmz_mail
pass out log on $ext_if proto tcp from $mailserver to any port smtp \
     queue ext_dmz_mailt
</programlisting>
    <para></para>
  </chapter>

  <chapter id="tinyq">
    <title>overloading to a tiny queue</title>
    <programlisting>
pass log quick on $ext_if proto tcp from any to any port ssh flags S/SA \
keep state queue (ssh_bulk, ssh_interactive)</programlisting>
    <para>becomes</para>
    <programlisting>
pass log quick on $ext_if proto tcp from any to any port ssh flags S/SA \
keep state (max-src-conn 15, max-src-conn-rate 5/3, \
     overload &lt;bruteforce&gt; flush global) \
     queue (ssh_bulk, ssh_interactive)
</programlisting>
    <para>where</para>
    <programlisting>queue smallpipe bandwidth 1% cbq</programlisting>
    <para>and</para>
    <programlisting>pass inet proto tcp from &lt;bruteforce&gt; to any \
     port $tcp_services queue smallpipe</programlisting>
  </chapter>

<chapter id="altqsmtp">
<title>
ALTQ - handling unwanted traffic
</title>
<programlisting>altq on $ext_if cbq queue { q_default q_web q_mail }

   queue q_default cbq(default)
   queue q_web (...) 

    ## all mail limited to 1Mb/sec
    queue q_mail bandwidth 1Mb { q_mail_windows }
    ## windows mail limited to 56Kb/sec
    queue q_mail_windows bandwidth 56Kb

    pass in quick proto tcp from any os "Windows" to $ext_if \
    port 25 keep state queue q_mail_windows
    pass in quick proto tcp from any to $ext_if port 25 \
    label "smtp" keep state queue q_mail
</programlisting>

<screen>
" I can't believe I didn't see this earlier. Oh, how sweet. ... 
  Already a huge difference in my load. Bwa ha ha. "
</screen>
<para>
Randal L. Schwartz, <ulink url="http://use.perl.org/~merlyn/journal/17094">http://use.perl.org/~merlyn/journal/17094</ulink>
</para>
</chapter>

<chapter id="carp">
<title>
CARP and pfsync
</title>
<para>
Common Address Redundancy Protocol (CARP)
</para>
<itemizedlist>
<listitem>
<para>
Introduced with OpenBSD 3.5
</para>
</listitem>
<listitem>
<para>
Patent free alternative to VRRP (RFC 2281, 3768, patent owners: Cisco, IBM, Nokia)
</para>
</listitem>
<listitem>
<para>
Firewall/server redundancy
</para>
</listitem>
<listitem>
<para>
Virtual network interface for automatic failover
</para>
</listitem>
</itemizedlist>

<para>
pfsync
</para>
<itemizedlist>
<listitem>
<para>
Virtual network interface (assigned to physical interface)
</para>
</listitem>
<listitem>
<para>
Handles syncronization between PF firewalls (in advance of failover)
</para>
</listitem>
</itemizedlist>
<para>
Best reference: <ulink url="http://www.countersiege.com/doc/pfsync-carp/">http://www.countersiege.com/doc/pfsync-carp/</ulink>
</para>
</chapter>

  <chapter id="carpsetup.spec">
    <title>CARP: project spec</title>
    <para>Our network -</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="carp-before-simple-network.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
    <para>becomes (&hellip;)</para>
</chapter>
  <chapter id="carpsetup.spec2">
    <title>CARP: project spec cont'd</title>
    <para>Our network becomes</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="carp-redundant-firewalls-network.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
  </chapter>

  <chapter id="carpsetup.spec.txt">
    <title>CARP: project spec cont'd </title>
    <para>Our network should</para>
    <itemizedlist>
      <listitem>
	<para>
Keep functioning much the same way as it did earlier
</para>
      </listitem>
      <listitem>
	<para>
Have better availability with no noticeable downtime
</para>
      </listitem>
      <listitem>
	<para>
Experience graceful failover with no interruption of active connections
</para>
      </listitem>
    </itemizedlist>
    <para>Tall order, huh?</para>
  </chapter>

  <chapter id="carpsetup.otheros">
    <title>Is your system CARP ready?</title>
    <itemizedlist>
      <listitem>
	<para><emphasis>OpenBSD</emphasis>: GENERIC kernel comes with <filename>carp</filename> and <filename>pfsync</filename> devices compiled in</para>
      </listitem>
      <listitem>
	<para><emphasis>FreeBSD</emphasis>: GENERIC kernel does not have <filename>carp</filename> or <filename>pfsync</filename> devices enabled, must be enabled in kernel config and compiled in</para>
      </listitem>
      <listitem>
	<para><emphasis>NetBSD</emphasis>: GENERIC kernel does not have <filename>carp</filename>, needs to be enabled and compiled in. NetBSD does not support <filename>pfsync</filename></para>
      </listitem>
    </itemizedlist>
  </chapter>

  <chapter id="carpsetup.param0">
    <title>Setting up CARP</title>
    <para>You need the sysctls</para>
    <screen>$ <userinput>sysctl net.inet.carp.allow</userinput>
net.inet.carp.allow=1</screen>
    <para></para>
    <screen>$ <userinput>sysctl net.inet.carp</userinput>
net.inet.carp.allow=1
net.inet.carp.preempt=0
net.inet.carp.log=0
net.inet.carp.arpbalance=0
</screen>
    <para>
to let the magic work, we need
</para>
    <screen>
$ sudo sysctl net.inet.carp.preempt=1
</screen>
  </chapter>
  <chapter id="carpsetup.param1">
    <title>CARP: ifconfig</title>
    <para>on the <emphasis>master</emphasis></para>
    <screen>$ sudo ifconfig carp0 192.0.2.19 vhid 1
$ sudo ifconfig carp1 192.168.1.1 vhid 2</screen>
    <para>on the <emphasis>backup</emphasis></para>
    <screen>$ sudo ifconfig carp0 192.0.2.19 vhid 1 advskew 100
$ sudo ifconfig carp1 192.168.1.1 vhid 2 advskew 100</screen>
    <para>the master announces every (1 + 0/256) seconds</para>
    <para>the backup announces every (1 + 100/256) seconds</para>
    <para><emphasis>Note</emphasis> Multicast. Use <userinput>carppeer</userinput> option for unicast</para>
    <para>Also see <ulink url="http://bulabula.org/carp-and-stp-meet-switch-security.html">Henning Brauer's notes</ulink></para>
  </chapter>
  <chapter id="pfsync">
    <title>pfsync</title>
    <para>Use a physically separate net (or crossover cable)</para>
    <screen>
$ sudo ifconfig pfsync0 syncpeer 10.0.12.16 syncdev ep2
</screen>
  </chapter>

  <chapter id="carp.ruleset">
    <title>What happens to the rule set?</title>
    <para>Pass CARP traffic on the appropriate interfaces </para>
    <programlisting>
pass on $carpdevs proto carp keep state
</programlisting>
    <para>Pass pfsync traffic on the appropriate interfaces </para>
    <programlisting>
pass on $syncdev proto pfsync
</programlisting>
    <para>Some traffic doesn't make sense to fail over </para>
    <programlisting>
pass in on $int_if from $ssh_allowed to self keep state (no-sync)
</programlisting>
    <para>PF sees the traffic on the physical interface</para>
  </chapter>

  <chapter id="carp-example">
    <title>carp config example</title>
    <para>
master:
</para>
<para>
<filename>sysctl.conf</filename>
</para>
    <screen>
net.inet.carp.preempt=1
</screen>
<para><filename>hostname.carp0</filename></para>
<screen>
pass mekmitasdigoat 192.0.2.19 vhid 1
</screen>
<para><filename>hostname.carp1</filename></para>
<screen>
pass mekmitasdigoat 192.168.1.1 vhid 2
</screen>

<para>
backup:
</para>

<para><filename>sysctl.conf</filename></para>
<screen>net.inet.carp.preempt=1
</screen>

<para><filename>hostname.carp0
</filename></para>
<screen>pass mekmitasdigoat 192.0.2.19 vhid 1 advskew 100
</screen>

<para><filename>hostname.carp1
</filename></para>
<screen>pass mekmitasdigoat 192.168.1.1 vhid 2 advskew 100
</screen>
</chapter>
  <chapter id="carp.ruleset.conf">
    <title>Carp ruleset</title>
    <screen>ext_if=sis0
int_if=sis1
carpdevs="sis0 sis1"
int_carp=carp1
ext_carp=carp0
nat on $ext_if from $int_if:network -&gt; ($ext_carp)
</screen>
  </chapter>
<chapter id="troubleshoot">
<title>
Making your network troubleshooting friendly
</title>
<para>
Mainly concerns the <firstterm>Internet Control Message Protocol</firstterm> (<firstterm>ICMP</firstterm>)
</para>
<itemizedlist>
<listitem>
<para>
<firstterm>Control Messages</firstterm> (transmission parameters, packet sizes, routing, <firstterm>path MTU discovery</firstterm>)
</para>
</listitem>
<listitem>
<para>
Mid 1990s <firstterm>Ping of Death</firstterm> scare - ICMP 'just evil', 'a necessary evil'
</para>
</listitem>
<listitem>
<para>
Modern OSes not vulnerable; people are still scared
</para>
</listitem>
</itemizedlist>
</chapter>
<chapter id="dowepass">
<title>
Then, do we let it all through?
</title>
<programlisting>
pass inet proto icmp from any to any
</programlisting>
<para>
<emphasis>Pro</emphasis>: makes debugging easier
</para>
<para>
<emphasis>Con</emphasis>: may reveal too much about your network
</para>
<para>
<emphasis>Note</emphasis>: some ICMP traffic piggybacks on <userinput>keep state</userinput>
</para>
</chapter>
<chapter id="icmpstopatgw">
<title>
The easy way out: The buck stops here
</title>
<programlisting>
pass inet proto icmp icmp-type $icmp_types from $int_if:network \
          to any keep state
pass inet proto icmp icmp-type $icmp_types from any to $ext_if \
          keep state
</programlisting>
<para>
Lets your traffic pass; hides the details of your local net
</para>
</chapter>
<chapter id="letpingthru">
<title>
Letting <application>ping</application> through
</title>
<para>
<application>ping</application>: icmp - some packet types
</para>
<programlisting>
icmp_types = "echoreq"
 # [...]
pass inet proto icmp all icmp-type $icmp_types keep state
</programlisting>
</chapter>
<chapter id="helptraceroute">
<title>
Helping <application>traceroute</application>
</title>
<para>
<application>traceroute</application> needs a bit of help, but uses a fixed formula:
</para>
<programlisting>
# allow out the default range for traceroute(8):
# "base+nhops*nqueries-1" (33434+64*3-1)
pass out on $ext_if inet proto udp from any to any \
     port 33433 >< 33626 keep state
</programlisting>
<para>
This is the stuff you find in list archives - openbsd-misc (e. g. <ulink url="http://marc.info/">http://marc.info/</ulink>)
</para>
<para>
<emphasis>Note</emphasis>: Unix <application>traceroute</application> uses UDP by default; Microsoft uses ICMP ECHO (like unix with -I)
</para>
</chapter>
<chapter id="pathmtudisc">
<title>
Path MTU discovery
</title>
<para>
Negotiating critical communication parameters
</para>
    <itemizedlist>
      <listitem>
<para>
Sending progressively larger packets with <emphasis>"Do not fragment"</emphasis> flag set
</para>

      </listitem>
      <listitem>
<para>
Expecting ICMP reply<emphasis> "type 3, code 4"</emphasis>
</para>
<para>
-&gt; "destination unreachable", "fragmentation needed, Do not fragment flag set"
</para>

      </listitem>
    </itemizedlist>
</chapter>
<chapter id="pathmtudisc2">
<title>
Path MTU discovery (cont'd)
</title>
<para>
Suggested rule set addition:
</para>
<programlisting>
icmp_types = "{ echoreq, unreach }"
</programlisting>
<programlisting>
pass inet proto icmp all icmp-type $icmp_types keep state
</programlisting>
<para>
See RFC792, RFC950, RFC1191, RFC1256, RFC2521, RFC2765 (ICMP4), 
</para>
<para>
RFC1885, RFC2463, RFC2466 (ICMP6)</para>
<para>
<ulink url="http://www.ietf.org">ietf.org</ulink> or <ulink url="http://www.faqs.org">faqs.org</ulink> + PF man pages
</para>
</chapter>

<chapter id="logging">
<title>
Logging
</title>
<para>
Keyword "log" in the rules to be logged
</para>
<para>
<filename>/etc/pf.conf</filename>
</para>
<programlisting>
pass out log from &lt;client&gt; to any port $email \
     label client-email keep state
</programlisting>
<para>
Logs in binary, <application>tcpdump(8)</application> readable format
</para>
<para>NOTE: <userinput>log</userinput> logs only initial packet, use <userinput>log (all)</userinput> to log all matching packets</para>
<para>
<emphasis>OpenBSD 4.1 onwards:</emphasis> cloneable <filename>pflog</filename>, rules can log to specific interface:
</para>
<programlisting>
pass log (all, to pflog2) inet proto tcp from $mailserver \
     to any port smtp 
</programlisting>
    <para><filename>pflog</filename> interfaces created with <application>ifconfig</application> <userinput>pflogN create</userinput></para>
</chapter>

<chapter id="tcpdumpex">
<title>
Taking a peek with <application>tcpdump</application>
</title>
<para>PF logs via the <computeroutput>pflogN</computeroutput>
interfaces, <application>pflogd</application> collects data, stores in <filename>/var/log/pflog</filename>.
</para>
<screen><computeroutput>
peter@skapet:~$ sudo tcpdump -n -e -ttt -i pflog0
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: listening on pflog0, link-type PFLOG
Feb 16 16:43:20.152187 rule 0/(match) block in on ep0: 194.54.59.189.2559 > 
194.54.107.19.139: [|tcp] (DF)
Feb 16 16:48:26.073244 rule 27/(match) pass in on ep0: 61.213.167.236 > 
194.54.107.19: icmp: echo request
Feb 16 16:49:09.563448 rule 0/(match) block in on ep0: 61.152.249.148.80 > 
194.54.107.19.55609: [|tcp]
Feb 16 16:49:14.601022 rule 0/(match) block in on ep0: 194.54.59.189.3056 > 
194.54.107.19.139: [|tcp] (DF)
Feb 16 16:53:10.110110 rule 0/(match) block in on ep0: 68.194.177.173 > 
194.54.107.19: [|icmp]
Feb 16 16:55:54.818549 rule 27/(match) pass in on ep0: 61.213.167.237 > 
194.54.107.19: icmp: echo request
Feb 16 16:57:55.577782 rule 27/(match) pass in on ep0: 202.43.202.16 > 
194.54.107.19: icmp: echo request
</computeroutput></screen>
</chapter>
  <chapter id="tcpdumpfriend">
    <title>tcpdump is your friend</title>
    <para><application>tcpdump</application> has PF smarts for pflog interfaces, such as</para>
    <screen>
tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0
</screen>
    <para>or</para>
    <screen>$ <userinput>sudo tcpdump -n -ttt -i pflog0 port domain</userinput>
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: listening on pflog0, link-type PFLOG
Sep 30 14:27:41.260190 212.5.66.14.53 > 194.54.107.19.53:[|domain]
Sep 30 14:27:41.260253 212.5.66.14.53 > 194.54.107.19.53:[|domain]
Sep 30 14:27:41.260267 212.5.66.14.53 > 194.54.107.19.53:[|domain]
Sep 30 14:27:41.260638 194.54.107.19.53 > 212.5.66.14.53:[|domain]
Sep 30 14:27:41.260798 194.54.107.19.53 > 212.5.66.14.53:[|domain]
Sep 30 14:27:41.260923 194.54.107.19.53 > 212.5.66.14.53:[|domain]</screen>
    <para></para>
  </chapter>
  <chapter id="logdata2rules">
    <title>Matching log data to your rule set</title>
    <para>
<filename>pflog</filename> log data include rule number matched <emphasis>in the loaded rule set</emphasis>
</para>
<screen>$ sudo tcpdump -nettti pflog0
tcpdump: WARNING: pflog0: no IPv4 address assigned
tcpdump: listening on pflog0, link-type PFLOG
Sep 13 15:26:52.122002 rule 17/(match) pass in on epic0: 91.143.126.48.46618 > 194.54.103.65.22: [|tcp] (DF)
Sep 13 15:28:02.771442 rule 12/(match) pass in on epic0: 194.54.107.19.8025 > 194.54.107.18.8025: udp 50
Sep 13 15:28:02.773958 rule 10/(match) pass in on epic0: 194.54.107.19.8025 > 194.54.103.65.8025: udp 50
Sep 13 15:29:27.882888 rule 10/(match) pass in on epic0: 194.54.107.19.29774 > 194.54.103.65.53:[|domain]
Sep 13 15:29:28.394320 rule 12/(match) pass in on epic0: 194.54.107.19.29774 > 194.54.107.18.53:[|domain]
</screen>
    <para>match to <userinput>pfctl -vvsr</userinput> output</para>
    <screen>$ sudo pfctl -vvsr
@0 scrub in all fragment reassemble
  [ Evaluations: 6116699   Packets: 3069556   Bytes: 646214426   States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
@0 block return log all
  [ Evaluations: 102723    Packets: 2539      Bytes: 269448      States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
@1 block return log quick from &lt;bruteforce:1&gt; to any
  [ Evaluations: 102723    Packets: 40        Bytes: 2384        States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
@2 anchor "ftp-proxy/*" all
  [ Evaluations: 102683    Packets: 28044     Bytes: 22617668    States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
</screen>
 
  </chapter>
  <chapter id="log2syslog">
    <title>Log to syslog</title>
    <para>you can log to syslog, local or remote</para>
    <para><emphasis>NOTE:</emphasis> potential for huge amounts of data </para>
    <para>disable local pflog via <filename>rc.conf.local</filename></para>
    <programlisting>
pflogd_flags="-f /dev/null"
</programlisting>
    <para>define log in <filename>syslog.conf</filename></para>
    <programlisting>
pflogd_flags="-f /dev/null"
</programlisting>
    <para>start it all (or put in <filename>rc.local</filename>)</para>
    <programlisting>
$ sudo nohup tcpdump -lnettti pflog0 | logger -t pf -p local2.info &
</programlisting>

  </chapter>
  <chapter id="labelstats">
    <title>Statistics via labels</title>
<para>
<firstterm>label</firstterm> creates counters for statistics
</para>
    <programlisting>
pass log proto { tcp, udp } from any to $emailserver port smtp \
     label "mail-in"
pass log proto { tcp, udp } from $emailserver to any port smtp \
     label "mail-out"
</programlisting>
    <para>
shows up with <userinput>pfctl -vs rules</userinput>, human readable:
</para>
    <screen>
$ pfctl -vs rules
pass inet proto tcp from any to 192.0.2.225 port = smtp flags S/SA keep state label "mail-in"
[ Evaluations: 1664158 Packets: 1601986 Bytes: 763762591 States: 0 ]
[ Inserted: uid 0 pid 24490 ]
pass inet proto tcp from 192.0.2.225 to any port = smtp flags S/SA keep state label "mail-out"
[ Evaluations: 2814933 Packets: 2711211 Bytes: 492510664 States: 0 ]
[ Inserted: uid 0 pid 24490 ] 
</screen>
    <para>or to feed to a script:</para>
    <screen>
$ sudo pfctl -vsl
mail-in 1664158 1601986 763762591 887895 682427415 714091 81335176
mail-out 2814933 2711211 492510664 1407278 239776267 1303933 252734397</screen>
    <para>label, evaluations, packets passed, bytes passed, packets in, bytes in, packets out, bytes out </para>
  </chapter>
<chapter id="variable-labelnames"> 
<title>$variable label  names</title> 
<para>For even better (finer grained) statistics, you can use variables in label names:</para>
  <para><userinput>$if</userinput> - The interface.
</para>
<para><userinput>$srcaddr</userinput> - The source IP address.
</para>
<para><userinput>$dstaddr</userinput> - The destination IP address.
</para>
<para><userinput>$srcport</userinput> - The source port specification.
</para>
<para><userinput>$dstport</userinput> - The destination port
specification.
</para>
<para><userinput>$proto</userinput> - The protocol name.
</para>
<para><userinput>$nr</userinput> - The rule number.
</para>
<para>
These expand at ruleset load time
</para>
  </chapter>
<chapter id="variable-labelnames-ex"> 
<title>$variable label names: example </title> 
<para>
</para>
<screen>
pass proto tcp from $client1 to $mail_servers port $mail_services \
     label "$srcaddr"
pass proto tcp from $client1 to any port $web_services label "$srcaddr"

</screen>
    <para>
Accumulate periodically using <userinput>pfctl -vslz</userinput> (the <userinput>z</userinput> reset counters), feed to database
</para>
</chapter>

<chapter id="pftop">
<title>
Keeping an eye on things with pftop
</title>
<para>
</para>
<screen>
pfTop: Up State 1-21/67, View: default, Order: none, Cache: 10000       19:52:28

PR   DIR SRC                  DEST                 STATE   AGE   EXP  PKTS BYTES
tcp  Out 194.54.103.89:3847   216.193.211.2:25      9:9     28    67    29  3608
tcp  In  207.182.140.5:44870  127.0.0.1:8025        4:4     15 86400    30  1594
tcp  In  207.182.140.5:36469  127.0.0.1:8025       10:10   418    75   810 44675
tcp  In  194.54.107.19:51593  194.54.103.65:22      4:4    146 86395   158 37326
tcp  In  194.54.107.19:64926  194.54.103.65:22      4:4    193 86243   131 21186
tcp  In  194.54.103.76:3010   64.136.25.171:80      9:9    154    59    11  1570
tcp  In  194.54.103.76:3013   64.136.25.171:80      4:4      4 86397     6  1370
tcp  In  194.54.103.66:3847   216.193.211.2:25      9:9     28    67    29  3608
tcp  Out 194.54.103.76:3009   64.136.25.171:80      9:9    214     0     9  1490
tcp  Out 194.54.103.76:3010   64.136.25.171:80      4:4     64 86337     7  1410
udp  Out 194.54.107.18:41423  194.54.96.9:53        2:1     36     0     2   235
udp  In  194.54.107.19:58732  194.54.103.66:53      1:2     36     0     2   219
udp  In  194.54.107.19:54402  194.54.103.66:53      1:2     36     0     2   255
udp  In  194.54.107.19:54681  194.54.103.66:53      1:2     36     0     2   271
</screen>
</chapter>

<chapter id="pflow">
	<title>New in 4.5: pflow(4) and pflow state option</title>
	<para>pflow(4) pseudo-device exports netflow v5 data</para>
	<para>	<filename>/etc/pf.conf</filename></para>
	<programlisting>
		pass out log from &lt;client&gt; to any port $email \
		label client-email keep state (pflow)
	</programlisting>
</chapter>
  
<chapter id="pfstat">
    <title>Graph your traffic: pfstat</title>
<para>
<filename>pfstat</filename>, collects PF log statistics and graphs
(nice pictures for the suits!) 
</para>
    <para>State table entries, last 24 hours:</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="pfstat.jpg" scale="50">
	</imageobject>
      </mediaobject>
    </informalfigure>

    <para>Packets, last 24 hours:</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="pfstat-packets.jpg" scale="50">
	</imageobject>
      </mediaobject>
    </informalfigure>

  </chapter>

<chapter id="otherlogtools">
<title>
Other log tools you may want to look into
</title>

<para><filename>net/pfflowd</filename>, collects PF log data, converts to
Cisco <emphasis>NetFlow&trade;</emphasis> for further processing (also
see <filename>flowd</filename> by the same developer)</para>
    <para>
<emphasis>SNMP</emphasis> <filename>net/net-snmp</filename>,
PF-Related SNMP MIBs from Joel Knight's site, <ulink url="http://www.packetmischief.ca/openbsd/snmp">http://www.packetmischief.ca/openbsd/snmp</ulink>
</para>
</chapter>

  <chapter id="logsummary">
    <title>Good logs for good debugging</title>
    <para>Stay in control, understand your logs</para>
    <para>Be selective, tweak for debugging</para>
    <para>Stay in control</para>
  </chapter>

  <chapter id="goodtweaks-badtweaks">
    <title>Getting your setup just right</title>
    <para>In general <emphasis>the defaults are sane</emphasis></para>
    <para>Most tunables can usually be left alone</para>
    <para>But you need to know what they do</para>
    <para><userinput>man pf.conf</userinput> is your friend</para>
  </chapter>
  <chapter id="block-policy">
    <title>block-policy</title>
<para>
<userinput>block-policy</userinput>: the default response to blocked connections
</para>
<para>
<userinput>drop</userinput> - drop without return, or
</para>
<para>
<userinput>return</userinput> - <computeroutput>Connection refused</computeroutput>,
<computeroutput>Destination unreachable</computeroutput>, etc
</para>
    <para>The default is to drop, to play nicely (ie Go away!):</para>
<programlisting>
set block-policy return
</programlisting>
  </chapter>
  <chapter id="skip">
    <title>skip</title>
    <para>Disable filtering for an interface. Typical use:</para>
    <programlisting>
set skip on lo0
</programlisting>
    <para>(filtering on loopback almost never makes sense)</para>

  </chapter>

  <chapter id="state-policy">
    <title>state-policy</title>
    <para>Sets how packets match with state table entries.</para>
    <para>possible values: <userinput>floating</userinput> and <userinput>if-bound</userinput></para>
    <para>default is <userinput>floating</userinput>, can be overridden for specific rules, ie</para>
    <programlisting>
pass out on egress inet proto tcp to any port $allowed \
     modulate state (if-bound) 
</programlisting>
    <para><emphasis>Recommendation:</emphasis> leave as is</para>
  </chapter>

  <chapter id="state-defaults">
	  <title>state-defaults (new in 4.5)</title>
	  <para>Sets default state options for rules</para>
	  <programlisting>
	  set state-defaults pflow
	  </programlisting>
  </chapter>

  
  <chapter id="timeout">
    <title>timeout</title>
    <para>Cluster of timeout related values for the state table entries</para>
    <screen>
$ sudo  pfctl -s timeouts
tcp.first                   120s
tcp.opening                  30s
tcp.established           86400s
tcp.closing                 900s
tcp.finwait                  45s
tcp.closed                   90s
tcp.tsdiff                   30s
udp.first                    60s
udp.single                   30s
udp.multiple                 60s
icmp.first                   20s
icmp.error                   10s
other.first                  60s
other.single                 30s
other.multiple               60s
frag                         30s
interval                     10s
adaptive.start             6000 states
adaptive.end              12000 states
src.track                     0s
</screen>
    <para>you can set these individually <emphasis>if you know what you are doing</emphasis>. </para>
  </chapter>
  <chapter id="limit">
    <title>limit</title>
    <para>Set the sizes of memory pools</para>
    <screen>$ sudo pfctl -sm
states        hard limit    10000
src-nodes     hard limit    10000
frags         hard limit     5000
tables        hard limit     1000
table-entries hard limit   200000</screen>
    <para>You can adjust those in <filename>pf.conf</filename>,</para>
    <programlisting>set limit states 25000
set limit table-entries 300000</programlisting>
    <para>or </para>
    <programlisting>set limit { states 25000, src-nodes 25000, table-entries 300000 }</programlisting>
    <para><emphasis>Note:</emphasis> limited by available kernel memory</para>
  </chapter>
  <chapter id="debug">
    <title>debug</title>
    <para>Set the debug info level, possible values <userinput>none</userinput>, <userinput>urgent</userinput> (default), <userinput>misc</userinput>, <userinput>loud</userinput></para>
    <para>useful when debugging, use <userinput>set debug loud</userinput> or use <application>pfctl</application>:</para>
    <screen>$sudo pfctl -x loud
$ tail -f /var/log/messages
Oct 4 11:41:11 skapet /bsd: pf_map_addr: selected address 194.54.107.19
Oct 4 11:41:15 skapet /bsd: pf: loose state match: TCP 194.54.107.19:25 194.54.107.19:25
158.36.191.135:62458 [lo=3178647045 high=3178664421 win=33304 modulator=0 wscale=1]
[lo=3111401744 high=3111468309 win=17376 modulator=0 wscale=0] 9:9 R seq=3178647045
(3178647044) ack=3111401744 len=0 ackskew=0 pkts=9:12
Oct 4 11:41:15 skapet /bsd: pf: loose state match: TCP 194.54.107.19:25 194.54.107.19:25
158.36.191.135:62458 [lo=3178647045 high=3178664421 win=33304 modulator=0 wscale=1]
[lo=3111401744 high=3111468309 win=17376 modulator=0 wscale=0] 10:10 R seq=3178647045
(3178647044) ack=3111401744 len=0 ackskew=0 pkts=10:12
Oct 4 11:42:24 skapet /bsd: pf_map_addr: selected address 194.54.107.19
</screen>
    <para>Lots of info, enough data for auto-DOS if you're not careful</para>
  </chapter>
  <chapter id="ruleset-optimization">
    <title>ruleset-optimiation</title>
    <para>Enable or tweak the ruleset optimizer, possible values <userinput>none</userinput>, <userinput>basic</userinput> (default), <userinput>profile</userinput> </para>
    <programlisting>
set ruleset-optimization basic
</programlisting>

    <para>or</para>
 
    <screen>$ sudo pfctl -o basic</screen>
    <para>With the <userinput>basic</userinput> setting the optimizer </para>
    <itemizedlist>
      <listitem>
	<para>Removes duplicate rules</para>
      </listitem>
      <listitem>
	<para>Removes rules that are subsets of other rules</para>
      </listitem>
      <listitem>
	<para>Merges rules into tables if appropriate</para>
      </listitem>
      <listitem>
	<para>Changes rules order to improve performance</para>
      </listitem>
    </itemizedlist>
  </chapter>
  <chapter id="optimization">
    <title>optimization</title>
    <para>Choose profile for state-timeout handling, possible values <userinput>normal</userinput> (default), <userinput>high-latency</userinput>, <userinput>satellite</userinput>, <userinput>aggressive</userinput>, <userinput>conservative</userinput>.</para>
    <para><emphasis>Recommendation:</emphasis> keep the default unless you know you need something else</para>
    <para><userinput>high-latency</userinput>, <userinput>satellite</userinput>: states expire slowly (synonyms)</para>
    <para><userinput>aggressive</userinput>: states expire faster, saves memory, could drop idle connections early</para>
    <para><userinput>conservative</userinput>: states expire very slowly, uses more memory</para>
  </chapter>

<chapter id="hygiene">
<title>
Hygiene: scrub and antispoof
</title>
<para>
<userinput>scrub</userinput>: </para>
<para>
normalization, defragmentation
</para>
<programlisting>
scrub in all
</programlisting>
<para>
<userinput>antispoof</userinput>: </para>
<para>
"this packet should not be here"
</para>
    <para>drop packets from the wrong network</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="antispoof.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
<programlisting>
antispoof for $ext_if
antispoof for $int_if
</programlisting>
</chapter>

  <chapter id="testing">
    <title>Testing your setup</title>
    <para>Go back to the specification.  Does the config do what it's supposed to?</para>
    <para>Consider this network again:</para>
    <informalfigure>
      <mediaobject>
	<imageobject>
	  <imagedata align="center" fileref="DMZ-network.png" scale="135">
	</imageobject>
      </mediaobject>
    </informalfigure>
  </chapter>
  <chapter id="testing.spec">
    <title>Specification (possibly incomplete)</title>
    <itemizedlist>
      <listitem>
	<para>Default deny (aka <userinput>block all</userinput>)</para>
      </listitem>
      <listitem>
	<para>Allow access from anywhere to DMZ hosts for certain services</para>
      </listitem>
      <listitem>
	<para>Allow access from local net to DMZ, local net to anywhere port <userinput>$client_out</userinput></para>
      </listitem>
      <listitem>
	<para>Allow access from DMZ to anywhere for some services.</para>
      </listitem>
    </itemizedlist>
    <para><emphasis>Your task:</emphasis> Test that this works, valid traffic passes.</para>
    <para>Test stuff that shouldn't work too, make sure it breaks.</para>
  </chapter>
  <chapter id="debugging">
    <title>Debugging your setup</title>
    <para>If your setup does not conform to spec - <emphasis>debug</emphasis></para>
    <para>First thing to check: is PF enabled?</para>
    <screen>
$ sudo pfctl -si | grep Status
Status: Enabled for 20 days 06:28:24            Debug: Loud</screen>
    <para></para>
    <para>Does enabling/disabling PF make a difference?</para>
    <para>Do a ruleset walkthrough, based on <userinput>pfctl -s rules</userinput> output</para>
    <screen>
$ sudo pfctl -sr              
scrub in all fragment reassemble
block return log all
block return log quick from &lt;bruteforce&gt; to any
anchor "ftp-proxy/*" all</screen>
  </chapter>
  <chapter id="debug2">
    <title>Debugging some more</title>
    <para>Get working with <userinput>pfctl -vvsr</userinput> output</para>
    <screen>$ sudo pfctl -vvsr
@0 scrub in all fragment reassemble
  [ Evaluations: 6116699   Packets: 3069556   Bytes: 646214426   States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
@0 block return log all
  [ Evaluations: 102723    Packets: 2539      Bytes: 269448      States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
@1 block return log quick from &lt;bruteforce:1&gt; to any
  [ Evaluations: 102723    Packets: 40        Bytes: 2384        States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
@2 anchor "ftp-proxy/*" all
  [ Evaluations: 102683    Packets: 28044     Bytes: 22617668    States: 0     ]
  [ Inserted: uid 0 pid 2006 ]
</screen>
    <para>Trace your packet's path through the logic in the <emphasis>loaded</emphasis> rule set.</para>
    <para>What's the <emphasis>last</emphasis> matching rule? Any <userinput>quick</userinput> rules to watch for?</para>
  </chapter>
  <chapter id="debug3">
    <title>Debug - use tcpdump</title>
    <para>Use <application>tcpdump</application> to check for traffic </para>
    <screen>$ sudo tcpdump -nvvvpi xl0 tcp and not port ssh and not port smtp
tcpdump: listening on xl0, link-type EN10MB
16:23:33.351341 194.54.107.19.58679 &gt; 80.79.54.23.80: S [tcp sum ok] 2920990951:2920990951(0) win 65535 
&lt;mss 1460,nop,wscale 1,nop,nop,timestamp 166143589 0,sackOK,eol&gt; (DF) (ttl 63, id 14602, len 64)
16:23:33.434469 80.79.54.23.80 &gt; 194.54.107.19.58679: S [tcp sum ok] 2276676381:2276676381(0) ack 2920990952 
win 16384 &lt;mss 1460,nop,nop,sackOK,nop,wscale 0,nop,nop,timestamp 3138530904 166143589&gt; (DF) (ttl 48, id 39423, len 64)
16:23:33.434813 194.54.107.19.58679 &gt; 80.79.54.23.80: . [tcp sum ok] 1:1(0) ack 1 win 33304 &lt;nop,nop,timestamp 
166143673 3138530904&gt; (DF) (ttl 63, id 14603, len 52)
16:23:33.436111 194.54.107.19.58679 &gt; 80.79.54.23.80: P 1:242(241) ack 1 win 33304 &lt;nop,nop,timestamp 
166143674 3138530904&gt; (DF) (ttl 63, id 14604, len 293)
16:23:33.698605 80.79.54.23.80 &gt; 194.54.107.19.58679: . 1:1449(1448) ack 242 win 17376 &lt;nop,nop,timestamp 
3138530905 166143674&gt; (DF) (ttl 48, id 51709, len 1500)
16:23:33.700022 80.79.54.23.80 &gt; 194.54.107.19.58679: P 1449:2533(1084) ack 242 win 17376 &lt;nop,nop,timestamp 
3138530905 166143674&gt; (DF) (ttl 48, id 45465, len 1136)
</screen>
    <para>Find out exactly where your logic breaks</para>
  </chapter>

  <chapter id="stayincontrol">
    <title>Have fun!</title>
    <para>
<emphasis>Conclusion:</emphasis> Know your network, stay in control.
</para>
    <para>With OpenBSD and PF, you have <emphasis>the best toolset</emphasis> for taking control and do things the smart way. We've only scraped the surface here.</para>
    <para>This is when the fun part starts, it's up to you!</para>
  </chapter>
<chapter id="suppporttheproject">
<title>
If you enjoyed this: Support OpenBSD!
</title>
<para>
Buy OpenBSD CDs and other items, donate!
</para>
<para>
OpenBSD.org Orders Page: <ulink url="http://www.openbsd.org/orders.html">http://www.openbsd.org/orders.html</ulink></para>
<para>
OpenBSD Donations Page: <ulink url="http://www.openbsd.org/donations.html">http://www.openbsd.org/donations.html</ulink>.
</para>
<para>
OpenBSD Hardware Wanted Page: <ulink url="http://www.openbsd.org/want.html">http://www.openbsd.org/want.html</ulink>.
</para>
<para>
<emphasis>Remember:</emphasis> Free software takes real work and real money to develop
and maintain.
</para>
    <para>If you want to support me, <ulink url="http://www.nostarch.com/pf.htm">buy the book</ulink>, PDFs are even better!</para>
</chapter>

<chapter id="references">
<title>
References
</title>
    <para>Peter N. M. Hansteen, <ulink url="http://www.nostarch.com/pf.htm">The Book of PF</ulink>, No Starch Press December 2007</para>
    <para>My online PF tutorial, several formats <ulink url="http://home.nuug.no/~peter/pf/">http://home.nuug.no/~peter/pf/</ulink></para>
<para>
OpenBSDs web <ulink url="http://www.openbsd.org/">http://www.openbsd.org/</ulink>
</para>
<para>
OpenBSDs FAQ, <ulink url="http://www.openbsd.org/faq/index.html">http://www.openbsd.org/faq/index.html</ulink>
</para>
<para>
PF User Guide <ulink url="http://www.openbsd.org/faq/pf/index.html">http://www.openbsd.org/faq/pf/index.html</ulink>
</para>
<para>
Daniel Hartmeier's PF pages, <ulink url="http://www.benzedrine.cx/pf.html">http://www.benzedrine.cx/pf.html</ulink>
</para>
<para>
Daniel Hartmeier: Design and Performance of the OpenBSD Stateful Packet Filter (pf), 
<ulink url="http://www.benzedrine.cx/pf-paper.html">http://www.benzedrine.cx/pf-paper.html</ulink> (presented at Usenix 2002)
</para>
<para>
Nate Underwood: HOWTO: Transparent Packet Filtering with OpenBSD, 
<ulink url="http://ezine.daemonnews.org/200207/transpfobsd.html">http://ezine.daemonnews.org/200207/transpfobsd.html</ulink>
</para>
<para>
Randal L. Schwartz: Monitoring Net Traffic with OpenBSD's Packet Filter, 
<ulink url="http://www.samag.com/documents/s=9053/sam0403j/0403j.htm">http://www.samag.com/documents/s=9053/sam0403j/0403j.htm</ulink>
</para>
<para>Unix.se: Brandvägg med OpenBSD, <ulink url="http://unix.se/Brandv%E4gg_med_OpenBSD">http://unix.se/Brandv%E4gg_med_OpenBSD</ulink>
</para>
<para>Randal L. Schwartz: Blog for Thu, Jan 29, 2004, <ulink url="http://use.perl.org/~merlyn/journal/17094">http://use.perl.org/~merlyn/journal/17094</ulink>
</para>
<para>
RFC 1631, "The IP Network Address Translator (NAT)", May 1994 <ulink url="http://www.ietf.org/rfc/rfc1631.txt?number=1631">http://www.ietf.org/rfc/rfc1631.txt?number=1631</ulink>
</para>
<para>
RFC 1918, "Address Allocation for Private Internets", February 1996 <ulink url="http://www.ietf.org/rfc/rfc1918.txt?number=1918">http://www.ietf.org/rfc/rfc1918.txt?number=1918</ulink>
</para>
<para>The FreeBSD PF home page, <ulink url="http://pf4freebsd.love2party.net/">http://pf4freebsd.love2party.net/</ulink> </para>
<para>
Peter Postma's PF on NetBSD pages, <ulink url="http://nedbsd.nl/~ppostma/pf/">http://nedbsd.nl/~ppostma/pf/</ulink>
</para>
<para>
Marcus Ranum: <ulink url="http://www.ranum.com/security/computer_security/editorials/dumb/index.html">The
Six Dumbest Ideas in Computer Security</ulink>, September 1, 2005
</para>
<para>
Kjell Jřrgen Hole WiFi courseware, <ulink
url="http://www.kjhole.com/Standards/WiFi/WiFiDownloads.html">http://www.kjhole.com/Standards/WiFi/WiFiDownloads.html</ulink>, also see <ulink
url="http://wifinetnews.com/archives/cat_security.html">wifinetnews.com</ulink>; 
also <ulink url="http://www.drizzle.com/~aboba/IEEE/">The Unofficial
802.11 Security Web Page</ulink> comes higly recommended.
</para>
<para>
Greylisting.org <ulink url="http://www.greylisting.org/">greylisting.org</ulink>
</para>
<para>
Evan Harris: <ulink url="http://greylisting.org/articles/whitepaper.shtml">The Next Step in the Spam Control War: Greylisting</ulink> (the original greylisting paper)
</para>
    <para>Mark Uemura: <ulink url="http://undeadly.org/cgi?action=article&amp;sid=20080324141004"> What's New in 4.3: authpf-noip</ulink></para>
    <para>Henning Brauer: <ulink url="http://bulabula.org/carp-and-stp-meet-switch-security.html">Carp and STP meet switch security</ulink></para>

</chapter>


</book>
