aboutsummaryrefslogtreecommitdiff
path: root/en_US.ISO8859-1/books/handbook/firewalls/chapter.xml
diff options
context:
space:
mode:
Diffstat (limited to 'en_US.ISO8859-1/books/handbook/firewalls/chapter.xml')
-rw-r--r--en_US.ISO8859-1/books/handbook/firewalls/chapter.xml4250
1 files changed, 0 insertions, 4250 deletions
diff --git a/en_US.ISO8859-1/books/handbook/firewalls/chapter.xml b/en_US.ISO8859-1/books/handbook/firewalls/chapter.xml
deleted file mode 100644
index c8791aa051..0000000000
--- a/en_US.ISO8859-1/books/handbook/firewalls/chapter.xml
+++ /dev/null
@@ -1,4250 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!--
- The FreeBSD Documentation Project
-
- $FreeBSD$
--->
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
- xml:id="firewalls">
-
- <info>
- <title>Firewalls</title>
-
- <authorgroup>
- <author>
- <personname>
- <firstname>Joseph J.</firstname>
- <surname>Barbish</surname>
- </personname>
- <contrib>Contributed by </contrib>
- </author>
- </authorgroup>
-
- <authorgroup>
- <author>
- <personname>
- <firstname>Brad</firstname>
- <surname>Davis</surname>
- </personname>
- <contrib>Converted to SGML and updated by </contrib>
- </author>
- </authorgroup>
- </info>
-
- <indexterm><primary>firewall</primary></indexterm>
-
- <indexterm>
- <primary>security</primary>
-
- <secondary>firewalls</secondary>
- </indexterm>
-
- <sect1 xml:id="firewalls-intro">
- <title>Synopsis</title>
-
- <para>Firewalls make it possible to filter the incoming and
- outgoing traffic that flows through a system. A firewall can
- use one or more sets of <quote>rules</quote> to inspect network
- packets as they come in or go out of network connections and
- either allows the traffic through or blocks it. The rules of
- a firewall can inspect one or more characteristics of the
- packets such as the protocol type, source or destination host
- address, and source or destination port.</para>
-
- <para>Firewalls can enhance the security of a host or a network.
- They can be used to do one or more of the following:</para>
-
- <itemizedlist>
- <listitem>
- <para>Protect and insulate the applications, services, and
- machines of an internal network from unwanted traffic from
- the public Internet.</para>
- </listitem>
-
- <listitem>
- <para>Limit or disable access from hosts of the internal
- network to services of the public Internet.</para>
- </listitem>
-
- <listitem>
- <para>Support network address translation
- (<acronym>NAT</acronym>), which allows an internal network
- to use private <acronym>IP</acronym> addresses and share a
- single connection to the public Internet using either a
- single <acronym>IP</acronym> address or a shared pool of
- automatically assigned public addresses.</para>
- </listitem>
- </itemizedlist>
-
- <para>&os; has three firewalls built into the base system:
- <application>PF</application>, <application>IPFW</application>,
- and <application>IPFILTER</application>, also known as
- <application>IPF</application>. &os; also provides two traffic
- shapers for controlling bandwidth usage: &man.altq.4; and
- &man.dummynet.4;. <application>ALTQ</application> has
- traditionally been closely tied with
- <application>PF</application> and
- <application>dummynet</application> with
- <application>IPFW</application>. Each firewall uses rules to
- control the access of packets to and from a &os; system,
- although they go about it in different ways and each has a
- different rule syntax.</para>
-
- <para>&os; provides multiple firewalls in order to meet the
- different requirements and preferences for a wide variety of
- users. Each user should evaluate which firewall best meets
- their needs.</para>
-
- <para>After reading this chapter, you will know:</para>
-
- <itemizedlist>
- <listitem>
- <para>How to define packet filtering rules.</para>
- </listitem>
-
- <listitem>
- <para>The differences between the firewalls built into
- &os;.</para>
- </listitem>
-
- <listitem>
- <para>How to use and configure the
- <application>PF</application> firewall.</para>
- </listitem>
-
- <listitem>
- <para>How to use and configure the
- <application>IPFW</application> firewall.</para>
- </listitem>
-
- <listitem>
- <para>How to use and configure the
- <application>IPFILTER</application> firewall.</para>
- </listitem>
- </itemizedlist>
-
- <para>Before reading this chapter, you should:</para>
-
- <itemizedlist>
- <listitem>
- <para>Understand basic &os; and Internet concepts.</para>
- </listitem>
- </itemizedlist>
-
- <note>
- <para>Since all firewalls are based on inspecting the values of
- selected packet control fields, the creator of the firewall
- ruleset must have an understanding of how
- <acronym>TCP/IP</acronym> works, what the different values in
- the packet control fields are, and how these values are used
- in a normal session conversation. For a good introduction,
- refer to <link
- xlink:href="http://www.ipprimer.com">Daryl's
- TCP/IP Primer</link>.</para>
- </note>
- </sect1>
-
- <sect1 xml:id="firewalls-concepts">
- <title>Firewall Concepts</title>
-
- <indexterm>
- <primary>firewall</primary>
-
- <secondary>rulesets</secondary>
- </indexterm>
-
- <para>A ruleset contains a group of rules which pass or block
- packets based on the values contained in the packet. The
- bi-directional exchange of packets between hosts comprises a
- session conversation. The firewall ruleset processes both the
- packets arriving from the public Internet, as well as the
- packets produced by the system as a response to them. Each
- <acronym>TCP/IP</acronym> service is predefined by its protocol
- and listening port. Packets destined for a specific service
- originate from the source address using an unprivileged port and
- target the specific service port on the destination address.
- All the above parameters can be used as selection criteria to
- create rules which will pass or block services.</para>
-
- <para>To lookup unknown port numbers, refer to
- <filename>/etc/services</filename>. Alternatively, visit <uri
- xlink:href="http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers">http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers</uri>
- and do a port number lookup to find the purpose of a particular
- port number.</para>
-
- <para>Check out this link for <uri
- xlink:href="http://web.archive.org/web/20150803024617/http://www.sans.org/security-resources/idfaq/oddports.php">port numbers used by Trojans</uri>.</para>
-
- <para>FTP has two modes: active mode and passive mode. The
- difference is in how the data channel is acquired. Passive
- mode is more secure as the data channel is acquired by the
- ordinal ftp session requester. For a good explanation of FTP
- and the different modes, see <uri
- xlink:href="http://www.slacksite.com/other/ftp.html">http://www.slacksite.com/other/ftp.html</uri>.</para>
-
- <para>A firewall ruleset can be either
- <quote>exclusive</quote> or <quote>inclusive</quote>. An
- exclusive firewall allows all traffic through except for the
- traffic matching the ruleset. An inclusive firewall does the
- reverse as it only allows traffic matching the rules through and
- blocks everything else.</para>
-
- <para>An inclusive firewall offers better control of the outgoing
- traffic, making it a better choice for systems that offer
- services to the public Internet. It also controls the type of
- traffic originating from the public Internet that can gain
- access to a private network. All traffic that does not match
- the rules is blocked and logged. Inclusive firewalls are
- generally safer than exclusive firewalls because they
- significantly reduce the risk of allowing unwanted
- traffic.</para>
-
- <note>
- <para>Unless noted otherwise, all configuration and example
- rulesets in this chapter create inclusive firewall
- rulesets.</para>
- </note>
-
- <para>Security can be tightened further using a <quote>stateful
- firewall</quote>. This type of firewall keeps track of open
- connections and only allows traffic which either matches an
- existing connection or opens a new, allowed connection.</para>
-
- <para>Stateful filtering treats traffic as a bi-directional
- exchange of packets comprising a session. When state is
- specified on a matching rule the firewall dynamically generates
- internal rules for each anticipated packet being exchanged
- during the session. It has sufficient matching capabilities to
- determine if a packet is valid for a session. Any packets that
- do not properly fit the session template are automatically
- rejected.</para>
-
- <para>When the session completes, it is removed from the dynamic
- state table.</para>
-
- <para>Stateful filtering allows one to focus on blocking/passing
- new sessions. If the new session is passed, all its subsequent
- packets are allowed automatically and any impostor packets are
- automatically rejected. If a new session is blocked, none of
- its subsequent packets are allowed. Stateful filtering provides
- advanced matching abilities capable of defending against the
- flood of different attack methods employed by attackers.</para>
-
- <para><acronym>NAT</acronym> stands for <emphasis>Network
- Address Translation</emphasis>. <acronym>NAT</acronym>
- function enables the private LAN behind the firewall to share a
- single ISP-assigned IP address, even if that address is
- dynamically assigned. NAT allows each computer in the LAN to
- have Internet access, without having to pay the ISP for multiple
- Internet accounts or IP addresses.</para>
-
- <para><acronym>NAT</acronym> will automatically translate the
- private LAN IP address for each system on the LAN to the
- single public IP address as packets exit the firewall bound for
- the public Internet. It also performs the reverse translation
- for returning packets.</para>
-
- <para>According to RFC 1918, the following IP address ranges are
- reserved for private networks which will never be routed
- directly to the public Internet, and therefore are available
- for use with NAT:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>10.0.0.0/8</literal>.</para>
- </listitem>
-
- <listitem>
- <para><literal>172.16.0.0/12</literal>.</para>
- </listitem>
-
- <listitem>
- <para><literal>192.168.0.0/16</literal>.</para>
- </listitem>
- </itemizedlist>
-
- <warning>
- <para>When working with the firewall rules, be <emphasis>very
- careful</emphasis>. Some configurations <emphasis>can
- lock the administrator out</emphasis> of the server. To be
- on the safe side, consider performing the initial firewall
- configuration from the local console rather than doing it
- remotely over <application>ssh</application>.</para>
- </warning>
- </sect1>
-
- <sect1 xml:id="firewalls-pf">
- <info>
- <title>PF</title>
-
- <authorgroup>
- <author>
- <personname>
- <firstname>John</firstname>
- <surname>Ferrell</surname>
- </personname>
- <contrib>Revised and updated by </contrib>
- </author>
- </authorgroup>
- </info>
-
- <indexterm>
- <primary>firewall</primary>
-
- <secondary>PF</secondary>
- </indexterm>
-
- <para>Since &os;&nbsp;5.3, a ported version of OpenBSD's
- <application>PF</application> firewall has been included as an
- integrated part of the base system.
- <application>PF</application> is a complete, full-featured
- firewall that has optional support for
- <application>ALTQ</application> (Alternate Queuing), which
- provides Quality of Service (<acronym>QoS</acronym>).</para>
-
- <para>The OpenBSD Project maintains the definitive reference for
- <application>PF</application> in the <link
- xlink:href="http://www.openbsd.org/faq/pf/">PF FAQ</link>.
- Peter Hansteen maintains a thorough
- <application>PF</application> tutorial at <link
- xlink:href="http://home.nuug.no/~peter/pf/">http://home.nuug.no/~peter/pf/</link>.</para>
-
- <warning>
- <para>When reading the <link
- xlink:href="http://www.openbsd.org/faq/pf/">PF FAQ</link>,
- keep in mind that &os;'s version of
- <application>PF</application> has diverged substantially from
- the upstream OpenBSD version over the years. Not all features
- work the same way on &os; as they do in OpenBSD and vice
- versa.</para>
- </warning>
-
- <para>The &a.pf; is a good place to ask questions about
- configuring and running the <application>PF</application>
- firewall. Check the mailing list archives before asking a
- question as it may have already been answered.</para>
-
- <para>This section of the Handbook focuses on
- <application>PF</application> as it pertains to &os;. It
- demonstrates how to enable <application>PF</application> and
- <application>ALTQ</application>. It also provides several
- examples for creating rulesets on a &os; system.</para>
-
- <sect2>
- <title>Enabling <application>PF</application></title>
-
- <para>To use <application>PF</application>, its kernel
- module must be first loaded. This section describes the
- entries that can be added to <filename>/etc/rc.conf</filename>
- to enable <application>PF</application>.</para>
-
- <para>Start by adding <literal>pf_enable=yes</literal> to
- <filename>/etc/rc.conf</filename>:</para>
-
- <screen>&prompt.root; <userinput>sysrc pf_enable=yes</userinput></screen>
-
- <para>Additional options, described in &man.pfctl.8;, can be
- passed to <application>PF</application> when it is started.
- Add or change this entry in <filename>/etc/rc.conf</filename>
- and specify any required flags between the two quotes
- (<literal>""</literal>):</para>
-
- <programlisting>pf_flags="" # additional flags for pfctl startup</programlisting>
-
- <para><application>PF</application> will not start if it cannot
- find its ruleset configuration file. By default, &os; does
- not ship with a ruleset and there is no
- <filename>/etc/pf.conf</filename>. Example rulesets can be
- found in <filename>/usr/share/examples/pf/</filename>. If a
- custom ruleset has been saved somewhere else, add a line to
- <filename>/etc/rc.conf</filename> which specifies the full
- path to the file:</para>
-
- <programlisting>pf_rules="<replaceable>/path/to/pf.conf</replaceable>"</programlisting>
-
- <para>Logging support for <application>PF</application> is
- provided by &man.pflog.4;. To enable logging support, add
- <literal>pflog_enable=yes</literal> to
- <filename>/etc/rc.conf</filename>:</para>
-
- <screen>&prompt.root; <userinput>sysrc pflog_enable=yes</userinput></screen>
-
- <para>The following lines can also be added to change the
- default location of the log file or to specify any additional
- flags to pass to &man.pflog.4; when it is started:</para>
-
- <programlisting>pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
-pflog_flags="" # additional flags for pflogd startup</programlisting>
-
- <para>Finally, if there is a <acronym>LAN</acronym> behind the
- firewall and packets need to be forwarded for the computers on
- the <acronym>LAN</acronym>, or <acronym>NAT</acronym> is
- required, enable the following option:</para>
-
- <programlisting>gateway_enable="YES" # Enable as LAN gateway</programlisting>
-
- <para>After saving the needed edits,
- <application>PF</application> can be started with logging
- support by typing:</para>
-
- <screen>&prompt.root; <userinput>service pf start</userinput>
-&prompt.root; <userinput>service pflog start</userinput></screen>
-
-<!--
-This is no longer true as of 9.x. It also references the CARP section
-which doesn't explain how to use it...At some point it should.
- <indexterm>
- <primary>kernel options</primary>
- <secondary>device pf</secondary>
- </indexterm>
-
- <indexterm>
- <primary>kernel options</primary>
- <secondary>device pflog</secondary>
- </indexterm>
-
- <indexterm>
- <primary>kernel options</primary>
- <secondary>device pfsync</secondary>
- </indexterm>
-
- <note>
- <para>While it is not necessary to compile
- <application>PF</application> support into the &os; kernel,
- some advanced features are not included, namely &man.pfsync.4;, which is a
- pseudo-device that exposes certain changes to the state table
- used by <application>PF</application>. It can be paired with
- &man.carp.4; to create failover firewalls using
- <application>PF</application>. More information on
- <acronym>CARP</acronym> can be found in <xref linkend="carp"/>.</para>
-
- <para>The following <application>PF</application> kernel options
- are available:</para>
-
- <programlisting>device pf
-device pflog
-device pfsync</programlisting>
-
- <para>where:</para>
-
- <para><literal>device pf</literal> enables PF support.</para>
-
- <para><literal>device pflog</literal> enables the optional
- &man.pflog.4; pseudo network device which can be used to log
- traffic to a &man.bpf.4; descriptor. The &man.pflogd.8;
- daemon can then be used to store the logging information to
- disk.</para>
-
- <para><literal>device pfsync</literal> enables the optional
- &man.pfsync.4; pseudo-network device that is used to monitor
- <quote>state changes</quote>.</para>
- </note>
- -->
-
- <para>By default, <application>PF</application> reads its
- configuration rules from <filename>/etc/pf.conf</filename> and
- modifies, drops, or passes packets according to the rules or
- definitions specified in this file. The &os; installation
- includes several sample files located in
- <filename>/usr/share/examples/pf/</filename>. Refer to the
- <link xlink:href="http://www.openbsd.org/faq/pf/">PF
- FAQ</link> for complete coverage
- of <application>PF</application> rulesets.</para>
-
- <para>To control <application>PF</application>, use
- <command>pfctl</command>. <xref linkend="pfctl"/> summarizes
- some useful options to this command. Refer to &man.pfctl.8;
- for a description of all available options:</para>
-
- <table xml:id="pfctl" frame="none" pgwide="1">
- <title>Useful <command>pfctl</command> Options</title>
-
- <tgroup cols="2">
- <thead>
- <row>
- <entry>Command</entry>
- <entry>Purpose</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry><command>pfctl
- -e</command></entry>
- <entry>Enable <application>PF</application>.</entry>
- </row>
-
- <row>
- <entry><command>pfctl
- -d</command></entry>
- <entry>Disable <application>PF</application>.</entry>
- </row>
-
- <row>
- <entry><command>pfctl -F all
- -f /etc/pf.conf</command></entry>
- <entry>Flush all <acronym>NAT</acronym>, filter, state,
- and table rules and reload
- <filename>/etc/pf.conf</filename>.</entry>
- </row>
-
- <row>
- <entry><command>pfctl -s [ rules | nat |
- states ]</command></entry>
- <entry>Report on the filter rules,
- <acronym>NAT</acronym> rules, or state
- table.</entry>
- </row>
-
- <row>
- <entry><command>pfctl -vnf
- /etc/pf.conf</command></entry>
- <entry>Check <filename>/etc/pf.conf</filename> for
- errors, but do not load ruleset.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <tip>
- <para><package>security/sudo</package> is useful for running
- commands like <command>pfctl</command> that require elevated
- privileges. It can be installed from the Ports
- Collection.</para>
- </tip>
-
- <para>To keep an eye on the traffic that passes through the
- <application>PF</application> firewall, consider installing
- the <package>sysutils/pftop</package> package or port. Once
- installed, <application>pftop</application> can be run to
- view a running snapshot of traffic in a format which is
- similar to &man.top.1;.</para>
- </sect2>
-
- <sect2 xml:id="pf-tutorial">
- <info>
- <title><application>PF</application> Rulesets</title>
-
- <authorgroup>
- <author>
- <personname>
- <firstname>Peter</firstname>
- <surname>Hansteen</surname>
- <othername>N. M.</othername>
- </personname>
- <contrib>Contributed by </contrib>
- </author>
- </authorgroup>
- </info>
-
- <para>This section demonstrates how to create a customized
- ruleset. It starts with the simplest of rulesets and builds
- upon its concepts using several examples to demonstrate
- real-world usage of <application>PF</application>'s many
- features.</para>
-
- <para>The simplest possible ruleset is for a single machine
- that does not run any services and which needs access to one
- network, which may be the Internet. To create this minimal
- ruleset, edit <filename>/etc/pf.conf</filename> so it looks
- like this:</para>
-
- <programlisting>block in all
-pass out all keep state</programlisting>
-
- <para>The first rule denies all incoming traffic by default.
- The second rule allows connections created by this system to
- pass out, while retaining state information on those
- connections. This state information allows return traffic for
- those connections to pass back and should only be used on
- machines that can be trusted. The ruleset can be loaded
- with:</para>
-
- <screen>&prompt.root; <userinput>pfctl -e ; pfctl -f /etc/pf.conf</userinput></screen>
-
- <para>In addition to keeping state,
- <application>PF</application> provides
- <firstterm>lists</firstterm> and
- <firstterm>macros</firstterm> which can be defined for use
- when creating rules. Macros can include lists and need to be
- defined before use. As an example, insert these lines at the
- very top of the ruleset:</para>
-
- <programlisting>tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
-udp_services = "{ domain }"</programlisting>
-
- <para><application>PF</application> understands port names as
- well as port numbers, as long as the names are listed in
- <filename>/etc/services</filename>. This example creates two
- macros. The first is a list of seven
- <acronym>TCP</acronym> port names and the second is one
- <acronym>UDP</acronym> port name. Once defined, macros can be
- used in rules. In this example, all traffic is blocked except
- for the connections initiated by this system for the seven
- specified <acronym>TCP</acronym> services and the one
- specified <acronym>UDP</acronym> service:</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 keep state
-pass proto udp to any port $udp_services keep state</programlisting>
-
- <para>Even though <acronym>UDP</acronym> is considered to be a
- stateless protocol, <application>PF</application> is able to
- track some state information. For example, when a
- <acronym>UDP</acronym> request is passed which asks a name
- server about a domain name, <application>PF</application> will
- watch for the response to pass it back.</para>
-
- <para>Whenever an edit is made to a ruleset, the new rules must
- be loaded so they can be used:</para>
-
- <screen>&prompt.root; <userinput>pfctl -f /etc/pf.conf</userinput></screen>
-
- <para>If there are no syntax errors, <command>pfctl</command>
- will not output any messages during the rule load. Rules can
- also be tested before attempting to load them:</para>
-
- <screen>&prompt.root; <userinput>pfctl -nf /etc/pf.conf</userinput></screen>
-
- <para>Including <option>-n</option> causes the rules to be
- interpreted only, but not loaded. This provides an
- opportunity to correct any errors. At all times, the last
- valid ruleset loaded will be enforced until either
- <application>PF</application> is disabled or a new ruleset is
- loaded.</para>
-
- <tip>
- <para>Adding <option>-v</option> to a <command>pfctl</command>
- ruleset verify or load will display the fully parsed rules
- exactly the way they will be loaded. This is extremely
- useful when debugging rules.</para>
- </tip>
-
- <sect3 xml:id="pftut-gateway">
- <title>A Simple Gateway with NAT</title>
-
- <para>This section demonstrates how to configure a &os; system
- running <application>PF</application> to act as a gateway
- for at least one other machine. The gateway needs at least
- two network interfaces, each connected to a separate
- network. In this example, <filename>xl0</filename> is
- connected to the Internet and <filename>xl1</filename> is
- connected to the internal network.</para>
-
- <para>First, enable the gateway to let the machine
- forward the network traffic it receives on one interface to
- another interface. This <application>sysctl</application>
- setting will forward <acronym>IPv4</acronym> packets:</para>
-
- <screen>&prompt.root; <userinput>sysctl net.inet.ip.forwarding=1</userinput></screen>
-
- <para>To forward <acronym>IPv6</acronym> traffic, use:</para>
-
- <screen>&prompt.root; <userinput>sysctl net.inet6.ip6.forwarding=1</userinput></screen>
-
- <para>To enable these settings at system boot, use
- &man.sysrc.8; to add them to
- <filename>/etc/rc.conf</filename>:</para>
-
- <screen>&prompt.root; <userinput>sysrc gateway_enable=yes</userinput>
-&prompt.root; <userinput>sysrc ipv6_gateway_enable=yes</userinput></screen>
-
- <para>Verify with <command>ifconfig</command> that both of the
- interfaces are up and running.</para>
-
- <para>Next, create the <application>PF</application> rules to
- allow the gateway to pass traffic. While the following rule
- allows stateful traffic from hosts of the internal network
- to pass to the gateway, the <literal>to</literal> keyword
- does not guarantee passage all the way from source to
- destination:</para>
-
- <programlisting>pass in on xl1 from xl1:network to xl0:network port $ports keep state</programlisting>
-
- <para>That rule only lets the traffic pass in to the gateway
- on the internal interface. To let the packets go further, a
- matching rule is needed:</para>
-
- <programlisting>pass out on xl0 from xl1:network to xl0:network port $ports keep state</programlisting>
-
- <para>While these two rules will work, rules this specific are
- rarely needed. For a busy network admin, a readable ruleset
- is a safer ruleset. The remainder of this section
- demonstrates how to keep the rules as simple as possible for
- readability. For example, those two rules could be
- replaced with one rule:</para>
-
- <programlisting>pass from xl1:network to any port $ports keep state</programlisting>
-
- <para>The <literal>interface:network</literal> notation can be
- replaced with a macro to make the ruleset even more
- readable. For example, a <literal>$localnet</literal> macro
- could be defined as the network directly attached to the
- internal interface (<literal>$xl1:network</literal>).
- Alternatively, the definition of
- <literal>$localnet</literal> could be changed to an
- <emphasis>IP address/netmask</emphasis> notation to denote
- a network, such as <literal>192.168.100.1/24</literal> for a
- subnet of private addresses.</para>
-
- <para>If required, <literal>$localnet</literal> could even be
- defined as a list of networks. Whatever the specific needs,
- a sensible <literal>$localnet</literal> definition could be
- used in a typical pass rule as follows:</para>
-
- <programlisting>pass from $localnet to any port $ports keep state</programlisting>
-
- <para>The following sample ruleset allows all traffic
- initiated by machines on the internal network. It first
- defines two macros to represent the external and internal
- 3COM interfaces of the gateway.</para>
-
- <note>
- <para>For dialup users, the external interface will use
- <filename>tun0</filename>. For an
- <acronym>ADSL</acronym> connection, specifically those
- using <acronym>PPP</acronym> over Ethernet
- (<acronym>PPPoE</acronym>), the correct external
- interface is <filename>tun0</filename>, not the physical
- Ethernet interface.</para>
- </note>
-
- <programlisting>ext_if = "xl0" # macro for external interface - use tun0 for PPPoE
-int_if = "xl1" # macro for internal interface
-localnet = $int_if:network
-# ext_if IP address could be dynamic, hence ($ext_if)
-nat on $ext_if from $localnet to any -&gt; ($ext_if)
-block all
-pass from { lo0, $localnet } to any keep state</programlisting>
-
- <para>This ruleset introduces the <literal>nat</literal> rule
- which is used to handle the network address translation from
- the non-routable addresses inside the internal network to
- the <acronym>IP</acronym> address assigned to the external
- interface. The parentheses surrounding the last part of the
- nat rule <literal>($ext_if)</literal> is included when the
- <acronym>IP</acronym> address of the external interface is
- dynamically assigned. It ensures that network traffic runs
- without serious interruptions even if the external
- <acronym>IP</acronym> address changes.</para>
-
- <para>Note that this ruleset probably allows more traffic to
- pass out of the network than is needed. One reasonable
- setup could create this macro:</para>
-
- <programlisting>client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, \
- https, cvspserver, 2628, 5999, 8000, 8080 }"</programlisting>
-
- <para>to use in the main pass rule:</para>
-
- <programlisting>pass inet proto tcp from $localnet to any port $client_out \
- flags S/SA keep state</programlisting>
-
- <para>A few other pass rules may be needed. This one enables
- <acronym>SSH</acronym> on the external interface:</para>
-
- <programlisting>pass in inet proto tcp to $ext_if port ssh</programlisting>
-
- <para>This macro definition and rule allows
- <acronym>DNS</acronym> and <acronym>NTP</acronym> for
- internal clients:</para>
-
- <programlisting>udp_services = "{ domain, ntp }"
-pass quick inet proto { tcp, udp } to any port $udp_services keep state</programlisting>
-
- <para>Note the <literal>quick</literal> keyword in this rule.
- Since the ruleset consists of several rules, it is important
- to understand the relationships between the rules in a
- ruleset. Rules are evaluated from top to bottom, in the
- sequence they are written. For each packet or connection
- evaluated by <application>PF</application>,
- <emphasis>the last matching rule</emphasis> in the ruleset
- is the one which is applied. However, when a packet matches
- a rule which contains the <literal>quick</literal> keyword,
- the rule processing stops and the packet is treated
- according to that rule. This is very useful when an
- exception to the general rules is needed.</para>
- </sect3>
-
- <sect3 xml:id="pftut-ftp">
- <title>Creating an <acronym>FTP</acronym> Proxy</title>
-
- <para>Configuring working <acronym>FTP</acronym> rules can be
- problematic due to the nature of the <acronym>FTP</acronym>
- protocol. <acronym>FTP</acronym> pre-dates firewalls by
- several decades and is insecure in its design. The most
- common points against using <acronym>FTP</acronym>
- include:</para>
-
- <itemizedlist>
- <listitem>
- <para>Passwords are transferred in the clear.</para>
- </listitem>
-
- <listitem>
- <para>The protocol demands the use of at least two
- <acronym>TCP</acronym> connections (control and data) on
- separate ports.</para>
- </listitem>
-
- <listitem>
- <para>When a session is established, data is communicated
- using randomly selected ports.</para>
- </listitem>
- </itemizedlist>
-
- <para>All of these points present security challenges, even
- before considering any potential security weaknesses in
- client or server software. More secure alternatives for
- file transfer exist, such as &man.sftp.1; or &man.scp.1;,
- which both feature authentication and data transfer over
- encrypted connections..</para>
-
- <para>For those situations when <acronym>FTP</acronym> is
- required, <application>PF</application> provides
- redirection of <acronym>FTP</acronym> traffic to a small
- proxy program called &man.ftp-proxy.8;, which is included in
- the base system of &os;. The role of the proxy is to
- dynamically insert and delete rules in the ruleset, using a
- set of anchors, to correctly handle
- <acronym>FTP</acronym> traffic.</para>
-
- <para>To enable the <acronym>FTP</acronym> proxy, add this
- line to <filename>/etc/rc.conf</filename>:</para>
-
- <programlisting>ftpproxy_enable="YES"</programlisting>
-
- <para>Then start the proxy by running <command>service
- ftp-proxy start</command>.</para>
-
- <para>For a basic configuration, three elements need to be
- added to <filename>/etc/pf.conf</filename>. First, the
- anchors which the proxy will use to insert the rules it
- generates for the <acronym>FTP</acronym> sessions:</para>
-
- <programlisting>nat-anchor "ftp-proxy/*"
-rdr-anchor "ftp-proxy/*"</programlisting>
-
- <para>Second, a pass rule is needed to allow
- <acronym>FTP</acronym> traffic in to the proxy.</para>
-
- <para>Third, redirection and <acronym>NAT</acronym> rules need
- to be defined before the filtering rules. Insert this
- <literal>rdr</literal> rule immediately after the
- <literal>nat</literal> rule:</para>
-
- <programlisting>rdr pass on $int_if proto tcp from any to any port ftp -&gt; 127.0.0.1 port 8021</programlisting>
-
- <para>Finally, allow the redirected traffic to pass:</para>
-
- <programlisting>pass out proto tcp from $proxy to any port ftp</programlisting>
-
- <para>where <literal>$proxy</literal> expands to the address
- the proxy daemon is bound to.</para>
-
- <para>Save <filename>/etc/pf.conf</filename>, load the new
- rules, and verify from a client that <acronym>FTP</acronym>
- connections are working:</para>
-
- <screen>&prompt.root; <userinput>pfctl -f /etc/pf.conf</userinput></screen>
-
- <para>This example covers a basic setup where the clients in
- the local network need to contact <acronym>FTP</acronym>
- servers elsewhere. This basic configuration should
- work well with most combinations of <acronym>FTP</acronym>
- clients and servers. As shown in &man.ftp-proxy.8;, the
- proxy's behavior can be changed in various ways by adding
- options to the <literal>ftpproxy_flags=</literal> line.
- Some clients or servers may have specific quirks that must
- be compensated for in the configuration, or there may be a
- need to integrate the proxy in specific ways such as
- assigning <acronym>FTP</acronym> traffic to a specific
- queue.</para>
-
- <para>For ways to run an <acronym>FTP</acronym> server
- protected by <application>PF</application> and
- &man.ftp-proxy.8;, configure a separate
- <command>ftp-proxy</command> in reverse mode, using
- <option>-R</option>, on a separate port with its own
- redirecting pass rule.</para>
- </sect3>
-
- <sect3 xml:id="pftut-icmp">
- <title>Managing <acronym>ICMP</acronym></title>
-
- <para>Many of the tools used for debugging or troubleshooting
- a <acronym>TCP/IP</acronym> network rely on the Internet
- Control Message Protocol (<acronym>ICMP</acronym>), which
- was designed specifically with debugging in mind.</para>
-
- <para>The <acronym>ICMP</acronym> protocol sends and receives
- <emphasis>control messages</emphasis> between hosts and
- gateways, mainly to provide feedback to a sender about any
- unusual or difficult conditions enroute to the target host.
- Routers use <acronym>ICMP</acronym> to negotiate packet
- sizes and other transmission parameters in a process often
- referred to as <emphasis>path <acronym>MTU</acronym>
- discovery</emphasis>.</para>
-
- <para>From a firewall perspective, some
- <acronym>ICMP</acronym> control messages are vulnerable to
- known attack vectors. Also, letting all diagnostic traffic
- pass unconditionally makes debugging easier, but it also
- makes it easier for others to extract information about the
- network. For these reasons, the following rule may not be
- optimal:</para>
-
- <programlisting>pass inet proto icmp from any to any</programlisting>
-
- <para>One solution is to let all <acronym>ICMP</acronym>
- traffic from the local network through while stopping all
- probes from outside the network:</para>
-
- <programlisting>pass inet proto icmp from $localnet to any keep state
-pass inet proto icmp from any to $ext_if keep state</programlisting>
-
- <para>Additional options are available which demonstrate some
- of <application>PF</application>'s flexibility. For
- example, rather than allowing all <acronym>ICMP</acronym>
- messages, one can specify the messages used by &man.ping.8;
- and &man.traceroute.8;. Start by defining a macro for that
- type of message:</para>
-
- <programlisting>icmp_types = "echoreq"</programlisting>
-
- <para>and a rule which uses the macro:</para>
-
- <programlisting>pass inet proto icmp all icmp-type $icmp_types keep state</programlisting>
-
- <para>If other types of <acronym>ICMP</acronym> packets are
- needed, expand <literal>icmp_types</literal> to a list of
- those packet types. Type <command>more
- /usr/src/sbin/pfctl/pfctl_parser.c</command> to see
- the list of <acronym>ICMP</acronym> message types supported
- by <application>PF</application>. Refer to <link
- xlink:href="http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml">http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml</link>
- for an explanation of each message type.</para>
-
- <para>Since Unix <command>traceroute</command> uses
- <acronym>UDP</acronym> by default, another rule is needed to
- allow Unix <command>traceroute</command>:</para>
-
- <programlisting># allow out the default range for traceroute(8):
-pass out on $ext_if inet proto udp from any to any port 33433 &gt;&lt; 33626 keep state</programlisting>
-
- <para>Since <command>TRACERT.EXE</command> on Microsoft
- Windows systems uses <acronym>ICMP</acronym> echo request
- messages, only the first rule is needed to allow network
- traces from those systems. Unix
- <command>traceroute</command> can be instructed to use other
- protocols as well, and will use <acronym>ICMP</acronym> echo
- request messages if <option>-I</option> is used. Check the
- &man.traceroute.8; man page for details.</para>
-
- <sect4 xml:id="pftut-pathmtudisc">
- <title>Path <acronym>MTU</acronym> Discovery</title>
-
- <para>Internet protocols are designed to be device
- independent, and one consequence of device independence is
- that the optimal packet size for a given connection cannot
- always be predicted reliably. The main constraint on
- packet size is the <firstterm>Maximum Transmission
- Unit</firstterm> (<acronym>MTU</acronym>) which sets the
- upper limit on the packet size for an interface. Type
- <command>ifconfig</command> to view the
- <acronym>MTU</acronym>s for a system's network
- interfaces.</para>
-
- <para><acronym>TCP/IP</acronym> uses a process known as path
- <acronym>MTU</acronym> discovery to determine the right
- packet size for a connection. This process sends packets
- of varying sizes with the <quote>Do not fragment</quote>
- flag set, expecting an <acronym>ICMP</acronym> return
- packet of <quote>type 3, code 4</quote> when the upper
- limit has been reached. Type 3 means <quote>destination
- unreachable</quote>, and code 4 is short for
- <quote>fragmentation needed, but the do-not-fragment flag
- is set</quote>. To allow path MTU discovery in order
- to support connections to other <acronym>MTU</acronym>s,
- add the <literal>destination unreachable</literal> type to
- the <literal>icmp_types</literal> macro:</para>
-
- <programlisting>icmp_types = "{ echoreq, unreach }"</programlisting>
-
- <para>Since the pass rule already uses that macro, it does
- not need to be modified to support the new
- <acronym>ICMP</acronym> type:</para>
-
- <programlisting>pass inet proto icmp all icmp-type $icmp_types keep state</programlisting>
-
- <para><application>PF</application> allows filtering on all
- variations of <acronym>ICMP</acronym> types and codes.
- The list of possible types and codes are documented in
- &man.icmp.4; and &man.icmp6.4;.</para>
- </sect4>
- </sect3>
-
- <sect3 xml:id="pftut-tables">
- <title>Using Tables</title>
-
- <para>Some types of data are relevant to filtering and
- redirection at a given time, but their definition is too
- long to be included in the ruleset file.
- <application>PF</application> supports the use of tables,
- which are defined lists that can be manipulated without
- needing to reload the entire ruleset, and which can provide
- fast lookups. Table names are always enclosed within
- <literal>&lt; &gt;</literal>, like this:</para>
-
- <programlisting>table &lt;clients&gt; { 192.168.2.0/24, !192.168.2.5 }</programlisting>
-
- <para>In this example, the <literal>192.168.2.0/24</literal>
- network is part of the table, except for the address
- <literal>192.168.2.5</literal>, which is excluded using the
- <literal>!</literal> operator. It is also possible to load
- tables from files where each item is on a separate line, as
- seen in this example
- <filename>/etc/clients</filename>:</para>
-
- <programlisting>192.168.2.0/24
-!192.168.2.5</programlisting>
-
- <para>To refer to the file, define the table like this:</para>
-
- <programlisting>table &lt;clients&gt; persist file "/etc/clients"</programlisting>
-
- <para>Once the table is defined, it can be referenced by a
- rule:</para>
-
- <programlisting>pass inet proto tcp from &lt;clients&gt; to any port $client_out flags S/SA keep state</programlisting>
-
- <para>A table's contents can be manipulated live, using
- <command>pfctl</command>. This example adds another network
- to the table:</para>
-
- <screen>&prompt.root; <userinput>pfctl -t clients -T add 192.168.1.0/16</userinput></screen>
-
- <para>Note that any changes made this way will take affect
- now, making them ideal for testing, but will not survive a
- power failure or reboot. To make the changes permanent,
- modify the definition of the table in the ruleset or edit
- the file that the table refers to. One can maintain the
- on-disk copy of the table using a &man.cron.8; job which
- dumps the table's contents to disk at regular intervals,
- using a command such as <command>pfctl -t clients -T show
- &gt;/etc/clients</command>. Alternatively,
- <filename>/etc/clients</filename> can be updated with the
- in-memory table contents:</para>
-
- <screen>&prompt.root; <userinput>pfctl -t clients -T replace -f /etc/clients</userinput></screen>
- </sect3>
-
- <sect3 xml:id="pftut-overload">
- <title>Using Overload Tables to Protect
- <acronym>SSH</acronym></title>
-
- <para>Those who run <acronym>SSH</acronym> on an external
- interface have probably seen something like this in the
- authentication logs:</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</programlisting>
-
- <para>This is indicative of a brute force attack where
- somebody or some program is trying to discover the user name
- and password which will let them into the system.</para>
-
- <para>If external <acronym>SSH</acronym> access is needed for
- legitimate users, changing the default port used by
- <acronym>SSH</acronym> can offer some protection. However,
- <application>PF</application> provides a more elegant
- solution. Pass rules can contain limits on what connecting
- hosts can do and violators can be banished to a table of
- addresses which are denied some or all access. It is even
- possible to drop all existing connections from machines
- which overreach the limits.</para>
-
- <para>To configure this, create this table in the tables
- section of the ruleset:</para>
-
- <programlisting>table &lt;bruteforce&gt; persist</programlisting>
-
- <para>Then, somewhere early in the ruleset, add rules to block
- brute access while allowing legitimate access:</para>
-
- <programlisting>block quick from &lt;bruteforce&gt;
-pass inet proto tcp from any to $localnet port $tcp_services \
- flags S/SA keep state \
- (max-src-conn <replaceable>100</replaceable>, max-src-conn-rate <replaceable>15/5</replaceable>, \
- overload &lt;bruteforce&gt; flush global)</programlisting>
-
- <para>The part in parentheses defines the limits and the
- numbers should be changed to meet local requirements. It
- can be read as follows:</para>
-
- <para><literal>max-src-conn</literal> is the number of
- simultaneous connections allowed from one host.</para>
-
- <para><literal>max-src-conn-rate</literal> is the rate of new
- connections allowed from any single host
- (<replaceable>15</replaceable>) per number of seconds
- (<replaceable>5</replaceable>).</para>
-
- <para><literal>overload &lt;bruteforce&gt;</literal> means
- that any host which exceeds these limits gets its address
- added to the <literal>bruteforce</literal> table. The
- ruleset blocks all traffic from addresses in the
- <literal>bruteforce</literal> table.</para>
-
- <para>Finally, <literal>flush global</literal> says that when
- a host reaches the limit, that all
- (<literal>global</literal>) of that host's connections will
- be terminated (<literal>flush</literal>).</para>
-
- <note>
- <para>These rules will <emphasis>not</emphasis> block slow
- bruteforcers, as described in <link
- xlink:href="http://home.nuug.no/~peter/hailmary2013/">http://home.nuug.no/~peter/hailmary2013/</link>.</para>
- </note>
-
- <para>This example ruleset is intended mainly as an
- illustration. For example, if a generous number of
- connections in general are wanted, but the desire is to be
- more restrictive when it comes to
- <application>ssh</application>, supplement the rule above
- with something like the one below, early on in the rule
- set:</para>
-
- <programlisting>pass quick proto { tcp, udp } 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)</programlisting>
-
- <note>
- <title>It May Not be Necessary to Block All
- Overloaders</title>
-
- <para>It is worth noting that the overload mechanism is a
- general technique which does not apply exclusively to
- <acronym>SSH</acronym>, and it is not always optimal to
- entirely block all traffic from offenders.</para>
-
- <para>For example, an overload rule could be used to
- protect a mail service or a web service, and the overload
- table could be used in a rule to assign offenders to a
- queue with a minimal bandwidth allocation or to redirect
- to a specific web page.</para>
- </note>
-
- <para>Over time, tables will be filled by overload rules and
- their size will grow incrementally, taking up more memory.
- Sometimes an <acronym>IP</acronym> address that is blocked
- is a dynamically assigned one, which has since been assigned
- to a host who has a legitimate reason to communicate with
- hosts in the local network.</para>
-
- <para>For situations like these,
- <application>pfctl</application> provides the ability to
- expire table entries. For example, this command will remove
- <literal>&lt;bruteforce&gt;</literal> table entries which
- have not been referenced for <literal>86400</literal>
- seconds:</para>
-
- <screen>&prompt.root; <userinput>pfctl -t bruteforce -T expire 86400</userinput></screen>
-
- <para>Similar functionality is provided by
- <package>security/expiretable</package>, which removes table
- entries which have not been accessed for a specified period
- of time.</para>
-
- <para>Once installed, <application>expiretable</application>
- can be run to remove <literal>&lt;bruteforce&gt;</literal>
- table entries older than a specified age. This example
- removes all entries older than 24 hours:</para>
-
- <programlisting>/usr/local/sbin/expiretable -v -d -t 24h bruteforce</programlisting>
- </sect3>
-
- <sect3 xml:id="pftut-spamd">
- <title>Protecting Against <acronym>SPAM</acronym></title>
-
- <para>Not to be confused with the
- <application>spamd</application> daemon which comes bundled
- with <application>spamassassin</application>,
- <package>mail/spamd</package> can be configured with
- <application>PF</application> to provide an outer defense
- against <acronym>SPAM</acronym>. This
- <application>spamd</application> hooks into the
- <application>PF</application> configuration using a set of
- redirections.</para>
-
- <para>Spammers tend to send a large number of messages, and
- <acronym>SPAM</acronym> is mainly sent from a few spammer
- friendly networks and a large number of hijacked machines,
- both of which are reported to
- <firstterm>blacklists</firstterm> fairly quickly.</para>
-
- <para>When an <acronym>SMTP</acronym> connection from an
- address in a blacklist is received,
- <application>spamd</application> presents its banner and
- immediately switches to a mode where it answers
- <acronym>SMTP</acronym> traffic one byte at a time. This
- technique, which is intended to waste as much time as
- possible on the spammer's end, is called
- <firstterm>tarpitting</firstterm>. The specific
- implementation which uses one byte <acronym>SMTP</acronym>
- replies is often referred to as
- <firstterm>stuttering</firstterm>.</para>
-
- <para>This example demonstrates the basic procedure for
- setting up <application>spamd</application> with
- automatically updated blacklists. Refer to the man pages
- which are installed with <package>mail/spamd</package> for
- more information.</para>
-
- <procedure>
- <title>Configuring <application>spamd</application></title>
-
- <step>
- <para>Install the <package>mail/spamd</package> package
- or port. To use <application>spamd</application>'s
- greylisting features, &man.fdescfs.5; must be mounted at
- <filename>/dev/fd</filename>. Add the following line to
- <filename>/etc/fstab</filename>:</para>
-
- <programlisting> fdescfs /dev/fd fdescfs rw 0 0</programlisting>
-
- <para>Then, mount the filesystem:</para>
-
- <programlisting>&prompt.root; <userinput>mount fdescfs</userinput></programlisting>
- </step>
-
- <step>
- <para>Next, edit the <application>PF</application> ruleset
- to include:</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, $localnet } 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, $localnet } port smtp -&gt; 127.0.0.1 port 8025</programlisting>
-
- <para>The two tables <literal>&lt;spamd&gt;</literal> and
- <literal>&lt;spamd-white&gt;</literal> are essential.
- <acronym>SMTP</acronym> traffic from an address listed
- in <literal>&lt;spamd&gt;</literal> but not in
- <literal>&lt;spamd-white&gt;</literal> is redirected to
- the <application>spamd</application> daemon listening at
- port 8025.</para>
- </step>
-
- <step>
- <para>The next step is to configure
- <application>spamd</application> in
- <filename>/usr/local/etc/spamd.conf</filename> and to
- add some <filename>rc.conf</filename> parameters.</para>
-
- <para>The installation of <package>mail/spamd</package>
- includes a sample configuration file
- (<filename>/usr/local/etc/spamd.conf.sample</filename>)
- and a man page for <filename>spamd.conf</filename>.
- Refer to these for additional configuration options
- beyond those shown in this example.</para>
-
- <para>One of the first lines in the configuration file
- that does not begin with a <literal>#</literal> comment
- sign contains the block which defines the
- <literal>all</literal> list, which specifies the lists
- to use:</para>
-
- <programlisting>all:\
- :traplist:whitelist:</programlisting>
-
- <para>This entry adds the desired blacklists, separated by
- colons (<literal>:</literal>). To use a whitelist to
- subtract addresses from a blacklist, add the name of the
- whitelist <emphasis>immediately</emphasis> after the
- name of that blacklist. For example:
- <literal>:blacklist:whitelist:</literal>.</para>
-
- <para>This is followed by the specified blacklist's
- definition:</para>
-
- <programlisting>traplist:\
- :black:\
- :msg="SPAM. Your address %A has sent spam within the last 24 hours":\
- :method=http:\
- :file=www.openbsd.org/spamd/traplist.gz</programlisting>
-
- <para>where the first line is the name of the blacklist
- and the second line specifies the list type. The
- <literal>msg</literal> field contains the message to
- display to blacklisted senders during the
- <acronym>SMTP</acronym> dialogue. The
- <literal>method</literal> field specifies how
- <application>spamd-setup</application> fetches the list
- data; supported methods are <literal>http</literal>,
- <literal>ftp</literal>, from a
- <literal>file</literal> in a mounted file system, and
- via <literal>exec</literal> of an external program.
- Finally, the <literal>file</literal> field specifies
- the name of the file <application>spamd</application>
- expects to receive.</para>
-
- <para>The definition of the specified whitelist is
- similar, but omits the <literal>msg</literal> field
- since a message is not needed:</para>
-
- <programlisting>whitelist:\
- :white:\
- :method=file:\
- :file=/var/mail/whitelist.txt</programlisting>
-
- <tip>
- <title>Choose Data Sources with Care</title>
-
- <para>Using all the blacklists in the sample
- <filename>spamd.conf</filename> will blacklist large
- blocks of the Internet. Administrators need to edit
- the file to create an optimal configuration which uses
- applicable data sources and, when necessary, uses
- custom lists.</para>
- </tip>
-
- <para>Next, add this entry to
- <filename>/etc/rc.conf</filename>. Additional flags are
- described in the man page specified by the
- comment:</para>
-
- <programlisting>spamd_flags="-v" # use "" and see spamd-setup(8) for flags</programlisting>
-
- <para>When finished, reload the ruleset, start
- <application>spamd</application> by typing
- <command>service obspamd start</command>, and complete
- the configuration using <command>spamd-setup</command>.
- Finally, create a &man.cron.8; job which calls
- <command>spamd-setup</command> to update the tables at
- reasonable intervals.</para>
- </step>
- </procedure>
-
- <para>On a typical gateway in front of a mail server, hosts
- will soon start getting trapped within a few seconds to
- several minutes.</para>
-
- <para><application>PF</application> also supports
- <firstterm>greylisting</firstterm>, which temporarily
- rejects messages from unknown hosts with
- <replaceable>45n</replaceable> codes. Messages from
- greylisted hosts which try again within a reasonable time
- are let through. Traffic from senders which are set up to
- behave within the limits set by RFC 1123 and RFC 2821 are
- immediately let through.</para>
-
- <para>More information about greylisting as a technique can be
- found at the <link
- xlink:href="http://www.greylisting.org/">greylisting.org</link>
- web site. The most amazing thing about greylisting, apart
- from its simplicity, is that it still works. Spammers and
- malware writers have been very slow to adapt to bypass this
- technique.</para>
-
- <para>The basic procedure for configuring greylisting is as
- follows:</para>
-
- <procedure>
- <title>Configuring Greylisting</title>
-
- <step>
- <para>Make sure that &man.fdescfs.5; is mounted as
- described in Step 1 of the previous Procedure.</para>
- </step>
-
- <step>
- <para>To run <application>spamd</application> in
- greylisting mode, add this line to
- <filename>/etc/rc.conf</filename>:</para>
-
- <programlisting>spamd_grey="YES" # use spamd greylisting if YES</programlisting>
-
- <para>Refer to the <application>spamd</application> man
- page for descriptions of additional related
- parameters.</para>
- </step>
-
- <step>
- <para>To complete the greylisting setup:</para>
-
- <programlisting>&prompt.root; <userinput>service obspamd restart</userinput>
-&prompt.root; <userinput>service obspamlogd start</userinput></programlisting>
- </step>
- </procedure>
-
- <para>Behind the scenes, the <application>spamdb</application>
- database tool and the <application>spamlogd</application>
- whitelist updater perform essential functions for the
- greylisting feature. <application>spamdb</application> is
- the administrator's main interface to managing the black,
- grey, and white lists via the contents of the
- <filename>/var/db/spamdb</filename> database.</para>
- </sect3>
-
- <sect3 xml:id="pftut-hygiene">
- <title>Network Hygiene</title>
-
- <para>This section describes how
- <literal>block-policy</literal>, <literal>scrub</literal>,
- and <literal>antispoof</literal> can be used to make the
- ruleset behave sanely.</para>
-
- <para>The <literal>block-policy</literal> is an option which
- can be set in the <literal>options</literal> part of the
- ruleset, which precedes the redirection and filtering rules.
- This option determines which feedback, if any,
- <application>PF</application> sends to hosts that are
- blocked by a rule. The option has two possible values:
- <literal>drop</literal> drops blocked packets with no
- feedback, and <literal>return</literal> returns a status
- code such as
- <computeroutput>Connection refused</computeroutput>.</para>
-
- <para>If not set, the default policy is
- <literal>drop</literal>. To change the
- <literal>block-policy</literal>, specify the desired
- value:</para>
-
- <programlisting>set block-policy return</programlisting>
-
- <para>In <application>PF</application>,
- <literal>scrub</literal> is a keyword which enables network
- packet normalization. This process reassembles fragmented
- packets and drops TCP packets that have invalid flag
- combinations. Enabling <literal>scrub</literal> provides a
- measure of protection against certain kinds of attacks
- based on incorrect handling of packet fragments. A number
- of options are available, but the simplest form is suitable
- for most configurations:</para>
-
- <programlisting>scrub in all</programlisting>
-
- <para>Some services, such as <acronym>NFS</acronym>, require
- specific fragment handling options. Refer to <link
- xlink:href="https://home.nuug.no/~peter/pf/en/scrub.html">https://home.nuug.no/~peter/pf/en/scrub.html</link>
- for more information.</para>
-
- <para>This example reassembles fragments, clears the
- <quote>do not fragment</quote> bit, and sets the maximum
- segment size to 1440 bytes:</para>
-
- <programlisting>scrub in all fragment reassemble no-df max-mss 1440</programlisting>
-
- <para>The <literal>antispoof</literal> mechanism protects
- against activity from spoofed or forged
- <acronym>IP</acronym> addresses, mainly by blocking packets
- appearing on interfaces and in directions which are
- logically not possible.</para>
-
- <para>These rules weed out spoofed traffic coming in from the
- rest of the world as well as any spoofed packets which
- originate in the local network:</para>
-
- <programlisting>antispoof for $ext_if
-antispoof for $int_if</programlisting>
- </sect3>
-
- <sect3 xml:id="pftut-unrouteables">
- <title>Handling Non-Routable Addresses</title>
-
- <para>Even with a properly configured gateway to handle
- network address translation, one may have to compensate for
- other people's misconfigurations. A common misconfiguration
- is to let traffic with non-routable addresses out to the
- Internet. Since traffic from non-routeable addresses can
- play a part in several <acronym>DoS</acronym> attack
- techniques, consider explicitly blocking traffic from
- non-routeable addresses from entering the network through
- the external interface.</para>
-
- <para>In this example, a macro containing non-routable
- addresses is defined, then used in blocking rules. Traffic
- to and from these addresses is quietly dropped on the
- gateway's external
- interface.</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>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Enabling <application>ALTQ</application></title>
-
- <para>On &os;, <application>ALTQ</application> can be used with
- <application>PF</application> to provide Quality of Service
- (<acronym>QOS</acronym>). Once
- <application>ALTQ</application> is enabled, queues can be
- defined in the ruleset which determine the processing priority
- of outbound packets.</para>
-
- <para>Before enabling <application>ALTQ</application>, refer to
- &man.altq.4; to determine if the drivers for the network cards
- installed on the system support it.</para>
-
- <para><application>ALTQ</application> is not available as a
- loadable kernel module. If the system's interfaces support
- <application>ALTQ</application>, create a custom kernel using
- the instructions in <xref linkend="kernelconfig"/>. The
- following kernel options are available. The first is needed
- to enable <application>ALTQ</application>. At least one of
- the other options is necessary to specify the queueing
- scheduler algorithm:</para>
-
- <programlisting>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)</programlisting>
-
- <para>The following scheduler algorithms are available:</para>
-
- <variablelist>
- <varlistentry>
- <term>CBQ</term>
- <listitem>
- <para>Class Based Queuing (<acronym>CBQ</acronym>) is
- used to divide a connection's bandwidth into different
- classes or queues to prioritize traffic based on filter
- rules.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>RED</term>
- <listitem>
- <para>Random Early Detection (<acronym>RED</acronym>) is
- used to avoid network congestion by measuring the length
- of the queue and comparing it to the minimum and maximum
- thresholds for the queue. When the queue is over the
- maximum, all new packets are randomly dropped.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>RIO</term>
- <listitem>
- <para>In Random Early Detection In and Out
- (<acronym>RIO</acronym>) mode, <acronym>RED</acronym>
- maintains multiple average queue lengths and multiple
- threshold values, one for each
- <acronym>QOS</acronym> level.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>HFSC</term>
- <listitem>
- <para>Hierarchical Fair Service Curve Packet Scheduler
- (<acronym>HFSC</acronym>) is described in <uri
- xlink:href="http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html">http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html</uri>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>PRIQ</term>
- <listitem>
- <para>Priority Queuing (<acronym>PRIQ</acronym>) always
- passes traffic that is in a higher queue first.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>More information about the scheduling
- algorithms and example rulesets are available at the <uri
- xlink:href="https://web.archive.org/web/20151109213426/http://www.openbsd.org/faq/pf/queueing.html">OpenBSD's web archive</uri>.</para>
- </sect2>
- </sect1>
-
- <sect1 xml:id="firewalls-ipfw">
- <title><application>IPFW</application></title>
-
- <indexterm>
- <primary>firewall</primary>
-
- <secondary>IPFW</secondary>
- </indexterm>
-
- <para><application>IPFW</application> is a stateful firewall
- written for &os; which supports both <acronym>IPv4</acronym> and
- <acronym>IPv6</acronym>. It is comprised of several components:
- the kernel firewall filter rule processor and its integrated
- packet accounting facility, the logging facility,
- <acronym>NAT</acronym>, the &man.dummynet.4; traffic shaper, a
- forward facility, a bridge facility, and an ipstealth
- facility.</para>
-
- <para>&os; provides a sample ruleset in
- <filename>/etc/rc.firewall</filename> which defines several
- firewall types for common scenarios to assist novice users in
- generating an appropriate ruleset.
- <application>IPFW</application> provides a powerful syntax which
- advanced users can use to craft customized rulesets that meet
- the security requirements of a given environment.</para>
-
- <para>This section describes how to enable
- <application>IPFW</application>, provides an overview of its
- rule syntax, and demonstrates several rulesets for common
- configuration scenarios.</para>
-
- <sect2 xml:id="firewalls-ipfw-enable">
- <title>Enabling <application>IPFW</application></title>
-
- <indexterm>
- <primary><application>IPFW</application></primary>
-
- <secondary>enabling</secondary>
- </indexterm>
-
- <para><application>IPFW</application> is included in the basic
- &os; install as a kernel loadable module, meaning that a
- custom kernel is not needed in order to enable
- <application>IPFW</application>.</para>
-
- <para>For those users who wish to statically compile
- <application>IPFW</application> support into a custom kernel,
- see <xref linkend="firewalls-ipfw-kernelconfig"/>.</para>
-
- <para>To configure the system to enable
- <application>IPFW</application> at boot time, add
- <literal>firewall_enable="YES"</literal> to
- <filename>/etc/rc.conf</filename>:</para>
-
- <screen>&prompt.root; <userinput>sysrc firewall_enable="YES"</userinput></screen>
-
- <para>To use one of the default firewall types provided by &os;,
- add another line which specifies the type:</para>
-
- <screen>&prompt.root; <userinput>sysrc firewall_type="open"</userinput></screen>
-
- <para>The available types are:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>open</literal>: passes all traffic.</para>
- </listitem>
- <listitem>
- <para><literal>client</literal>: protects only this
- machine.</para>
- </listitem>
- <listitem>
- <para><literal>simple</literal>: protects the whole
- network.</para>
- </listitem>
- <listitem>
- <para><literal>closed</literal>: entirely disables IP
- traffic except for the loopback interface.</para>
- </listitem>
- <listitem>
- <para><literal>workstation</literal>: protects only this
- machine using stateful rules.</para>
- </listitem>
- <listitem>
- <para><literal>UNKNOWN</literal>: disables the loading of
- firewall rules.</para>
- </listitem>
- <listitem>
- <para><filename><replaceable>filename</replaceable></filename>:
- full path of the file containing the firewall
- ruleset.</para>
- </listitem>
- </itemizedlist>
-
- <para>If <literal>firewall_type</literal> is set to either
- <literal>client</literal> or <literal>simple</literal>,
- modify the default rules found in
- <filename>/etc/rc.firewall</filename> to fit the
- configuration of the system.</para>
-
- <para>Note that the <literal>filename</literal> type is used to
- load a custom ruleset.</para>
-
- <para>An alternate way to load a custom ruleset is to set the
- <literal>firewall_script</literal> variable to the absolute
- path of an <emphasis>executable script</emphasis> that
- includes <application>IPFW</application> commands. The
- examples used in this section assume that the
- <literal>firewall_script</literal> is set to
- <filename>/etc/ipfw.rules</filename>:</para>
-
- <screen>&prompt.root; <userinput>sysrc firewall_script="/etc/ipfw.rules"</userinput></screen>
-
- <para>To enable logging through &man.syslogd.8;, include this
- line:</para>
-
- <screen>&prompt.root; <userinput>sysrc firewall_logging="YES"</userinput></screen>
-
- <warning>
- <para>Only firewall rules with the <option>log</option> option will
- be logged. The default rules do not include this option and it
- must be manually added. Therefore it is advisable that the default
- ruleset is edited for logging. In addition, log rotation may be
- desired if the logs are stored in a separate file.</para>
- </warning>
-
- <para>There is no <filename>/etc/rc.conf</filename> variable to
- set logging limits. To limit the number of times a rule is
- logged per connection attempt, specify the number using this
- line in <filename>/etc/sysctl.conf</filename>:</para>
-
- <screen>&prompt.root; <userinput>echo "net.inet.ip.fw.verbose_limit=<replaceable>5</replaceable>" >> /etc/sysctl.conf</userinput></screen>
-
- <para>To enable logging through a dedicated interface named
- <literal>ipfw0</literal>, add this line to
- <filename>/etc/rc.conf</filename> instead:</para>
-
- <screen>&prompt.root; <userinput>sysrc firewall_logif="YES"</userinput></screen>
-
- <para>Then use <application>tcpdump</application> to see what is
- being logged:</para>
-
- <screen>&prompt.root; <userinput>tcpdump -t -n -i ipfw0</userinput></screen>
-
- <tip>
- <para>There is no overhead due to logging unless
- <application>tcpdump</application> is attached.</para>
- </tip>
-
- <para>After saving the needed edits, start the firewall. To
- enable logging limits now, also set the
- <command>sysctl</command> value specified above:</para>
-
- <screen>&prompt.root; <userinput>service ipfw start</userinput>
-&prompt.root; <userinput>sysctl net.inet.ip.fw.verbose_limit=<replaceable>5</replaceable></userinput></screen>
- </sect2>
-
- <sect2 xml:id="firewalls-ipfw-rules">
- <title><application>IPFW</application> Rule Syntax</title>
-
- <indexterm>
- <primary><application>IPFW</application></primary>
-
- <secondary>rule processing order</secondary>
- </indexterm>
-
- <para>When a packet enters the <application>IPFW</application>
- firewall, it is compared against the first rule in the ruleset
- and progresses one rule at a time, moving from top to bottom
- in sequence. When the packet matches the selection parameters
- of a rule, the rule's action is executed and the search of the
- ruleset terminates for that packet. This is referred to as
- <quote>first match wins</quote>. If the packet does not match
- any of the rules, it gets caught by the mandatory
- <application>IPFW</application> default rule number 65535,
- which denies all packets and silently discards them. However,
- if the packet matches a rule that contains the
- <literal>count</literal>, <literal>skipto</literal>, or
- <literal>tee</literal> keywords, the search continues. Refer
- to &man.ipfw.8; for details on how these keywords affect rule
- processing.</para>
-
- <indexterm>
- <primary><application>IPFW</application></primary>
-
- <secondary>rule syntax</secondary>
- </indexterm>
-
- <para>When creating an
- <application>IPFW</application> rule, keywords must be
- written in the following order. Some keywords are mandatory
- while other keywords are optional. The words shown in
- uppercase represent a variable and the words shown in
- lowercase must precede the variable that follows it. The
- <literal>#</literal> symbol is used to mark the start of a
- comment and may appear at the end of a rule or on its own
- line. Blank lines are ignored.</para>
-
- <para><replaceable>CMD RULE_NUMBER set SET_NUMBER ACTION log
- LOG_AMOUNT PROTO from SRC SRC_PORT to DST DST_PORT
- OPTIONS</replaceable></para>
-
- <para>This section provides an overview of these keywords and
- their options. It is not an exhaustive list of every possible
- option. Refer to &man.ipfw.8; for a complete description of
- the rule syntax that can be used when creating
- <application>IPFW</application> rules.</para>
-
- <variablelist>
- <varlistentry>
- <term>CMD</term>
- <listitem>
- <para>Every rule must start with
- <parameter>ipfw add</parameter>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>RULE_NUMBER</term>
- <listitem>
- <para>Each rule is associated with a number from
- <literal>1</literal> to
- <literal>65534</literal>. The number is used to
- indicate the order of rule processing. Multiple rules
- can have the same number, in which case they are applied
- according to the order in which they have been
- added.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>SET_NUMBER</term>
- <listitem>
- <para>Each rule is associated with a set number from
- <literal>0</literal> to <literal>31</literal>.
- Sets can be individually disabled or enabled, making it
- possible to quickly add or delete a set of rules. If a
- SET_NUMBER is not specified, the rule will be added to
- set <literal>0</literal>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>ACTION</term>
- <listitem>
- <para>A rule can be associated with one of the following
- actions. The specified action will be executed when the
- packet matches the selection criterion of the
- rule.</para>
-
- <para><parameter>allow | accept | pass |
- permit</parameter>: these keywords are equivalent and
- allow packets that match the rule.</para>
-
- <para><parameter>check-state</parameter>: checks the
- packet against the dynamic state table. If a match is
- found, execute the action associated with the rule which
- generated this dynamic rule, otherwise move to the next
- rule. A <literal>check-state</literal> rule does not
- have selection criterion. If no
- <literal>check-state</literal> rule is present in the
- ruleset, the dynamic rules table is checked at the first
- <literal>keep-state</literal> or
- <literal>limit</literal> rule.</para>
-
- <para><parameter>count</parameter>: updates counters for
- all packets that match the rule. The search continues
- with the next rule.</para>
-
- <para><parameter>deny | drop</parameter>: either word
- silently discards packets that match this rule.</para>
-
- <para>Additional actions are available. Refer to
- &man.ipfw.8; for details.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>LOG_AMOUNT</term>
- <listitem>
- <para>When a packet matches a rule with the
- <literal>log</literal> keyword, a message will be logged
- to &man.syslogd.8; with a facility name of
- <literal>SECURITY</literal>. Logging only occurs if the
- number of packets logged for that particular rule does
- not exceed a specified LOG_AMOUNT. If no
- LOG_AMOUNT is specified, the limit is taken from the
- value of
- <varname>net.inet.ip.fw.verbose_limit</varname>. A
- value of zero removes the logging limit. Once the limit
- is reached, logging can be re-enabled by clearing the
- logging counter or the packet counter for that rule,
- using <command>ipfw resetlog</command>.</para>
-
- <note>
- <para>Logging is done after all other packet matching
- conditions have been met, and before performing the
- final action on the packet. The administrator decides
- which rules to enable logging on.</para>
- </note>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>PROTO</term>
- <listitem>
- <para>This optional value can be used to specify any
- protocol name or number found in
- <filename>/etc/protocols</filename>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>SRC</term>
- <listitem>
- <para>The <literal>from</literal> keyword must be followed
- by the source address or a keyword that represents the
- source address. An address can be represented by
- <literal>any</literal>, <literal>me</literal> (any
- address configured on an interface on this system),
- <literal>me6</literal>, (any <acronym>IPv6</acronym>
- address configured on an interface on this system), or
- <literal>table</literal> followed by the number of a
- lookup table which contains a list of addresses. When
- specifying an <acronym>IP</acronym> address, it can be
- optionally followed by its <acronym>CIDR</acronym> mask
- or subnet mask. For example,
- <literal>1.2.3.4/25</literal> or
- <literal>1.2.3.4:255.255.255.128</literal>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>SRC_PORT</term>
- <listitem>
- <para>An optional source port can be specified using the
- port number or name from
- <filename>/etc/services</filename>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>DST</term>
- <listitem>
- <para>The <literal>to</literal> keyword must be followed
- by the destination address or a keyword that represents
- the destination address. The same keywords and
- addresses described in the SRC section can be used to
- describe the destination.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>DST_PORT</term>
- <listitem>
- <para>An optional destination port can be specified using
- the port number or name from
- <filename>/etc/services</filename>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>OPTIONS</term>
- <listitem>
- <para>Several keywords can follow the source and
- destination. As the name suggests, OPTIONS are
- optional. Commonly used options include
- <literal>in</literal> or <literal>out</literal>, which
- specify the direction of packet flow,
- <literal>icmptypes</literal> followed by the type of
- <acronym>ICMP</acronym> message, and
- <literal>keep-state</literal>.</para>
-
- <para>When a <parameter>keep-state</parameter> rule is
- matched, the firewall will create a dynamic rule which
- matches bidirectional traffic between the source and
- destination addresses and ports using the same
- protocol.</para>
-
- <para>The dynamic rules facility is vulnerable to resource
- depletion from a SYN-flood attack which would open a
- huge number of dynamic rules. To counter this type of
- attack with <application>IPFW</application>, use
- <literal>limit</literal>. This option limits the number
- of simultaneous sessions by checking the open dynamic
- rules, counting the number of times this rule and
- <acronym>IP</acronym> address combination occurred. If
- this count is greater than the value specified by
- <literal>limit</literal>, the packet is
- discarded.</para>
-
- <para>Dozens of OPTIONS are available. Refer to
- &man.ipfw.8; for a description of each available
- option.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2>
- <title>Example Ruleset</title>
-
- <para>This section demonstrates how to create an example
- stateful firewall ruleset script named
- <filename>/etc/ipfw.rules</filename>. In this example, all
- connection rules use <literal>in</literal> or
- <literal>out</literal> to clarify the direction. They also
- use <literal>via</literal>
- <replaceable>interface-name</replaceable> to specify
- the interface the packet is traveling over.</para>
-
- <note>
- <para>When first creating or testing a firewall ruleset,
- consider temporarily setting this tunable:</para>
-
- <programlisting>net.inet.ip.fw.default_to_accept="1"</programlisting>
-
- <para>This sets the default policy of &man.ipfw.8; to be more
- permissive than the default <literal>deny ip from any to
- any</literal>, making it slightly more difficult to get
- locked out of the system right after a reboot.</para>
- </note>
-
- <para>The firewall script begins by indicating that it is a
- Bourne shell script and flushes any existing rules. It then
- creates the <literal>cmd</literal> variable so that
- <literal>ipfw add</literal> does not have to be typed at the
- beginning of every rule. It also defines the
- <literal>pif</literal> variable which represents the name of
- the interface that is attached to the Internet.</para>
-
- <programlisting>#!/bin/sh
-# Flush out the list before we begin.
-ipfw -q -f flush
-
-# Set rules command prefix
-cmd="ipfw -q add"
-pif="dc0" # interface name of NIC attached to Internet</programlisting>
-
- <para>The first two rules allow all traffic on the trusted
- internal interface and on the loopback interface:</para>
-
- <programlisting># Change xl0 to LAN NIC interface name
-&dollar;cmd 00005 allow all from any to any via xl0
-
-# No restrictions on Loopback Interface
-&dollar;cmd 00010 allow all from any to any via lo0</programlisting>
-
- <para>The next rule allows the packet through if it matches an
- existing entry in the dynamic rules table:</para>
-
- <programlisting>&dollar;cmd 00101 check-state</programlisting>
-
- <para>The next set of rules defines which stateful connections
- internal systems can create to hosts on the Internet:</para>
-
- <programlisting># Allow access to public DNS
-# Replace x.x.x.x with the IP address of a public DNS server
-# and repeat for each DNS server in /etc/resolv.conf
-&dollar;cmd 00110 allow tcp from any to x.x.x.x 53 out via &dollar;pif setup keep-state
-&dollar;cmd 00111 allow udp from any to x.x.x.x 53 out via &dollar;pif keep-state
-
-# Allow access to ISP's DHCP server for cable/DSL configurations.
-# Use the first rule and check log for IP address.
-# Then, uncomment the second rule, input the IP address, and delete the first rule
-&dollar;cmd 00120 allow log udp from any to any 67 out via &dollar;pif keep-state
-#&dollar;cmd 00120 allow udp from any to x.x.x.x 67 out via &dollar;pif keep-state
-
-# Allow outbound HTTP and HTTPS connections
-&dollar;cmd 00200 allow tcp from any to any 80 out via &dollar;pif setup keep-state
-&dollar;cmd 00220 allow tcp from any to any 443 out via &dollar;pif setup keep-state
-
-# Allow outbound email connections
-&dollar;cmd 00230 allow tcp from any to any 25 out via &dollar;pif setup keep-state
-&dollar;cmd 00231 allow tcp from any to any 110 out via &dollar;pif setup keep-state
-
-# Allow outbound ping
-&dollar;cmd 00250 allow icmp from any to any out via &dollar;pif keep-state
-
-# Allow outbound NTP
-&dollar;cmd 00260 allow udp from any to any 123 out via &dollar;pif keep-state
-
-# Allow outbound SSH
-&dollar;cmd 00280 allow tcp from any to any 22 out via &dollar;pif setup keep-state
-
-# deny and log all other outbound connections
-&dollar;cmd 00299 deny log all from any to any out via &dollar;pif</programlisting>
-
- <para>The next set of rules controls connections from Internet
- hosts to the internal network. It starts by denying packets
- typically associated with attacks and then explicitly allows
- specific types of connections. All the authorized services
- that originate from the Internet use <literal>limit</literal>
- to prevent flooding.</para>
-
- <programlisting># Deny all inbound traffic from non-routable reserved address spaces
-&dollar;cmd 00300 deny all from 192.168.0.0/16 to any in via &dollar;pif #RFC 1918 private IP
-&dollar;cmd 00301 deny all from 172.16.0.0/12 to any in via &dollar;pif #RFC 1918 private IP
-&dollar;cmd 00302 deny all from 10.0.0.0/8 to any in via &dollar;pif #RFC 1918 private IP
-&dollar;cmd 00303 deny all from 127.0.0.0/8 to any in via &dollar;pif #loopback
-&dollar;cmd 00304 deny all from 0.0.0.0/8 to any in via &dollar;pif #loopback
-&dollar;cmd 00305 deny all from 169.254.0.0/16 to any in via &dollar;pif #DHCP auto-config
-&dollar;cmd 00306 deny all from 192.0.2.0/24 to any in via &dollar;pif #reserved for docs
-&dollar;cmd 00307 deny all from 204.152.64.0/23 to any in via &dollar;pif #Sun cluster interconnect
-&dollar;cmd 00308 deny all from 224.0.0.0/3 to any in via &dollar;pif #Class D &amp; E multicast
-
-# Deny public pings
-&dollar;cmd 00310 deny icmp from any to any in via &dollar;pif
-
-# Deny ident
-&dollar;cmd 00315 deny tcp from any to any 113 in via &dollar;pif
-
-# Deny all Netbios services.
-&dollar;cmd 00320 deny tcp from any to any 137 in via &dollar;pif
-&dollar;cmd 00321 deny tcp from any to any 138 in via &dollar;pif
-&dollar;cmd 00322 deny tcp from any to any 139 in via &dollar;pif
-&dollar;cmd 00323 deny tcp from any to any 81 in via &dollar;pif
-
-# Deny fragments
-&dollar;cmd 00330 deny all from any to any frag in via &dollar;pif
-
-# Deny ACK packets that did not match the dynamic rule table
-&dollar;cmd 00332 deny tcp from any to any established in via &dollar;pif
-
-# Allow traffic from ISP's DHCP server.
-# Replace x.x.x.x with the same IP address used in rule 00120.
-#&dollar;cmd 00360 allow udp from any to x.x.x.x 67 in via &dollar;pif keep-state
-
-# Allow HTTP connections to internal web server
-&dollar;cmd 00400 allow tcp from any to me 80 in via &dollar;pif setup limit src-addr 2
-
-# Allow inbound SSH connections
-&dollar;cmd 00410 allow tcp from any to me 22 in via &dollar;pif setup limit src-addr 2
-
-# Reject and log all other incoming connections
-&dollar;cmd 00499 deny log all from any to any in via &dollar;pif</programlisting>
-
- <para>The last rule logs all packets that do not match any of
- the rules in the ruleset:</para>
-
- <programlisting># Everything else is denied and logged
-&dollar;cmd 00999 deny log all from any to any</programlisting>
- </sect2>
-
- <sect2 xml:id="in-kernel-nat">
- <info>
- <title>In-kernel <acronym>NAT</acronym></title>
-
- <authorgroup>
- <author>
- <personname>
- <firstname>Chern</firstname>
- <surname>Lee</surname>
- </personname>
- <contrib>Contributed by </contrib>
- </author>
- </authorgroup>
-
- <authorgroup>
- <author>
- <personname>
- <firstname>Dries</firstname>
- <surname>Michiels</surname>
- </personname>
- <contrib>Rewritten and updated by </contrib>
- </author>
- </authorgroup>
- </info>
-
- <indexterm>
- <primary>NAT</primary>
-
- <secondary>and <application>IPFW</application></secondary>
- </indexterm>
-
- <para>&os;'s <application>IPFW</application> firewall has two
- implementations of <acronym>NAT</acronym>: the userland
- implementation &man.natd.8;, and the more recent in-kernel
- <acronym>NAT</acronym> implementation. Both work in
- conjunction with <application>IPFW</application> to provide
- network address translation. This can be used to provide an
- Internet Connection Sharing solution so that several internal
- computers can connect to the Internet using a single public
- <acronym>IP</acronym> address.</para>
-
- <para>To do this, the &os; machine connected to the Internet
- must act as a gateway. This system must have two
- <acronym>NIC</acronym>s, where one is connected to the
- Internet and the other is connected to the internal
- <acronym>LAN</acronym>. Each machine connected to the
- <acronym>LAN</acronym> should be assigned an
- <acronym>IP</acronym> address in the private network space, as
- defined by <link
- xlink:href="https://www.ietf.org/rfc/rfc1918.txt">RFC
- 1918</link>.</para>
-
- <para>Some additional configuration is needed in order to enable
- the in-kernel <acronym>NAT</acronym> facility of
- <application>IPFW</application>. To enable in-kernel
- <acronym>NAT</acronym> support at boot time, the following
- must be set in <filename>/etc/rc.conf</filename>:</para>
-
- <programlisting>gateway_enable="YES"
-firewall_enable="YES"
-firewall_nat_enable="YES"</programlisting>
-
- <note>
- <para>When <literal>firewall_nat_enable</literal> is set but
- <literal>firewall_enable</literal> is not, it will have no
- effect and do nothing. This is because the in-kernel
- <acronym>NAT</acronym> implementation is only compatible
- with <application>IPFW</application>.</para></note>
-
- <para>When the ruleset contains stateful rules, the positioning
- of the <acronym>NAT</acronym> rule is critical and the
- <literal>skipto</literal> action is used. The
- <literal>skipto</literal> action requires a rule number so
- that it knows which rule to jump to. The example below builds
- upon the firewall ruleset shown in the previous section. It
- adds some additional entries and modifies some existing rules
- in order to configure the firewall for in-kernel
- <acronym>NAT</acronym>. It starts by adding some additional
- variables which represent the rule number to skip to, the
- <literal>keep-state</literal> option, and a list of
- <acronym>TCP</acronym> ports which will be used to reduce the
- number of rules.</para>
-
- <programlisting>#!/bin/sh
-ipfw -q -f flush
-cmd="ipfw -q add"
-skip="skipto 1000"
-pif=dc0
-ks="keep-state"
-good_tcpo="22,25,37,53,80,443,110"</programlisting>
-
- <para>With in-kernel <acronym>NAT</acronym> it is
- necessary to disable TCP segmentation offloading
- (<acronym>TSO</acronym>) due to the architecture of
- &man.libalias.3;, a library implemented as a kernel module to
- provide the in-kernel <acronym>NAT</acronym> facility of
- <application>IPFW</application>. <acronym>TSO</acronym> can
- be disabled on a per network interface basis using
- &man.ifconfig.8; or on a system wide basis using
- &man.sysctl.8;. To disable <acronym>TSO</acronym> system
- wide, the following must be set it
- <filename>/etc/sysctl.conf</filename>:</para>
-
- <programlisting>net.inet.tcp.tso="0"</programlisting>
-
- <para>A <acronym>NAT</acronym> instance will also be configured.
- It is possible to have multiple <acronym>NAT</acronym>
- instances each with their own configuration. For this example
- only one <acronym>NAT</acronym> instance is needed,
- <acronym>NAT</acronym> instance number 1. The configuration
- can take a few options such as: <option>if</option> which
- indicates the public interface, <option>same_ports</option>
- which takes care that alliased ports and local port numbers
- are mapped the same, <option>unreg_only</option> will result
- in only unregistered (private) address spaces to be processed
- by the <acronym>NAT</acronym> instance, and
- <option>reset</option> which will help to keep a functioning
- <acronym>NAT</acronym> instance even when the public
- <acronym>IP</acronym> address of the
- <application>IPFW</application> machine changes. For all
- possible options that can be passed to a single
- <acronym>NAT</acronym> instance configuration consult
- &man.ipfw.8;. When configuring a stateful
- <acronym>NAT</acronym>ing firewall, it is neseccary to allow
- translated packets to be reinjected in the firewall for
- further processing. This can be achieved by disabling
- <option>one_pass</option> behavior at the start of the
- firewall script.</para>
-
- <programlisting>ipfw disable one_pass
-ipfw -q nat 1 config if &dollar;pif same_ports unreg_only reset</programlisting>
-
- <para>The inbound <acronym>NAT</acronym> rule is inserted
- <emphasis>after</emphasis> the two rules which allow all
- traffic on the trusted and loopback interfaces and after the
- reassemble rule but <emphasis>before</emphasis> the
- <literal>check-state</literal> rule. It is important that the
- rule number selected for this <acronym>NAT</acronym> rule, in
- this example <literal>100</literal>, is higher than the first
- three rules and lower than the <literal>check-state</literal>
- rule. Furthermore, because of the behavior of in-kernel
- <acronym>NAT</acronym> it is advised to place a reassemble
- rule just before the first <acronym>NAT</acronym> rule and
- after the rules that allow traffic on trusted interface.
- Normally, <acronym>IP</acronym> fragmentation should not
- happen, but when dealing with <acronym>IPSEC/ESP/GRE</acronym>
- tunneling traffic it might and the reassembling of fragments
- is necessary before handing the complete packet over to the
- in-kernel <acronym>NAT</acronym> facility.</para>
-
- <note>
- <para>The reassemble rule was not needed with userland
- &man.natd.8; because the internal workings of the
- <application>IPFW</application> <literal>divert</literal>
- action already takes care of reassembling packets before
- delivery to the socket as also stated in &man.ipfw.8;.</para>
-
- <para>The <acronym>NAT</acronym> instance and rule number used
- in this example does not match with the default
- <acronym>NAT</acronym> instance and rule number created by
- <filename>rc.firewall</filename>.
- <filename>rc.firewall</filename> is a script that sets up
- the default firewall rules present in &os;.</para></note>
-
- <programlisting>&dollar;cmd 005 allow all from any to any via xl0 # exclude LAN traffic
-&dollar;cmd 010 allow all from any to any via lo0 # exclude loopback traffic
-&dollar;cmd 099 reass all from any to any in # reassemble inbound packets
-&dollar;cmd 100 nat 1 ip from any to any in via &dollar;pif # NAT any inbound packets
-# Allow the packet through if it has an existing entry in the dynamic rules table
-&dollar;cmd 101 check-state</programlisting>
-
- <para>The outbound rules are modified to replace the
- <literal>allow</literal> action with the
- <literal>&dollar;skip</literal> variable, indicating that rule
- processing will continue at rule <literal>1000</literal>. The
- seven <literal>tcp</literal> rules have been replaced by rule
- <literal>125</literal> as the
- <literal>&dollar;good_tcpo</literal> variable contains the
- seven allowed outbound ports.</para>
-
- <note>
- <para>Remember that <application>IPFW</application>'s
- performance is largely determined by the number of rules
- present in the ruleset.</para></note>
-
- <programlisting># Authorized outbound packets
-&dollar;cmd 120 &dollar;skip udp from any to x.x.x.x 53 out via &dollar;pif &dollar;ks
-&dollar;cmd 121 &dollar;skip udp from any to x.x.x.x 67 out via &dollar;pif &dollar;ks
-&dollar;cmd 125 &dollar;skip tcp from any to any &dollar;good_tcpo out via &dollar;pif setup &dollar;ks
-&dollar;cmd 130 &dollar;skip icmp from any to any out via &dollar;pif &dollar;ks</programlisting>
-
- <para>The inbound rules remain the same, except for the very
- last rule which removes the <literal>via $pif</literal> in
- order to catch both inbound and outbound rules. The
- <acronym>NAT</acronym> rule must follow this last outbound
- rule, must have a higher number than that last rule, and the
- rule number must be referenced by the
- <literal>skipto</literal> action. In this ruleset, rule
- number <literal>1000</literal> handles passing all packets to
- our configured instance for <acronym>NAT</acronym> processing.
- The next rule allows any packet which has undergone
- <acronym>NAT</acronym> processing to pass.</para>
-
- <programlisting>&dollar;cmd 999 deny log all from any to any
-&dollar;cmd 1000 nat 1 ip from any to any out via &dollar;pif # skipto location for outbound stateful rules
-&dollar;cmd 1001 allow ip from any to any</programlisting>
-
- <para>In this example, rules <literal>100</literal>,
- <literal>101</literal>, <literal>125</literal>,
- <literal>1000</literal>, and <literal>1001</literal> control
- the address translation of the outbound and inbound packets so
- that the entries in the dynamic state table always register
- the private <acronym>LAN</acronym> <acronym>IP</acronym>
- address.</para>
-
- <para>Consider an internal web browser which initializes a new
- outbound <acronym>HTTP</acronym> session over port 80. When
- the first outbound packet enters the firewall, it does not
- match rule <literal>100</literal> because it is headed out
- rather than in. It passes rule <literal>101</literal> because
- this is the first packet and it has not been posted to the
- dynamic state table yet. The packet finally matches rule
- <literal>125</literal> as it is outbound on an allowed port
- and has a source <acronym>IP</acronym> address from the
- internal <acronym>LAN</acronym>. On matching this rule, two
- actions take place. First, the <literal>keep-state</literal>
- action adds an entry to the dynamic state table and the
- specified action, <literal>skipto rule 1000</literal>, is
- executed. Next, the packet undergoes <acronym>NAT</acronym>
- and is sent out to the Internet. This packet makes its way to
- the destination web server, where a response packet is
- generated and sent back. This new packet enters the top of
- the ruleset. It matches rule <literal>100</literal> and has
- its destination <acronym>IP</acronym> address mapped back to
- the original internal address. It then is processed by the
- <literal>check-state</literal> rule, is found in the table as
- an existing session, and is released to the
- <acronym>LAN</acronym>.</para>
-
- <para>On the inbound side, the ruleset has to deny bad packets
- and allow only authorized services. A packet which matches an
- inbound rule is posted to the dynamic state table and the
- packet is released to the <acronym>LAN</acronym>. The packet
- generated as a response is recognized by the
- <literal>check-state</literal> rule as belonging to an
- existing session. It is then sent to rule
- <literal>1000</literal> to undergo
- <acronym>NAT</acronym> before being released to the outbound
- interface.</para>
-
- <note>
- <para>Transitioning from userland &man.natd.8; to in-kernel
- <acronym>NAT</acronym> might seem seamless at first but
- there is small catch. When using the GENERIC kernel,
- <application>IPFW</application> will load the
- <filename>libalias.ko</filename> kernel module, when
- <literal>firewall_nat_enable</literal> is enabled in
- <filename>rc.conf</filename>. The
- <filename>libalias.ko</filename> kernel module only provides
- basic <acronym>NAT</acronym> functionality, whereas the
- userland implementation &man.natd.8; has all
- <acronym>NAT</acronym> functionality available in its
- userland library without any extra configuration. All
- functionality refers to the following kernel modules that
- can additionally be loaded when needed besides the standard
- <filename>libalias.ko</filename> kernel module:
- <filename>alias_cuseeme.ko</filename>,
- <filename>alias_ftp.ko</filename>,
- <filename>alias_bbt.ko</filename>,
- <filename>skinny.ko</filename>, <filename>irc.ko</filename>,
- <filename>alias_pptp.ko</filename> and
- <filename>alias_smedia.ko</filename> using the
- <literal>kld_list</literal> directive in
- <filename>rc.conf</filename>. If a custom kernel is used,
- the full functionality of the userland library can be
- compiled in, in the kernel, using the <option>options
- LIBALIAS</option>.</para></note>
-
- <sect3>
- <title>Port Redirection</title>
-
- <para>The drawback with <acronym>NAT</acronym> in general is
- that the <acronym>LAN</acronym> clients are not accessible
- from the Internet. Clients on the <acronym>LAN</acronym>
- can make outgoing connections to the world but cannot
- receive incoming ones. This presents a problem if trying to
- run Internet services on one of the <acronym>LAN</acronym>
- client machines. A simple way around this is to redirect
- selected Internet ports on the <acronym>NAT</acronym>
- providing machine to a <acronym>LAN</acronym> client.</para>
-
- <para>For example, an <acronym>IRC</acronym> server runs on
- client <systemitem>A</systemitem> and a web server runs on
- client <systemitem>B</systemitem>. For this to work
- properly, connections received on ports 6667
- (<acronym>IRC</acronym>) and 80 (<acronym>HTTP</acronym>)
- must be redirected to the respective machines.</para>
-
- <para>With in-kernel <acronym>NAT</acronym> all configuration
- is done in the <acronym>NAT</acronym> instance
- configuration. For a full list of options that an in-kernel
- <acronym>NAT</acronym> instance can use, consult
- &man.ipfw.8;. The <application>IPFW</application> syntax
- follows the syntax of <application>natd</application>. The
- syntax for <option>redirect_port</option> is as
- follows:</para>
-
- <programlisting>redirect_port proto targetIP:targetPORT[-targetPORT]
- [aliasIP:]aliasPORT[-aliasPORT]
- [remoteIP[:remotePORT[-remotePORT]]]</programlisting>
-
- <para>To configure the above example setup, the arguments
- should be:</para>
-
- <programlisting>redirect_port tcp 192.168.0.2:6667 6667
-redirect_port tcp 192.168.0.3:80 80</programlisting>
-
- <para>After adding these arguments to the configuration of
- <acronym>NAT</acronym> instance 1 in the above ruleset, the
- <acronym>TCP</acronym> ports will be port forwarded to the
- <acronym>LAN</acronym> client machines running the
- <acronym>IRC</acronym> and <acronym>HTTP</acronym>
- services.</para>
-
- <programlisting>ipfw -q nat 1 config if &dollar;pif same_ports unreg_only reset \
- redirect_port tcp 192.168.0.2:6667 6667 \
- redirect_port tcp 192.168.0.3:80 80</programlisting>
-
- <para>Port ranges over individual ports can be indicated with
- <option>redirect_port</option>. For example,
- <replaceable>tcp 192.168.0.2:2000-3000
- 2000-3000</replaceable> would redirect all connections
- received on ports 2000 to 3000 to ports 2000 to 3000 on
- client <systemitem>A</systemitem>.</para>
- </sect3>
-
- <sect3>
- <title>Address Redirection</title>
-
- <para>Address redirection is useful if more than one
- <acronym>IP</acronym> address is available. Each
- <acronym>LAN</acronym> client can be assigned its own
- external <acronym>IP</acronym> address by &man.ipfw.8;,
- which will then rewrite outgoing packets from the
- <acronym>LAN</acronym> clients with the proper external
- <acronym>IP</acronym> address and redirects all traffic
- incoming on that particular <acronym>IP</acronym> address
- back to the specific <acronym>LAN</acronym> client. This is
- also known as static <acronym>NAT</acronym>. For example,
- if <acronym>IP</acronym> addresses <systemitem
- class="ipaddress">128.1.1.1</systemitem>, <systemitem
- class="ipaddress">128.1.1.2</systemitem>, and <systemitem
- class="ipaddress">128.1.1.3</systemitem> are available,
- <systemitem class="ipaddress">128.1.1.1</systemitem> can be
- used as the &man.ipfw.8; machine's external
- <acronym>IP</acronym> address, while <systemitem
- class="ipaddress">128.1.1.2</systemitem> and <systemitem
- class="ipaddress">128.1.1.3</systemitem> are forwarded
- back to <acronym>LAN</acronym> clients
- <systemitem>A</systemitem> and
- <systemitem>B</systemitem>.</para>
-
- <para>The <option>redirect_address</option> syntax is as
- below, where <literal>localIP</literal> is the internal
- <acronym>IP</acronym> address of the <acronym>LAN</acronym>
- client, and <literal>publicIP</literal> the external
- <acronym>IP</acronym> address corresponding to the
- <acronym>LAN</acronym> client.</para>
-
- <programlisting>redirect_address localIP publicIP</programlisting>
-
- <para>In the example, the arguments would read:</para>
-
- <programlisting>redirect_address 192.168.0.2 128.1.1.2
-redirect_address 192.168.0.3 128.1.1.3</programlisting>
-
- <para>Like <option>redirect_port</option>, these arguments
- are placed in a <acronym>NAT</acronym> instance
- configuration. With address redirection, there is no
- need for port redirection, as all data received on a
- particular <acronym>IP</acronym> address is
- redirected.</para>
-
- <para>The external <acronym>IP</acronym> addresses on the
- &man.ipfw.8; machine must be active and aliased to the
- external interface. Refer to &man.rc.conf.5; for
- details.</para>
- </sect3>
-
- <sect3>
- <title>Userspace <acronym>NAT</acronym></title>
-
- <para>Let us start with a statement: the userspace
- <acronym>NAT</acronym> implementation: &man.natd.8;, has
- more overhead than in-kernel <acronym>NAT</acronym>. For
- &man.natd.8; to translate packets, the packets have to be
- copied from the kernel to userspace and back which brings in
- extra overhead that is not present with in-kernel
- <acronym>NAT</acronym>.</para>
-
- <para>To enable the userpace <acronym>NAT</acronym> daemon
- &man.natd.8; at boot time, the following is a minimum
- configuration in <filename>/etc/rc.conf</filename>. Where
- <option>natd_interface</option> is set to the name of the
- <acronym>NIC</acronym> attached to the Internet. The
- &man.rc.8; script of &man.natd.8; will automatically check
- if a dynamic <acronym>IP</acronym> address is used and
- configure itself to handle that.</para>
-
- <programlisting>gateway_enable="YES"
-natd_enable="YES"
-natd_interface="rl0"</programlisting>
-
- <para>In general, the above ruleset as explained for in-kernel
- <acronym>NAT</acronym> can also be used together with
- &man.natd.8;. The exceptions are the configuration of the
- in-kernel <acronym>NAT</acronym> instance <literal>(ipfw -q
- nat 1 config ...)</literal> which is not needed together
- with reassemble rule 99 because its functionality is
- included in the <option>divert</option> action. Rule number
- 100 and 1000 will have to change sligthly as shown
- below.</para>
-
- <programlisting>&dollar;cmd 100 divert natd ip from any to any in via &dollar;pif
-&dollar;cmd 1000 divert natd ip from any to any out via &dollar;pif</programlisting>
-
- <para>To configure port or address redirection, a similar
- syntax as with in-kernel <acronym>NAT</acronym> is used.
- Although, now, instead of specifying the configuration in
- our ruleset script like with in-kernel
- <acronym>NAT</acronym>, configuration of &man.natd.8; is
- best done in a configuration file. To do this, an extra
- flag must be passed via <filename>/etc/rc.conf</filename>
- which specifies the path of the configuration file.</para>
-
- <programlisting>natd_flags="-f /etc/natd.conf"</programlisting>
-
- <note>
- <para>The specified file must contain a list of
- configuration options, one per line. For more information
- about the configuration file and possible variables,
- consult &man.natd.8;. Below are two example
- entries, one per line:</para>
-
- <programlisting>redirect_port tcp 192.168.0.2:6667 6667
-redirect_address 192.168.0.3 128.1.1.3</programlisting></note>
- </sect3>
- </sect2>
-
- <sect2 xml:id="firewalls-ipfw-cmd">
- <title>The <application>IPFW</application> Command</title>
-
- <indexterm><primary><command>ipfw</command></primary></indexterm>
-
- <para><command>ipfw</command> can be used to make manual,
- single rule additions or deletions to the active firewall
- while it is running. The problem with using this method is
- that all the changes are lost when the system reboots. It is
- recommended to instead write all the rules in a file and to
- use that file to load the rules at boot time and to replace
- the currently running firewall rules whenever that file
- changes.</para>
-
- <para><command>ipfw</command> is a useful way to display the
- running firewall rules to the console screen. The
- <application>IPFW</application> accounting facility
- dynamically creates a counter for each rule that counts each
- packet that matches the rule. During the process of testing a
- rule, listing the rule with its counter is one way to
- determine if the rule is functioning as expected.</para>
-
- <para>To list all the running rules in sequence:</para>
-
- <screen>&prompt.root; <userinput>ipfw list</userinput></screen>
-
- <para>To list all the running rules with a time stamp of when
- the last time the rule was matched:</para>
-
- <screen>&prompt.root; <userinput>ipfw -t list</userinput></screen>
-
- <para>The next example lists accounting information and the
- packet count for matched rules along with the rules
- themselves. The first column is the rule number, followed by
- the number of matched packets and bytes, followed by the rule
- itself.</para>
-
- <screen>&prompt.root; <userinput>ipfw -a list</userinput></screen>
-
- <para>To list dynamic rules in addition to static rules:</para>
-
- <screen>&prompt.root; <userinput>ipfw -d list</userinput></screen>
-
- <para>To also show the expired dynamic rules:</para>
-
- <screen>&prompt.root; <userinput>ipfw -d -e list</userinput></screen>
-
- <para>To zero the counters:</para>
-
- <screen>&prompt.root; <userinput>ipfw zero</userinput></screen>
-
- <para>To zero the counters for just the rule with number
- <replaceable>NUM</replaceable>:</para>
-
- <screen>&prompt.root; <userinput>ipfw zero <replaceable>NUM</replaceable></userinput></screen>
-
- <sect3>
- <title>Logging Firewall Messages</title>
-
- <indexterm>
- <primary><application>IPFW</application></primary>
-
- <secondary>logging</secondary>
- </indexterm>
-
- <para>Even with the logging facility enabled,
- <application>IPFW</application> will not generate any rule
- logging on its own. The firewall administrator decides
- which rules in the ruleset will be logged, and adds the
- <literal>log</literal> keyword to those rules. Normally
- only deny rules are logged. It is customary to duplicate
- the <quote>ipfw default deny everything</quote> rule with
- the <literal>log</literal> keyword included as the last rule
- in the ruleset. This way, it is possible to see all the
- packets that did not match any of the rules in the
- ruleset.</para>
-
- <para>Logging is a two edged sword. If one is not careful,
- an over abundance of log data or a DoS attack can fill the
- disk with log files. Log messages are not only written to
- <application>syslogd</application>, but also are displayed
- on the root console screen and soon become annoying.</para>
-
- <para>The <literal>IPFIREWALL_VERBOSE_LIMIT=5</literal>
- kernel option limits the number of consecutive messages
- sent to &man.syslogd.8;, concerning the packet matching of a
- given rule. When this option is enabled in the kernel, the
- number of consecutive messages concerning a particular rule
- is capped at the number specified. There is nothing to be
- gained from 200 identical log messages. With this option
- set to five,
- five consecutive messages concerning a particular rule
- would be logged to <application>syslogd</application> and
- the remainder identical consecutive messages would be
- counted and posted to <application>syslogd</application>
- with a phrase like the following:</para>
-
- <programlisting>last message repeated 45 times</programlisting>
-
- <para>All logged packets messages are written by default to
- <filename>/var/log/security</filename>, which is
- defined in <filename>/etc/syslog.conf</filename>.</para>
- </sect3>
-
- <sect3 xml:id="firewalls-ipfw-rules-script">
- <title>Building a Rule Script</title>
-
- <para>Most experienced <application>IPFW</application> users
- create a file containing the rules and code them in a manner
- compatible with running them as a script. The major benefit
- of doing this is the firewall rules can be refreshed in mass
- without the need of rebooting the system to activate them.
- This method is convenient in testing new rules as the
- procedure can be executed as many times as needed. Being a
- script, symbolic substitution can be used for frequently
- used values to be substituted into multiple rules.</para>
-
- <para>This example script is compatible with the syntax used
- by the &man.sh.1;, &man.csh.1;, and &man.tcsh.1; shells.
- Symbolic substitution fields are prefixed with a dollar sign
- (&dollar;). Symbolic fields do not have the &dollar;
- prefix. The value to populate the symbolic field must be
- enclosed in double quotes ("").</para>
-
- <para>Start the rules file like this:</para>
-
- <programlisting>############### start of example ipfw rules script #############
-#
-ipfw -q -f flush # Delete all rules
-# Set defaults
-oif="tun0" # out interface
-odns="192.0.2.11" # ISP's DNS server IP address
-cmd="ipfw -q add " # build rule prefix
-ks="keep-state" # just too lazy to key this each time
-&dollar;cmd 00500 check-state
-&dollar;cmd 00502 deny all from any to any frag
-&dollar;cmd 00501 deny tcp from any to any established
-&dollar;cmd 00600 allow tcp from any to any 80 out via &dollar;oif setup &dollar;ks
-&dollar;cmd 00610 allow tcp from any to &dollar;odns 53 out via &dollar;oif setup &dollar;ks
-&dollar;cmd 00611 allow udp from any to &dollar;odns 53 out via &dollar;oif &dollar;ks
-################### End of example ipfw rules script ############</programlisting>
-
- <para>The rules are not important as the focus of this example
- is how the symbolic substitution fields are
- populated.</para>
-
- <para>If the above example was in
- <filename>/etc/ipfw.rules</filename>, the rules could be
- reloaded by the following command:</para>
-
- <screen>&prompt.root; <userinput>sh /etc/ipfw.rules</userinput></screen>
-
- <para><filename>/etc/ipfw.rules</filename> can be located
- anywhere and the file can have any name.</para>
-
- <para>The same thing could be accomplished by running these
- commands by hand:</para>
-
- <screen>&prompt.root; <userinput>ipfw -q -f flush</userinput>
-&prompt.root; <userinput>ipfw -q add check-state</userinput>
-&prompt.root; <userinput>ipfw -q add deny all from any to any frag</userinput>
-&prompt.root; <userinput>ipfw -q add deny tcp from any to any established</userinput>
-&prompt.root; <userinput>ipfw -q add allow tcp from any to any 80 out via tun0 setup keep-state</userinput>
-&prompt.root; <userinput>ipfw -q add allow tcp from any to 192.0.2.11 53 out via tun0 setup keep-state</userinput>
-&prompt.root; <userinput>ipfw -q add 00611 allow udp from any to 192.0.2.11 53 out via tun0 keep-state</userinput></screen>
- </sect3>
- </sect2>
-
- <sect2 xml:id="firewalls-ipfw-kernelconfig">
- <title><application>IPFW</application> Kernel Options</title>
-
- <indexterm>
- <primary>kernel options</primary>
-
- <secondary>IPFIREWALL</secondary>
- </indexterm>
-
- <indexterm>
- <primary>kernel options</primary>
-
- <secondary>IPFIREWALL_VERBOSE</secondary>
- </indexterm>
-
- <indexterm>
- <primary>kernel options</primary>
-
- <secondary>IPFIREWALL_VERBOSE_LIMIT</secondary>
- </indexterm>
-
- <indexterm>
- <primary><application>IPFW</application></primary>
-
- <secondary>kernel options</secondary>
- </indexterm>
- <para>In order to statically compile
- <application>IPFW</application> support into a custom kernel,
- refer to the instructions in <xref linkend="kernelconfig"/>.
- The following options are available for the
- custom kernel configuration file:</para>
-
- <programlisting>options IPFIREWALL # enables IPFW
-options IPFIREWALL_VERBOSE # enables logging for rules with log keyword to syslogd(8)
-options IPFIREWALL_VERBOSE_LIMIT=5 # limits number of logged packets per-entry
-options IPFIREWALL_DEFAULT_TO_ACCEPT # sets default policy to pass what is not explicitly denied
-options IPFIREWALL_NAT # enables basic in-kernel NAT support
-options LIBALIAS # enables full in-kernel NAT support
-options IPFIREWALL_NAT64 # enables in-kernel NAT64 support
-options IPFIREWALL_NPTV6 # enables in-kernel IPv6 NPT support
-options IPFIREWALL_PMOD # enables protocols modification module support
-options IPDIVERT # enables NAT through natd(8)</programlisting>
-
- <note>
- <para><application>IPFW</application> can be loaded as
- a kernel module: options above are built by default
- as modules or can be set at runtime using tunables.</para>
- </note>
- </sect2>
- </sect1>
-
- <sect1 xml:id="firewalls-ipf">
- <title>IPFILTER (IPF)</title>
-
- <indexterm>
- <primary>firewall</primary>
-
- <secondary><application>IPFILTER</application></secondary>
- </indexterm>
-
- <para><application>IPFILTER</application>, also known as
- <application>IPF</application>, is a cross-platform, open source
- firewall which has been ported to several operating systems,
- including &os;, NetBSD, OpenBSD, and &solaris;.</para>
-
- <para><application>IPFILTER</application> is a kernel-side
- firewall and <acronym>NAT</acronym> mechanism that can be
- controlled and monitored by userland programs. Firewall rules
- can be set or deleted using <application>ipf</application>,
- <acronym>NAT</acronym> rules can be set or deleted using
- <application>ipnat</application>, run-time statistics for the
- kernel parts of <application>IPFILTER</application> can be
- printed using <application>ipfstat</application>, and
- <application>ipmon</application> can be used to log
- <application>IPFILTER</application> actions to the system log
- files.</para>
-
- <para><application>IPF</application> was originally written using
- a rule processing logic of <quote>the last matching rule
- wins</quote> and only used stateless rules. Since then,
- <application>IPF</application> has been enhanced to include the
- <literal>quick</literal> and <literal>keep state</literal>
- options.</para>
-
- <para>The <application>IPF</application> FAQ is at <uri
- xlink:href="http://www.phildev.net/ipf/index.html">http://www.phildev.net/ipf/index.html</uri>.
- A searchable archive of the IPFilter mailing list is available
- at <uri
- xlink:href="http://marc.info/?l=ipfilter">http://marc.info/?l=ipfilter</uri>.</para>
-
- <para>This section of the Handbook focuses on
- <application>IPF</application> as it pertains to FreeBSD. It
- provides examples of rules that contain the
- <literal>quick</literal> and <literal>keep state</literal>
- options.</para>
-
- <sect2>
- <title>Enabling <application>IPF</application></title>
-
- <indexterm>
- <primary><application>IPFILTER</application></primary>
-
- <secondary>enabling</secondary>
- </indexterm>
-
- <para><application>IPF</application> is included in the basic
- &os; install as a kernel loadable module, meaning that a
- custom kernel is not needed in order to enable
- <application>IPF</application>.</para>
-
- <indexterm>
- <primary>kernel options</primary>
-
- <secondary><application>IPFILTER</application></secondary>
- </indexterm>
-
- <indexterm>
- <primary>kernel options</primary>
-
- <secondary>IPFILTER_LOG</secondary>
- </indexterm>
-
- <indexterm>
- <primary>kernel options</primary>
-
- <secondary>IPFILTER_DEFAULT_BLOCK</secondary>
- </indexterm>
-
- <indexterm>
- <primary><application>IPFILTER</application></primary>
-
- <secondary>kernel options</secondary>
- </indexterm>
-
- <para>For users who prefer to statically compile
- <application>IPF</application> support into a custom kernel,
- refer to the instructions in <xref linkend="kernelconfig"/>.
- The following kernel options are available:</para>
-
- <programlisting>options IPFILTER
-options IPFILTER_LOG
-options IPFILTER_LOOKUP
-options IPFILTER_DEFAULT_BLOCK</programlisting>
-
- <para>where <literal>options IPFILTER</literal> enables support
- for <application>IPFILTER</application>,
- <literal>options IPFILTER_LOG</literal> enables
- <application>IPF</application> logging using the
- <filename>ipl</filename> packet logging pseudo-device for
- every rule that has the <literal>log</literal> keyword,
- <literal>IPFILTER_LOOKUP</literal> enables
- <acronym>IP</acronym> pools in order to speed up
- <acronym>IP</acronym> lookups, and <literal>options
- IPFILTER_DEFAULT_BLOCK</literal> changes the default
- behavior so that any packet not matching a firewall
- <literal>pass</literal> rule gets blocked.</para>
-
- <para>To configure the system to enable
- <application>IPF</application> at boot time, add the following
- entries to <filename>/etc/rc.conf</filename>. These entries
- will also enable logging and <literal>default pass
- all</literal>. To change the default policy to
- <literal>block all</literal> without compiling a custom
- kernel, remember to add a <literal>block all</literal> rule at
- the end of the ruleset.</para>
-
- <programlisting>ipfilter_enable="YES" # Start ipf firewall
-ipfilter_rules="/etc/ipf.rules" # loads rules definition text file
-ipv6_ipfilter_rules="/etc/ipf6.rules" # loads rules definition text file for IPv6
-ipmon_enable="YES" # Start IP monitor log
-ipmon_flags="-Ds" # D = start as daemon
- # s = log to syslog
- # v = log tcp window, ack, seq
- # n = map IP &amp; port to names</programlisting>
-
- <para>If <acronym>NAT</acronym> functionality is needed, also
- add these lines:</para>
-
- <programlisting>gateway_enable="YES" # Enable as LAN gateway
-ipnat_enable="YES" # Start ipnat function
-ipnat_rules="/etc/ipnat.rules" # rules definition file for ipnat</programlisting>
-
- <para>Then, to start <application>IPF</application> now:</para>
-
- <programlisting>&prompt.root; <userinput>service ipfilter start</userinput></programlisting>
-
- <para>To load the firewall rules, specify the name of the
- ruleset file using <command>ipf</command>. The following
- command can be used to replace the currently running firewall
- rules:</para>
-
- <screen>&prompt.root; <userinput>ipf -Fa -f /etc/ipf.rules</userinput></screen>
-
- <para>where <option>-Fa</option> flushes all the internal rules
- tables and <option>-f</option> specifies the file containing
- the rules to load.</para>
-
- <para>This provides the ability to make changes to a custom
- ruleset and update the running firewall with a fresh copy of
- the rules without having to reboot the system. This method is
- convenient for testing new rules as the procedure can be
- executed as many times as needed.</para>
-
- <para>Refer to &man.ipf.8; for details on the other flags
- available with this command.</para>
- </sect2>
-
- <sect2>
- <title><application>IPF</application> Rule Syntax</title>
-
- <indexterm>
- <primary><application>IPFILTER</application></primary>
-
- <secondary>rule syntax</secondary>
- </indexterm>
-
- <para>This section describes the <application>IPF</application>
- rule syntax used to create stateful rules. When creating
- rules, keep in mind that unless the <literal>quick</literal>
- keyword appears in a rule, every rule is read in order, with
- the <emphasis>last matching rule</emphasis> being the one
- that is applied. This means that even if the first rule to
- match a packet is a <literal>pass</literal>, if there is a
- later matching rule that is a <literal>block</literal>, the
- packet will be dropped. Sample rulesets can be found in
- <filename
- >/usr/share/examples/ipfilter</filename>.</para>
-
- <para>When creating rules, a <literal>#</literal> character is
- used to mark the start of a comment and may appear at the end
- of a rule, to explain that rule's function, or on its own
- line. Any blank lines are ignored.</para>
-
- <para>The keywords which are used in rules must be written in a
- specific order, from left to right. Some keywords are
- mandatory while others are optional. Some keywords have
- sub-options which may be keywords themselves and also include
- more sub-options. The keyword order is as follows, where the
- words shown in uppercase represent a variable and the words
- shown in lowercase must precede the variable that follows
- it:</para>
-
- <para><replaceable>ACTION DIRECTION OPTIONS proto PROTO_TYPE
- from SRC_ADDR SRC_PORT to DST_ADDR DST_PORT
- TCP_FLAG|ICMP_TYPE keep state STATE</replaceable></para>
-
- <para>This section describes each of these keywords and their
- options. It is not an exhaustive list of every possible
- option. Refer to &man.ipf.5; for a complete description of
- the rule syntax that can be used when creating
- <application>IPF</application> rules and examples for using
- each keyword.</para>
-
- <variablelist>
- <varlistentry>
- <term>ACTION</term>
- <listitem>
- <para>The action keyword indicates what to do with the
- packet if it matches that rule. Every rule
- <emphasis>must</emphasis> have an action. The
- following actions are recognized:</para>
-
- <para><literal>block</literal>: drops the packet.</para>
-
- <para><literal>pass</literal>: allows the packet.</para>
-
- <para><literal>log</literal>: generates a log
- record.</para>
-
- <para><literal>count</literal>: counts the number of
- packets and bytes which can provide an indication of
- how often a rule is used.</para>
-
- <para><literal>auth</literal>: queues the packet for
- further processing by another program.</para>
-
- <para><literal>call</literal>: provides access to
- functions built into <application>IPF</application> that
- allow more complex actions.</para>
-
- <para><literal>decapsulate</literal>: removes any headers
- in order to process the contents of the packet.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>DIRECTION</term>
- <listitem>
- <para>Next, each rule must explicitly state the direction
- of traffic using one of these keywords:</para>
-
- <para><literal>in</literal>: the rule is applied against
- an inbound packet.</para>
-
- <para><literal>out</literal>: the rule is applied against
- an outbound packet.</para>
-
- <para><literal>all</literal>: the rule applies to either
- direction.</para>
-
- <para>If the system has multiple interfaces, the interface
- can be specified along with the direction. An example
- would be <literal>in on fxp0</literal>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>OPTIONS</term>
- <listitem>
- <para>Options are optional. However, if multiple options
- are specified, they must be used in the order shown
- here.</para>
-
- <para><literal>log</literal>: when performing the
- specified ACTION, the contents of the packet's headers
- will be written to the &man.ipl.4; packet log
- pseudo-device.</para>
-
- <para><literal>quick</literal>: if a packet matches this
- rule, the ACTION specified by the rule occurs and no
- further processing of any following rules will occur for
- this packet.</para>
-
- <para><literal>on</literal>: must be followed by the
- interface name as displayed by &man.ifconfig.8;. The
- rule will only match if the packet is going through the
- specified interface in the specified direction.</para>
-
- <para>When using the
- <literal>log</literal> keyword, the following qualifiers
- may be used in this order:</para>
-
- <para><literal>body</literal>: indicates that the first
- 128 bytes of the packet contents will be logged after
- the headers.</para>
-
- <para><literal>first</literal>: if the
- <literal>log</literal> keyword is being used in
- conjunction with a <literal>keep state</literal> option,
- this option is recommended so that only the triggering
- packet is logged and not every packet which matches the
- stateful connection.</para>
-
- <para>Additional options are available to specify error
- return messages. Refer to &man.ipf.5; for more
- details.</para>
-
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>PROTO_TYPE</term>
- <listitem>
- <para>The protocol type is optional. However, it is
- mandatory if the rule needs to specify a SRC_PORT or
- a DST_PORT as it defines the type of protocol. When
- specifying the type of protocol, use the
- <literal>proto</literal> keyword followed by either a
- protocol number or name from
- <filename>/etc/protocols</filename>.
- Example protocol names include <literal>tcp</literal>,
- <literal>udp</literal>, or <literal>icmp</literal>. If
- PROTO_TYPE is specified but no SRC_PORT or DST_PORT is
- specified, all port numbers for that protocol will match
- that rule.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>SRC_ADDR</term>
- <listitem>
- <para>The <literal>from</literal> keyword is mandatory and
- is followed by a keyword which represents the source of
- the packet. The source can be a hostname, an
- <acronym>IP</acronym> address followed by the
- <acronym>CIDR</acronym> mask, an address pool, or the
- keyword <literal>all</literal>. Refer to &man.ipf.5;
- for examples.</para>
-
- <para>There is no way to match ranges of
- <acronym>IP</acronym> addresses which do not express
- themselves easily using the dotted numeric form /
- mask-length notation. The
- <package>net-mgmt/ipcalc</package> package or port may
- be used to ease the calculation of the
- <acronym>CIDR</acronym> mask. Additional information is
- available at the utility's web page: <uri
- xlink:href="http://jodies.de/ipcalc">http://jodies.de/ipcalc</uri>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>SRC_PORT</term>
- <listitem>
- <para>The port number of the source is optional. However,
- if it is used, it requires PROTO_TYPE to be first
- defined in the rule. The port number must also be
- preceded by the <literal>proto</literal> keyword.</para>
-
- <para>A number of different comparison operators are
- supported: <literal>=</literal> (equal to),
- <literal>!=</literal> (not equal to),
- <literal>&lt;</literal> (less than),
- <literal>&gt;</literal> (greater than),
- <literal>&lt;=</literal> (less than or equal to), and
- <literal>&gt;=</literal> (greater than or equal
- to).</para>
-
- <para>To specify port ranges, place the two port numbers
- between <literal>&lt;&gt;</literal> (less than and
- greater than ), <literal>&gt;&lt;</literal> (greater
- than and less than ), or <literal>:</literal> (greater
- than or equal to and less than or equal to).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>DST_ADDR</term>
- <listitem>
- <para>The <literal>to</literal> keyword is mandatory and
- is followed by a keyword which represents the
- destination of the packet. Similar to SRC_ADDR, it can
- be a hostname, an <acronym>IP</acronym> address
- followed by the <acronym>CIDR</acronym> mask, an address
- pool, or the keyword <literal>all</literal>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>DST_PORT</term>
- <listitem>
- <para>Similar to SRC_PORT, the port number of the
- destination is optional. However, if it is used, it
- requires PROTO_TYPE to be first defined in the rule.
- The port number must also be preceded by the
- <literal>proto</literal> keyword.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>TCP_FLAG|ICMP_TYPE</term>
- <listitem>
- <para>If <literal>tcp</literal> is specified as the
- PROTO_TYPE, flags can be specified as letters, where
- each letter represents one of the possible
- <acronym>TCP</acronym> flags used to determine the state
- of a connection. Possible values are:
- <literal>S</literal> (SYN),
- <literal>A</literal> (ACK),
- <literal>P</literal> (PSH),
- <literal>F</literal> (FIN),
- <literal>U</literal> (URG),
- <literal>R</literal> (RST),
- <literal>C</literal> (CWN), and
- <literal>E</literal> (ECN).</para>
-
- <para>If <literal>icmp</literal> is specified as the
- PROTO_TYPE, the <acronym>ICMP</acronym> type to match
- can be specified. Refer to &man.ipf.5; for the
- allowable types.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>STATE</term>
- <listitem>
- <para>If a <literal>pass</literal> rule contains
- <literal>keep state</literal>,
- <application>IPF</application> will add an entry to its
- dynamic state table and allow subsequent packets that
- match the connection.
- <application>IPF</application> can track state for
- <acronym>TCP</acronym>, <acronym>UDP</acronym>, and
- <acronym>ICMP</acronym> sessions. Any packet that
- <application>IPF</application> can be certain is part of
- an active session, even if it is a different protocol,
- will be allowed.</para>
-
- <para>In <application>IPF</application>, packets destined
- to go out through the interface connected to the public
- Internet are first checked against the dynamic state
- table. If the packet matches the next expected packet
- comprising an active session conversation, it exits the
- firewall and the state of the session conversation flow
- is updated in the dynamic state table. Packets that do
- not belong to an already active session are checked
- against the outbound ruleset. Packets coming in from
- the interface connected to the public Internet are first
- checked against the dynamic state table. If the packet
- matches the next expected packet comprising an active
- session, it exits the firewall and the state of the
- session conversation flow is updated in the dynamic
- state table. Packets that do not belong to an already
- active session are checked against the inbound
- ruleset.</para>
-
- <para>Several keywords can be added after
- <literal>keep state</literal>. If used, these keywords
- set various options that control stateful filtering,
- such as setting connection limits or connection age.
- Refer to &man.ipf.5; for the list of available options
- and their descriptions.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2>
- <title>Example Ruleset</title>
-
- <para>This section demonstrates how to create an example ruleset
- which only allows services matching
- <literal>pass</literal> rules and blocks all others.</para>
-
- <para>&os; uses the loopback interface
- (<filename>lo0</filename>) and the <acronym>IP</acronym>
- address <systemitem class="ipaddress">127.0.0.1</systemitem>
- for internal communication. The firewall ruleset must contain
- rules to allow free movement of these internally used
- packets:</para>
-
- <programlisting># no restrictions on loopback interface
-pass in quick on lo0 all
-pass out quick on lo0 all</programlisting>
-
- <para>The public interface connected to the Internet is used to
- authorize and control access of all outbound and inbound
- connections. If one or more interfaces are cabled to private
- networks, those internal interfaces may require rules to allow
- packets originating from the <acronym>LAN</acronym> to flow
- between the internal networks or to the interface attached to
- the Internet. The ruleset should be organized into three
- major sections: any trusted internal interfaces, outbound
- connections through the public interface, and inbound
- connections through the public interface.</para>
-
- <para>These two rules allow all traffic to pass through a
- trusted <acronym>LAN</acronym> interface named
- <filename>xl0</filename>:</para>
-
- <programlisting># no restrictions on inside LAN interface for private network
-pass out quick on xl0 all
-pass in quick on xl0 all</programlisting>
-
- <para>The rules for the public interface's outbound and inbound
- sections should have the most frequently matched rules placed
- before less commonly matched rules, with the last rule in the
- section blocking and logging all packets for that interface
- and direction.</para>
-
- <para>This set of rules defines the outbound section of the
- public interface named <filename>dc0</filename>. These rules
- keep state and identify the specific services that internal
- systems are authorized for public Internet access. All the
- rules use <literal>quick</literal> and specify the
- appropriate port numbers and, where applicable, destination
- addresses.</para>
-
- <programlisting># interface facing Internet (outbound)
-# Matches session start requests originating from or behind the
-# firewall, destined for the Internet.
-
-# Allow outbound access to public DNS servers.
-# Replace x.x.x. with address listed in /etc/resolv.conf.
-# Repeat for each DNS server.
-pass out quick on dc0 proto tcp from any to x.x.x. port = 53 flags S keep state
-pass out quick on dc0 proto udp from any to xxx port = 53 keep state
-
-# Allow access to ISP's specified DHCP server for cable or DSL networks.
-# Use the first rule, then check log for the IP address of DHCP server.
-# Then, uncomment the second rule, replace z.z.z.z with the IP address,
-# and comment out the first rule
-pass out log quick on dc0 proto udp from any to any port = 67 keep state
-#pass out quick on dc0 proto udp from any to z.z.z.z port = 67 keep state
-
-# Allow HTTP and HTTPS
-pass out quick on dc0 proto tcp from any to any port = 80 flags S keep state
-pass out quick on dc0 proto tcp from any to any port = 443 flags S keep state
-
-# Allow email
-pass out quick on dc0 proto tcp from any to any port = 110 flags S keep state
-pass out quick on dc0 proto tcp from any to any port = 25 flags S keep state
-
-# Allow NTP
-pass out quick on dc0 proto tcp from any to any port = 37 flags S keep state
-
-# Allow FTP
-pass out quick on dc0 proto tcp from any to any port = 21 flags S keep state
-
-# Allow SSH
-pass out quick on dc0 proto tcp from any to any port = 22 flags S keep state
-
-# Allow ping
-pass out quick on dc0 proto icmp from any to any icmp-type 8 keep state
-
-# Block and log everything else
-block out log first quick on dc0 all</programlisting>
-
- <para>This example of the rules in the inbound section of the
- public interface blocks all undesirable packets first. This
- reduces the number of packets that are logged by the last
- rule.</para>
-
- <programlisting># interface facing Internet (inbound)
-# Block all inbound traffic from non-routable or reserved address spaces
-block in quick on dc0 from 192.168.0.0/16 to any #RFC 1918 private IP
-block in quick on dc0 from 172.16.0.0/12 to any #RFC 1918 private IP
-block in quick on dc0 from 10.0.0.0/8 to any #RFC 1918 private IP
-block in quick on dc0 from 127.0.0.0/8 to any #loopback
-block in quick on dc0 from 0.0.0.0/8 to any #loopback
-block in quick on dc0 from 169.254.0.0/16 to any #DHCP auto-config
-block in quick on dc0 from 192.0.2.0/24 to any #reserved for docs
-block in quick on dc0 from 204.152.64.0/23 to any #Sun cluster interconnect
-block in quick on dc0 from 224.0.0.0/3 to any #Class D &amp; E multicast
-
-# Block fragments and too short tcp packets
-block in quick on dc0 all with frags
-block in quick on dc0 proto tcp all with short
-
-# block source routed packets
-block in quick on dc0 all with opt lsrr
-block in quick on dc0 all with opt ssrr
-
-# Block OS fingerprint attempts and log first occurrence
-block in log first quick on dc0 proto tcp from any to any flags FUP
-
-# Block anything with special options
-block in quick on dc0 all with ipopts
-
-# Block public pings and ident
-block in quick on dc0 proto icmp all icmp-type 8
-block in quick on dc0 proto tcp from any to any port = 113
-
-# Block incoming Netbios services
-block in log first quick on dc0 proto tcp/udp from any to any port = 137
-block in log first quick on dc0 proto tcp/udp from any to any port = 138
-block in log first quick on dc0 proto tcp/udp from any to any port = 139
-block in log first quick on dc0 proto tcp/udp from any to any port = 81</programlisting>
-
- <para>Any time there are logged messages on a rule with
- the <literal>log first</literal> option, run
- <command>ipfstat -hio</command> to evaluate how many times the
- rule has been matched. A large number of matches may indicate
- that the system is under attack.</para>
-
- <para>The rest of the rules in the inbound section define which
- connections are allowed to be initiated from the Internet.
- The last rule denies all connections which were not explicitly
- allowed by previous rules in this section.</para>
-
- <programlisting># Allow traffic in from ISP's DHCP server. Replace z.z.z.z with
-# the same IP address used in the outbound section.
-pass in quick on dc0 proto udp from z.z.z.z to any port = 68 keep state
-
-# Allow public connections to specified internal web server
-pass in quick on dc0 proto tcp from any to x.x.x.x port = 80 flags S keep state
-
-# Block and log only first occurrence of all remaining traffic.
-block in log first quick on dc0 all</programlisting>
- </sect2>
-
- <sect2>
- <title>Configuring <acronym>NAT</acronym></title>
-
- <indexterm><primary>NAT</primary></indexterm>
-
- <indexterm>
- <primary>IP masquerading</primary>
-
- <see>NAT</see>
- </indexterm>
-
- <indexterm>
- <primary>network address translation</primary>
-
- <see>NAT</see>
- </indexterm>
-
- <indexterm><primary><command>ipnat</command></primary></indexterm>
-
- <para>To enable <acronym>NAT</acronym>, add these statements
- to <filename>/etc/rc.conf</filename> and specify the name of
- the file containing the <acronym>NAT</acronym> rules:</para>
-
- <programlisting>gateway_enable="YES"
-ipnat_enable="YES"
-ipnat_rules="/etc/ipnat.rules"</programlisting>
-
- <para><acronym>NAT</acronym> rules are flexible and can
- accomplish many different things to fit the needs of both
- commercial and home users. The rule syntax presented here has
- been simplified to demonstrate common usage. For a complete
- rule syntax description, refer to &man.ipnat.5;.</para>
-
- <para>The basic syntax for a <acronym>NAT</acronym> rule is as
- follows, where <literal>map</literal> starts the rule and
- <replaceable>IF</replaceable> should be replaced with the
- name of the external interface:</para>
-
- <programlisting>map <replaceable>IF</replaceable> <replaceable>LAN_IP_RANGE</replaceable> -&gt; <replaceable>PUBLIC_ADDRESS</replaceable></programlisting>
-
- <para>The <replaceable>LAN_IP_RANGE</replaceable> is the range
- of <acronym>IP</acronym> addresses used by internal clients.
- Usually, it is a private address range such as <systemitem
- class="ipaddress">192.168.1.0/24</systemitem>. The
- <replaceable>PUBLIC_ADDRESS</replaceable> can either be the
- static external <acronym>IP</acronym> address or the keyword
- <literal>0/32</literal> which represents the
- <acronym>IP</acronym> address assigned to
- <replaceable>IF</replaceable>.</para>
-
- <para>In <application>IPF</application>, when a packet arrives
- at the firewall from the <acronym>LAN</acronym> with a public
- destination, it first passes through the outbound rules of the
- firewall ruleset. Then, the packet is passed to the
- <acronym>NAT</acronym> ruleset which is read from the top
- down, where the first matching rule wins.
- <application>IPF</application> tests each
- <acronym>NAT</acronym> rule against the packet's interface
- name and source <acronym>IP</acronym> address. When a
- packet's interface name matches a <acronym>NAT</acronym> rule,
- the packet's source <acronym>IP</acronym> address in the
- private <acronym>LAN</acronym> is checked to see if it falls
- within the <acronym>IP</acronym> address range specified in
- <replaceable>LAN_IP_RANGE</replaceable>. On a match, the
- packet has its source <acronym>IP</acronym> address rewritten
- with the public <acronym>IP</acronym> address specified by
- <replaceable>PUBLIC_ADDRESS</replaceable>.
- <application>IPF</application> posts an entry in its internal
- <acronym>NAT</acronym> table so that when the packet returns
- from the Internet, it can be mapped back to its original
- private <acronym>IP</acronym> address before being passed to
- the firewall rules for further processing.</para>
-
- <para>For networks that have large numbers of internal systems
- or multiple subnets, the process of funneling every private
- <acronym>IP</acronym> address into a single public
- <acronym>IP</acronym> address becomes a resource problem.
- Two methods are available to relieve this issue.</para>
-
- <para>The first method is to assign a range of ports to use as
- source ports. By adding the <literal>portmap</literal>
- keyword, <acronym>NAT</acronym> can be directed to only use
- source ports in the specified range:</para>
-
- <programlisting>map dc0 192.168.1.0/24 -&gt; 0/32 portmap tcp/udp 20000:60000</programlisting>
-
- <para>Alternately, use the <literal>auto</literal> keyword
- which tells <acronym>NAT</acronym> to determine the ports
- that are available for use:</para>
-
- <programlisting>map dc0 192.168.1.0/24 -&gt; 0/32 portmap tcp/udp auto</programlisting>
-
- <para>The second method is to use a pool of public addresses.
- This is useful when there are too many
- <acronym>LAN</acronym> addresses to fit into a single public
- address and a block of public <acronym>IP</acronym> addresses
- is available. These public addresses can be used as a pool
- from which <acronym>NAT</acronym> selects an
- <acronym>IP</acronym> address as a packet's address is
- mapped on its way out.</para>
-
- <para>The range of public <acronym>IP</acronym> addresses can
- be specified using a netmask or <acronym>CIDR</acronym>
- notation. These two rules are equivalent:</para>
-
- <programlisting>map dc0 192.168.1.0/24 -&gt; 204.134.75.0/255.255.255.0
-map dc0 192.168.1.0/24 -&gt; 204.134.75.0/24</programlisting>
-
- <para>A common practice is to have a publically accessible web
- server or mail server segregated to an internal network
- segment. The traffic from these servers still has to undergo
- <acronym>NAT</acronym>, but port redirection is needed to
- direct inbound traffic to the correct server. For example, to
- map a web server using the internal address <systemitem
- class="ipaddress">10.0.10.25</systemitem> to its public
- <acronym>IP</acronym> address of <systemitem
- class="ipaddress">20.20.20.5</systemitem>, use this
- rule:</para>
-
- <programlisting>rdr dc0 20.20.20.5/32 port 80 -&gt; 10.0.10.25 port 80</programlisting>
-
- <para>If it is the only web server, this rule would also work as
- it redirects all external <acronym>HTTP</acronym> requests to
- <literal>10.0.10.25</literal>:</para>
-
- <programlisting>rdr dc0 0.0.0.0/0 port 80 -&gt; 10.0.10.25 port 80</programlisting>
-
- <para><application>IPF</application> has a built in
- <acronym>FTP</acronym> proxy which can be used with
- <acronym>NAT</acronym>. It monitors all outbound traffic for
- active or passive <acronym>FTP</acronym> connection requests
- and dynamically creates temporary filter rules containing the
- port number used by the <acronym>FTP</acronym> data channel.
- This eliminates the need to open large ranges of high order
- ports for <acronym>FTP</acronym> connections.</para>
-
- <para>In this example, the first rule calls the proxy for
- outbound <acronym>FTP</acronym> traffic from the internal
- <acronym>LAN</acronym>. The second rule passes the
- <acronym>FTP</acronym> traffic from the firewall to the
- Internet, and the third rule handles all
- non-<acronym>FTP</acronym> traffic from the internal
- <acronym>LAN</acronym>:</para>
-
- <programlisting>map dc0 10.0.10.0/29 -&gt; 0/32 proxy port 21 ftp/tcp
-map dc0 0.0.0.0/0 -&gt; 0/32 proxy port 21 ftp/tcp
-map dc0 10.0.10.0/29 -&gt; 0/32</programlisting>
-
- <para>The <acronym>FTP</acronym> <literal>map</literal> rules go
- before the <acronym>NAT</acronym> rule so that when a packet
- matches an <acronym>FTP</acronym> rule, the
- <acronym>FTP</acronym> proxy creates temporary filter rules to
- let the <acronym>FTP</acronym> session packets pass and
- undergo <acronym>NAT</acronym>. All LAN packets that are not
- <acronym>FTP</acronym> will not match the
- <acronym>FTP</acronym> rules but will undergo
- <acronym>NAT</acronym> if they match the third rule.</para>
-
- <para>Without the <acronym>FTP</acronym> proxy, the following
- firewall rules would instead be needed. Note that without the
- proxy, all ports above <literal>1024</literal> need to be
- allowed:</para>
-
- <programlisting># Allow out LAN PC client FTP to public Internet
-# Active and passive modes
-pass out quick on rl0 proto tcp from any to any port = 21 flags S keep state
-
-# Allow out passive mode data channel high order port numbers
-pass out quick on rl0 proto tcp from any to any port &gt; 1024 flags S keep state
-
-# Active mode let data channel in from FTP server
-pass in quick on rl0 proto tcp from any to any port = 20 flags S keep state</programlisting>
-
- <para>Whenever the file containing the <acronym>NAT</acronym>
- rules is edited, run <command>ipnat</command> with
- <option>-CF</option> to delete the current
- <acronym>NAT</acronym> rules and flush the contents of the
- dynamic translation table. Include <option>-f</option> and
- specify the name of the <acronym>NAT</acronym> ruleset to
- load:</para>
-
- <screen>&prompt.root; <userinput>ipnat -CF -f /etc/ipnat.rules</userinput></screen>
-
- <para>To display the <acronym>NAT</acronym> statistics:</para>
-
- <screen>&prompt.root; <userinput>ipnat -s</userinput></screen>
-
- <para>To list the <acronym>NAT</acronym> table's current
- mappings:</para>
-
- <screen>&prompt.root; <userinput>ipnat -l</userinput></screen>
-
- <para>To turn verbose mode on and display information relating
- to rule processing and active rules and table entries:</para>
-
- <screen>&prompt.root; <userinput>ipnat -v</userinput></screen>
- </sect2>
-<!--
-This section is confusing and may no longer be needed with new syntax.
- <sect2 xml:id="firewalls-ipf-rules-script">
- <title>Building the Rule Script with Symbolic
- Substitution</title>
-
- <para>Some experienced IPF users create a file containing the
- rules and code them in a manner compatible with running them
- as a script with symbolic substitution. The major benefit
- of doing this is that only the value associated with the
- symbolic name needs to be changed, and when the script is
- run all the rules containing the symbolic name will have the
- value substituted in the rules. Being a script, symbolic
- substitution can be used to code frequently used values and
- substitute them in multiple rules. This can be seen in the
- following example.</para>
-
- <para>The script syntax used here is compatible with the
- &man.sh.1;, &man.csh.1;, and &man.tcsh.1; shells.</para>
-
- <para>Symbolic substitution fields are prefixed with a
- <literal>&dollar;</literal>.</para>
-
- <para>Symbolic fields do not have the &dollar; prefix.</para>
-
- <para>The value to populate the symbolic field must be enclosed
- between double quotes (<literal>"</literal>).</para>
-
- <para>Start the rule file with something like this:</para>
-
- <programlisting>############# Start of IPF rules script ########################
-
-oif="dc0" # name of the outbound interface
-odns="192.0.2.11" # ISP's DNS server IP address
-myip="192.0.2.7" # my static IP address from ISP
-ks="keep state"
-fks="flags S keep state"
-
-# You can choose between building /etc/ipf.rules file
-# from this script or running this script "as is".
-#
-# Uncomment only one line and comment out another.
-#
-# 1) This can be used for building /etc/ipf.rules:
-#cat &gt; /etc/ipf.rules &lt;&lt; EOF
-#
-# 2) This can be used to run script "as is":
-/sbin/ipf -Fa -f - &lt;&lt; EOF
-
-# Allow out access to my ISP's Domain name server.
-pass out quick on &dollar;oif proto tcp from any to &dollar;odns port = 53 &dollar;fks
-pass out quick on &dollar;oif proto udp from any to &dollar;odns port = 53 &dollar;ks
-
-# Allow out non-secure standard www function
-pass out quick on &dollar;oif proto tcp from &dollar;myip to any port = 80 &dollar;fks
-
-# Allow out secure www function https over TLS SSL
-pass out quick on &dollar;oif proto tcp from &dollar;myip to any port = 443 &dollar;fks
-EOF
-################## End of IPF rules script ########################</programlisting>
-
- <para>The rules are not important in this example as it instead
- focuses on how the symbolic substitution fields are populated.
- If this example was in a file named
- <filename>/etc/ipf.rules.script</filename>, these rules could
- be reloaded by running:</para>
-
- <screen>&prompt.root; <userinput>sh /etc/ipf.rules.script</userinput></screen>
-
- <para>There is one problem with using a rules file with embedded
- symbolics: IPF does not understand symbolic substitution, and
- cannot read such scripts directly.</para>
-
- <para>This script can be used in one of two ways:</para>
-
- <itemizedlist>
- <listitem>
- <para>Uncomment the line that begins with
- <literal>cat</literal>, and comment out the line that
- begins with <literal>/sbin/ipf</literal>. Place
- <literal>ipfilter_enable="YES"</literal> into
- <filename>/etc/rc.conf</filename>, and run the script
- once after each modification to create or update
- <filename>/etc/ipf.rules</filename>.</para>
- </listitem>
-
- <listitem>
- <para>Disable <application>IPFILTER</application> in the
- system startup scripts by adding
- <literal>ipfilter_enable="NO"</literal>to
- <filename>/etc/rc.conf</filename>.</para>
-
- <para>Then, add a script like the following to
- <filename>/usr/local/etc/rc.d/</filename>. The script
- should have an obvious name like
- <filename>ipf.loadrules.sh</filename>, where the
- <filename>.sh</filename> extension is mandatory.</para>
-
- <programlisting>#!/bin/sh
-sh /etc/ipf.rules.script</programlisting>
-
- <para>The permissions on this script file must be read,
- write, execute for owner
- <systemitem class="username">root</systemitem>:</para>
-
- <screen>&prompt.root; <userinput>chmod 700 /usr/local/etc/rc.d/ipf.loadrules.sh</userinput></screen>
- </listitem>
- </itemizedlist>
-
- <para>Now, when the system boots, the IPF rules will be
- loaded.</para>
- </sect2>
- -->
- <sect2>
- <title>Viewing <application>IPF</application> Statistics</title>
-
- <indexterm><primary><command>ipfstat</command></primary></indexterm>
-
- <indexterm>
- <primary><application>IPFILTER</application></primary>
-
- <secondary>statistics</secondary>
- </indexterm>
-
- <para><application>IPF</application> includes &man.ipfstat.8;
- which can be used to retrieve
- and display statistics which are gathered
- as packets match rules as they go through the
- firewall. Statistics are accumulated since the firewall was
- last started or since the last time they
- were reset to zero using <command>ipf
- -Z</command>.</para>
-
- <para>The default <command>ipfstat</command> output looks
- like this:</para>
-
- <screen>input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
- output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
- input packets logged: blocked 99286 passed 0
- output packets logged: blocked 0 passed 0
- packets logged: input 0 output 0
- log failures: input 3898 output 0
- fragment state(in): kept 0 lost 0
- fragment state(out): kept 0 lost 0
- packet state(in): kept 169364 lost 0
- packet state(out): kept 431395 lost 0
- ICMP replies: 0 TCP RSTs sent: 0
- Result cache hits(in): 1215208 (out): 1098963
- IN Pullups succeeded: 2 failed: 0
- OUT Pullups succeeded: 0 failed: 0
- Fastroute successes: 0 failures: 0
- TCP cksum fails(in): 0 (out): 0
- Packet log flags set: (0)</screen>
-
- <para>Several options are available. When supplied with either
- <option>-i</option> for inbound or <option>-o</option> for
- outbound, the command will retrieve and display the
- appropriate list of filter rules currently installed and in
- use by the kernel. To also see the rule numbers, include
- <option>-n</option>. For example, <command>ipfstat
- -on</command> displays the outbound rules table with rule
- numbers:</para>
-
- <screen>@1 pass out on xl0 from any to any
-@2 block out on dc0 from any to any
-@3 pass out quick on dc0 proto tcp/udp from any to any keep state</screen>
-
- <para>Include <option>-h</option> to prefix each rule with a
- count of how many times the rule was matched. For example,
- <command>ipfstat -oh</command> displays the outbound internal
- rules table, prefixing each rule with its usage count:</para>
-
- <screen>2451423 pass out on xl0 from any to any
-354727 block out on dc0 from any to any
-430918 pass out quick on dc0 proto tcp/udp from any to any keep state</screen>
-
- <para>To display the state table in a format similar to
- &man.top.1;, use <command>ipfstat -t</command>. When the
- firewall is under attack, this option provides the ability to
- identify and see the attacking packets. The optional
- sub-flags give the ability to select the destination or source
- <acronym>IP</acronym>, port, or protocol to be monitored in
- real time. Refer to &man.ipfstat.8; for details.</para>
- </sect2>
-
- <sect2>
- <title><application>IPF</application> Logging</title>
-
- <indexterm><primary><command>ipmon</command></primary></indexterm>
-
- <indexterm>
- <primary><application>IPFILTER</application></primary>
-
- <secondary>logging</secondary>
- </indexterm>
-
- <para><application>IPF</application> provides
- <command>ipmon</command>, which can be used to write the
- firewall's logging information in a human readable format. It
- requires that <literal>options IPFILTER_LOG</literal> be first
- added to a custom kernel using the instructions in <xref
- linkend="kernelconfig"/>.</para>
-
- <para>This command is typically run in daemon mode in order to
- provide a continuous system log file so that logging of past
- events may be reviewed. Since &os; has a built in
- &man.syslogd.8; facility to automatically rotate system logs,
- the default <filename>rc.conf</filename>
- <literal>ipmon_flags</literal> statement uses
- <option>-Ds</option>:</para>
-
- <programlisting>ipmon_flags="-Ds" # D = start as daemon
- # s = log to syslog
- # v = log tcp window, ack, seq
- # n = map IP &amp; port to names</programlisting>
-
- <para>Logging provides the ability to review, after the fact,
- information such as which packets were dropped, what addresses
- they came from, and where they were going. This information
- is useful in tracking down attackers.</para>
-
- <para>Once the logging facility is enabled in
- <filename>rc.conf</filename> and started with <command>service
- ipmon start</command>, <application>IPF</application> will
- only log the rules which contain the <literal>log</literal>
- keyword. The firewall administrator decides which rules in
- the ruleset should be logged and normally only deny rules are
- logged. It is customary to include the
- <literal>log</literal> keyword in the last rule in the
- ruleset. This makes it possible to see all the packets that
- did not match any of the rules in the ruleset.</para>
-
- <para>By default, <command>ipmon -Ds</command> mode uses
- <literal>local0</literal> as the logging facility. The
- following logging levels can be used to further segregate the
- logged data:</para>
-
- <screen>LOG_INFO - packets logged using the "log" keyword as the action rather than pass or block.
-LOG_NOTICE - packets logged which are also passed
-LOG_WARNING - packets logged which are also blocked
-LOG_ERR - packets which have been logged and which can be considered short due to an incomplete header</screen>
-
- <para>In order to setup <application>IPF</application> to
- log all data to <filename>/var/log/ipfilter.log</filename>,
- first create the empty file:</para>
-
- <screen>&prompt.root; <userinput>touch /var/log/ipfilter.log</userinput></screen>
-
- <para>Then, to write all logged messages to the specified file,
- add the following statement to
- <filename>/etc/syslog.conf</filename>:</para>
-
- <programlisting>local0.* /var/log/ipfilter.log</programlisting>
-
- <para>To activate the changes and instruct &man.syslogd.8;
- to read the modified <filename>/etc/syslog.conf</filename>,
- run <command>service syslogd reload</command>.</para>
-
- <para>Do not forget to edit
- <filename>/etc/newsyslog.conf</filename> to rotate the new
- log file.</para>
-
- <para>Messages generated by <command>ipmon</command> consist
- of data fields separated by white space. Fields common to
- all messages are:</para>
-
- <orderedlist>
- <listitem>
- <para>The date of packet receipt.</para>
- </listitem>
-
- <listitem>
- <para>The time of packet receipt. This is in the form
- HH:MM:SS.F, for hours, minutes, seconds, and fractions
- of a second.</para>
- </listitem>
-
- <listitem>
- <para>The name of the interface that processed the
- packet.</para>
- </listitem>
-
- <listitem>
- <para>The group and rule number of the rule in the format
- <literal>@0:17</literal>.</para>
- </listitem>
-
- <listitem>
- <para>The action: <literal>p</literal> for passed,
- <literal>b</literal> for blocked, <literal>S</literal> for
- a short packet, <literal>n</literal> did not match any
- rules, and <literal>L</literal> for a log rule.</para>
- </listitem>
-
- <listitem>
- <para>The addresses written as three fields: the source
- address and port separated by a comma, the -&gt; symbol,
- and the destination address and port. For example:
- <literal>209.53.17.22,80 -&gt;
- 198.73.220.17,1722</literal>.</para>
- </listitem>
-
- <listitem>
- <para><literal>PR</literal> followed by the protocol name
- or number: for example, <literal>PR tcp</literal>.</para>
- </listitem>
-
- <listitem>
- <para><literal>len</literal> followed by the header length
- and total length of the packet: for example,
- <literal>len 20 40</literal>.</para>
- </listitem>
- </orderedlist>
-
- <para>If the packet is a <acronym>TCP</acronym> packet, there
- will be an additional field starting with a hyphen followed by
- letters corresponding to any flags that were set. Refer to
- &man.ipf.5; for a list of letters and their flags.</para>
-
- <para>If the packet is an <acronym>ICMP</acronym> packet, there
- will be two fields at the end: the first always being
- <quote>icmp</quote> and the next being the
- <acronym>ICMP</acronym> message and sub-message type,
- separated by a slash. For example:
- <literal>icmp 3/3</literal> for a port unreachable
- message.</para>
- </sect2>
- </sect1>
-
- <sect1 xml:id="firewalls-blacklistd">
- <title>Blacklistd</title>
-
- <para>Blacklistd is a daemon listening to sockets to receive
- notifications from other daemons about connection attempts
- that failed or were successful. It is most widely used in
- blocking too many connection attempts on open ports. A
- prime example is <application>SSH</application> running on
- the internet getting a lot of requests from bots or scripts
- trying to guess passwords and gain access. Using
- <application>blacklistd</application>, the daemon can notify
- the firewall to create a filter rule to block excessive
- connection attempts from a single source after a number of
- tries. Blacklistd was first developed on
- NetBSD and appeared there in version 7. &os;&nbsp;11
- imported blacklistd from NetBSD.</para>
-
- <para>This chapter describes how to set up blacklistd,
- configure it, and provides examples on how to use it.
- Readers should be familiar with basic firewall concepts like
- rules. For details, refer to the firewall chapter. PF is
- used in the examples, but other firewalls available on
- &os; should be able to work with blacklistd, too.</para>
-
- <sect2>
- <title>Enabling Blacklistd</title>
-
- <para>The main configuration for blacklistd is stored in
- &man.blacklistd.conf.5;. Various command line options are
- also available to change blacklistd's run-time behavior.
- Persistent configuration across reboots should be stored
- in <filename>/etc/blacklistd.conf</filename>. To enable
- the daemon during system boot, add a
- <literal>blacklistd_enable</literal> line to
- <filename>/etc/rc.conf</filename> like this:</para>
-
- <screen>&prompt.root; <userinput>sysrc blacklistd_enable=yes</userinput></screen>
-
- <para>To start the service manually, run this command:</para>
-
- <screen>&prompt.root; <userinput>service blacklistd start</userinput></screen>
- </sect2>
-
- <sect2>
- <title>Creating a Blacklistd Ruleset</title>
-
- <para>Rules for blacklistd are configured in
- &man.blacklistd.conf.5; with one entry per line. Each
- rule contains a tuple separated by spaces or tabs. Rules
- either belong to a <literal>local</literal> or a
- <literal>remote</literal>, which applies to the machine
- where blacklistd is running or an outside source,
- respectively.</para>
-
- <sect3>
- <title>Local Rules</title>
-
- <para>An example blacklistd.conf entry for a local rule
- looks like this:</para>
-
- <programlisting>[local]
-ssh stream * * * 3 24h</programlisting>
-
- <para>All rules that follow the <literal>[local]</literal>
- section are treated as local rules (which is the
- default), applying to the local machine. When a
- <literal>[remote]</literal> section is encountered, all
- rules that follow it are handled as remote machine
- rules.</para>
-
- <para>Seven fields define a rule separated by either tabs
- or spaces. The first four fields identify the traffic
- that should be blacklisted. The three fields that
- follow define backlistd's behavior. Wildcards are
- denoted as asterisks (<literal>*</literal>), matching
- anything in this field. The first field defines the
- location. In local rules, these are the network ports.
- The syntax for the location field is as follows:</para>
-
- <programlisting>[<replaceable>address</replaceable>|<replaceable>interface</replaceable>][/<replaceable>mask</replaceable>][:<replaceable>port</replaceable>]</programlisting>
-
- <para>Adressses can be specified as IPv4 in numeric format
- or IPv6 in square brackets. An interface name like
- <literal><replaceable>em0</replaceable></literal> can also
- be used.</para>
-
- <para>The socket type is defined by the second field. TCP
- sockets are of type <literal>stream</literal>, whereas UDP
- is denoted as <literal>dgram</literal>. The example above
- uses TCP, since SSH is using that protocol.</para>
-
- <para>A protocol can be used in the third field of a
- blacklistd rule. The following protocols can be used:
- <literal>tcp</literal>, <literal>udp</literal>,
- <literal>tcp6</literal>, <literal>udp6</literal>, or
- numeric. A wildcard, like in the example, is typically
- used to match all protocols unless there is a reason to
- distinguish traffic by a certain protocol.</para>
-
- <para>In the fourth field, the effective user or owner of
- the daemon process that is reporting the event is defined.
- The username or <acronym>UID</acronym> can be used here,
- as well as a wildcard (see example rule above).</para>
-
- <para>The packet filter rule name is declared by the fifth
- field, which starts the behavior part of the rule. By
- default, blacklistd puts all blocks under a pf anchor
- called <literal>blacklistd</literal> in
- <filename>pf.conf</filename> like this:</para>
-
- <programlisting>anchor "blacklistd/*" in on $ext_if
-block in
-pass out</programlisting>
-
- <para>For separate blacklists, an anchor name can be used in
- this field. In other cases, the wildcard will suffice.
- When a name starts with a hyphen (<literal>-</literal>) it
- means that an anchor with the default rule name prepended
- should be used. A modified example from the above using
- the hyphen would look like this:</para>
-
- <programlisting>ssh stream * * -ssh 3 24h</programlisting>
-
- <para>With such a rule, any new blacklist rules are added to
- an anchor called <literal>blacklistd-ssh</literal>.</para>
-
- <para>To block whole subnets for a single rule violation, a
- <literal>/</literal> in the rule name can be used. This
- causes the remaining portion of the name to be interpreted
- as the mask to be applied to the address specified in
- the rule. For example, this rule would block every
- address adjoining <literal>/24</literal>.</para>
-
- <programlisting>22 stream tcp * */24 3 24h</programlisting>
-
- <note>
- <para>It is important to specify the proper
- protocol here. IPv4 and IPv6 treat /24 differently,
- that is the reason why <literal>*</literal> cannot be
- used in the third field for this rule.</para>
- </note>
-
- <para>This rule defines that if any one host in that network
- is misbehaving, everything else on that network will be
- blocked, too.</para>
-
- <para>The sixth field, called <literal>nfail</literal>, sets
- the number of login failures required to blacklist the
- remote IP in question. When a wildcard is used at this
- position, it means that blocks will never happen. In the
- example rule above, a limit of three is defined meaning
- that after three attempts to log into
- <application>SSH</application> on one connection, the IP
- is blocked.</para>
-
- <para>The last field in a blacklistd rule definition
- specifies how long a host is blacklisted. The default
- unit is seconds, but suffixes like <literal>m</literal>,
- <literal>h</literal>, and <literal>d</literal> can also be
- specified for minutes, hours, and days,
- respectively.</para>
-
- <para>The example rule in its entirety means that after
- three times authenticating to
- <application>SSH</application> will result in a new PF
- block rule for that host. Rule matches are performed by
- first checking local rules one after another, from most
- specific to least specific. When a match occurs, the
- <literal>remote</literal> rules are applied and the name,
- <literal>nfail</literal>, and disable fields are changed
- by the <literal>remote</literal> rule that matched.</para>
- </sect3>
-
- <sect3>
- <title>Remote Rules</title>
-
- <para>Remote rules are used to specify how blacklistd
- changes its behavior depending on the remote host
- currently being evaluated. Each field in a remote rule
- is the same as in a local rule. The only difference is
- in the way blacklistd is using them. To explain it,
- this example rule is used:</para>
-
- <programlisting>[remote]
-203.0.113.128/25 * * * =/25 = 48h</programlisting>
-
- <para>The address field can be an IP address (either v4 or
- v6), a port or both. This allows setting special rules
- for a specific remote address range like in this example.
- The fields for type, protocol and owner are identically
- interpreted as in the local rule.</para>
-
- <para>The name fields is different though: the equal sign
- (<literal>=</literal>) in a remote rule tells blacklistd
- to use the value from the matching local rule. It means
- that the firewall rule entry is taken and the
- <systemitem class="netmask">/25</systemitem> prefix (a
- netmask of <systemitem
- class="netmask">255.255.255.128</systemitem>) is added.
- When a connection from that address range is blacklisted,
- the entire subnet is affected. A PF anchor name can also
- be used here, in which case blacklistd will add rules for
- this address block to the anchor of that name. The
- default table is used when a wildcard is specified.</para>
-
- <para>A custom number of failures in the
- <literal>nfail</literal> column can be defined for an
- address. This is useful for exceptions to a specific
- rule, to maybe allow someone a less strict application
- of rules or a bit more leniency in login tries.
- Blocking is disabled when an asterisk is used in this
- sixth field.</para>
-
- <para>Remote rules allow a stricter enforcement of limits
- on attempts to log in compared to attempts coming from a
- local network like an office.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Blacklistd Client Configuration</title>
-
- <para>There are a few software packages in &os; that can
- utilize blacklistd's functionality. The two most
- prominent ones are &man.ftpd.8; and &man.sshd.8; to block
- excessive connection attempts. To activate blacklistd in
- the SSH daemon, add the following line to
- <filename>/etc/ssh/sshd_config</filename>:</para>
-
- <programlisting>UseBlacklist yes</programlisting>
-
- <para>Restart sshd afterwards to make these changes take
- effect.</para>
-
- <para>Blacklisting for &man.ftpd.8; is enabled using
- <literal>-B</literal>, either in
- <filename>/etc/inetd.conf</filename> or as a
- flag in <filename>/etc/rc.conf</filename> like
- this:</para>
-
- <programlisting>ftpd_flags="-B"</programlisting>
-
- <para>That is all that is needed to make these programs
- talk to blacklistd.</para>
- </sect2>
-
- <sect2>
- <title>Blacklistd Management</title>
-
- <para>Blacklistd provides the user with a management utility
- called &man.blacklistctl.8;. It displays blocked
- addresses and networks that are blacklisted by the rules
- defined in &man.blacklistd.conf.5;. To see the
- list of currently blocked hosts, use
- <command>dump</command> combined with <option>-b</option>
- like this.</para>
-
- <screen>&prompt.root; <userinput>blacklistctl dump -b</userinput>
- address/ma:port id nfail last access
-213.0.123.128/25:22 OK 6/3 2019/06/08 14:30:19</screen>
-
- <para>This example shows that there were 6 out of three
- permitted attempts on port 22 coming from the address
- range <systemitem
- class="netmask">213.0.123.128/25</systemitem>. There
- are more attempts listed than are allowed because SSH
- allows a client to try multiple logins on a single TCP
- connection. A connection that is currently going on is
- not stopped by blacklistd. The last connection attempt is
- listed in the <literal>last access</literal> column of the
- output.</para>
-
- <para>To see the remaining time that this host will be on
- the blacklist, add <option>-r</option> to the previous
- command.</para>
-
- <screen>&prompt.root; <userinput>blacklistctl dump -br</userinput>
- address/ma:port id nfail remaining time
-213.0.123.128/25:22 OK 6/3 36s</screen>
-
- <para>In this example, there are 36s seconds left until this
- host will not be blocked any more.</para>
- </sect2>
-
- <sect2>
- <title>Removing Hosts from the Block List</title>
-
- <para>Sometimes it is necessary to remove a host from the
- block list before the remaining time expires.
- Unfortunately, there is no functionality in blacklistd to
- do that. However, it is possible to remove the address
- from the PF table using pfctl. For each blocked port,
- there is a child anchor inside the blacklistd anchor
- defined in <filename>/etc/pf.conf</filename>. For
- example, if there is a child anchor for blocking port 22
- it is called <literal>blacklistd/22</literal>. There is a
- table inside that child anchor that contains the blocked
- addresses. This table is called port followed by the port
- number. In this example, it would be called
- <literal>port22</literal>. With that information at hand,
- it is now possible to use &man.pfctl.8; to display all
- addresses listed like this:</para>
-
- <screen>&prompt.root; <userinput>pfctl -a <replaceable>blacklistd/22</replaceable> -t <replaceable>port22</replaceable> -T show</userinput>
-...
-213.0.123.128/25
-...</screen>
-
- <para>After identifying the address to be unblocked from the
- list, the following command removes it from the list:</para>
-
- <screen>&prompt.root; <userinput>pfctl -a <replaceable>blacklistd/22</replaceable> -t <replaceable>port22</replaceable> -T delete <replaceable>213.0.123.128/25</replaceable></userinput></screen>
-
- <para>The address is now removed from PF, but will still
- show up in the blacklistctl list, since it does not know
- about any changes made in PF. The entry in blacklistd's
- database will eventually expire and be removed from its
- output eventually. The entry will be added again if the
- host is matching one of the block rules in blacklistd
- again.</para>
- </sect2>
- </sect1>
-</chapter>