4578 lines
179 KiB
XML
4578 lines
179 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!--
|
|
The FreeBSD Documentation Project
|
|
|
|
$FreeBSD$
|
|
-->
|
|
|
|
<chapter id="firewalls">
|
|
<chapterinfo>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Joseph J.</firstname>
|
|
<surname>Barbish</surname>
|
|
<contrib>Contributed by </contrib>
|
|
</author>
|
|
</authorgroup>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Brad</firstname>
|
|
<surname>Davis</surname>
|
|
<contrib>Converted to SGML and updated by </contrib>
|
|
</author>
|
|
</authorgroup>
|
|
</chapterinfo>
|
|
|
|
<title>Firewalls</title>
|
|
|
|
<indexterm><primary>firewall</primary></indexterm>
|
|
|
|
<indexterm>
|
|
<primary>security</primary>
|
|
|
|
<secondary>firewalls</secondary>
|
|
</indexterm>
|
|
|
|
<sect1 id="firewalls-intro">
|
|
<title>Introduction</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>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>IPFILTER</application> firewall.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>How to use and configure the
|
|
<application>IPFW</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>
|
|
</sect1>
|
|
|
|
<sect1 id="firewalls-concepts">
|
|
<title>Firewall Concepts</title>
|
|
|
|
<indexterm>
|
|
<primary>firewall</primary>
|
|
|
|
<secondary>rulesets</secondary>
|
|
</indexterm>
|
|
|
|
<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. The
|
|
disadvantage of a stateful firewall is that it can be vulnerable
|
|
to Denial of Service (<acronym>DoS</acronym>) attacks if a lot
|
|
of new connections are opened very fast. Most firewalls use a
|
|
combination of stateful and non-stateful behavior.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="firewalls-apps">
|
|
<title>Firewall Packages</title>
|
|
|
|
<para>&os; has three firewalls built into the base system:
|
|
<emphasis>IPFILTER</emphasis>, also known as
|
|
<acronym>IPF</acronym>, <emphasis>IPFIREWALL</emphasis>, also
|
|
known as <acronym>IPFW</acronym>, and <acronym>PF</acronym>).
|
|
&os; also provides two traffic shapers for controlling bandwidth
|
|
usage: &man.altq.4; and &man.dummynet.4;. Dummynet has
|
|
traditionally been closely tied with <acronym>IPFW</acronym>,
|
|
and <acronym>ALTQ</acronym> with <acronym>PF</acronym>. 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>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 <ulink
|
|
url="http://www.ipprimer.com/overview.cfm">Daryl's TCP/IP
|
|
Primer</ulink>.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="firewalls-pf">
|
|
<sect1info>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>John</firstname>
|
|
<surname>Ferrell</surname>
|
|
<contrib>Revised and updated by </contrib>
|
|
<!-- 24 March 2008 -->
|
|
</author>
|
|
</authorgroup>
|
|
</sect1info>
|
|
|
|
<title>PF and <acronym>ALTQ</acronym></title>
|
|
|
|
<indexterm>
|
|
<primary>firewall</primary>
|
|
|
|
<secondary>PF</secondary>
|
|
</indexterm>
|
|
|
|
<para>Since &os; 5.3, a ported version of OpenBSD's
|
|
<acronym>PF</acronym> firewall has been included as an
|
|
integrated part of the base system. <acronym>PF</acronym> is a
|
|
complete, full-featured firewall that has optional support for
|
|
<acronym>ALTQ</acronym> (Alternate Queuing), which provides
|
|
Quality of Service (<acronym>QoS</acronym>).</para>
|
|
|
|
<para>Since the OpenBSD Project maintains the definitive
|
|
reference for <acronym>PF</acronym> in the<ulink
|
|
url="http://www.openbsd.org/faq/pf/">PF FAQ</ulink>, this
|
|
section of the Handbook focuses on <acronym>PF</acronym> as it
|
|
pertains to &os;, while providing some general usage
|
|
information.</para>
|
|
|
|
<para>More information about porting <acronym>PF</acronym> to &os;
|
|
can be found at <ulink
|
|
url="http://pf4freebsd.love2party.net/"></ulink>.</para>
|
|
|
|
<sect2>
|
|
<title>Using the PF Loadable Kernel Modules</title>
|
|
|
|
<para>In order to use PF, the PF kernel module must be first
|
|
loaded. Add the following line to
|
|
<filename>/etc/rc.conf</filename>:</para>
|
|
|
|
<programlisting>pf_enable="YES"</programlisting>
|
|
|
|
<para>Then, run the startup script to load the module:</para>
|
|
|
|
<screen>&prompt.root; <userinput>service pf start</userinput></screen>
|
|
|
|
<para>The PF module will not load if it cannot find the
|
|
ruleset configuration file. The default location is
|
|
<filename>/etc/pf.conf</filename>. If the PF ruleset is
|
|
located 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>The sample <filename>pf.conf</filename>
|
|
can be found in <filename
|
|
class="directory">/usr/share/examples/pf/</filename>.</para>
|
|
|
|
<para>The <acronym>PF</acronym> module can also be loaded
|
|
manually from the command line:</para>
|
|
|
|
<screen>&prompt.root; <userinput>kldload pf.ko</userinput></screen>
|
|
|
|
<para>Logging support for PF is provided by
|
|
<varname>pflog.ko</varname> which can be loaded by adding the
|
|
following line to <filename>/etc/rc.conf</filename>:</para>
|
|
|
|
<programlisting>pflog_enable="YES"</programlisting>
|
|
|
|
<para>Then, run the startup script to load the module:</para>
|
|
|
|
<screen>&prompt.root; <userinput>service pflog start</userinput></screen>
|
|
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>PF Kernel Options</title>
|
|
|
|
<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>
|
|
|
|
<para>While it is not necessary to compile
|
|
<acronym>PF</acronym> support into the &os; kernel, some of
|
|
PF's advanced features are not included in the loadable
|
|
module, namely &man.pfsync.4;, which is a pseudo-device that
|
|
exposes certain changes to the state table used by
|
|
<acronym>PF</acronym>. It can be paired with &man.carp.4; to
|
|
create failover firewalls using <acronym>PF</acronym>. More
|
|
information on <acronym>CARP</acronym> can be found in <link
|
|
linkend="carp">of the Handbook</link>.</para>
|
|
|
|
<para>The following <acronym>PF</acronym> kernel options can be
|
|
found in <filename>/usr/src/sys/conf/NOTES</filename>:</para>
|
|
|
|
<programlisting>device pf
|
|
device pflog
|
|
device pfsync</programlisting>
|
|
|
|
<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>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Available <filename>rc.conf</filename> Options</title>
|
|
|
|
<para>The following &man.rc.conf.5; statements can be used to
|
|
configure <acronym>PF</acronym> and &man.pflog.4; at
|
|
boot:</para>
|
|
|
|
<programlisting>pf_enable="YES" # Enable PF (load module if required)
|
|
pf_rules="/etc/pf.conf" # rules definition file for pf
|
|
pf_flags="" # additional flags for pfctl startup
|
|
pflog_enable="YES" # start pflogd(8)
|
|
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
|
|
pflog_flags="" # additional flags for pflogd startup</programlisting>
|
|
|
|
<para>If there is a LAN behind the firewall and packets need to
|
|
be forwarded for the computers on the LAN, or NAT is required,
|
|
add the following option:</para>
|
|
|
|
<programlisting>gateway_enable="YES" # Enable as LAN gateway</programlisting>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Creating Filtering Rules</title>
|
|
|
|
<para>By default, <acronym>PF</acronym> 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
|
|
<ulink url="http://www.openbsd.org/faq/pf/">PF FAQ</ulink> for
|
|
complete coverage of <acronym>PF</acronym> rulesets.</para>
|
|
|
|
<warning>
|
|
<para>When reading the <ulink
|
|
url="http://www.openbsd.org/faq/pf/">PF FAQ</ulink>,
|
|
keep in mind that different versions of &os; contain
|
|
different versions of PF. Currently,
|
|
&os; 8.<replaceable>X</replaceable> is using the
|
|
same version of <acronym>PF</acronym> as
|
|
OpenBSD 4.1. &os; 9.<replaceable>X</replaceable>
|
|
and later is using the same version of <acronym>PF</acronym>
|
|
as OpenBSD 4.5.</para>
|
|
</warning>
|
|
|
|
<para>The &a.pf; is a good place to ask questions about
|
|
configuring and running the <acronym>PF</acronym> firewall.
|
|
Do not forget to check the mailing list archives before asking
|
|
questions.</para>
|
|
<para>To control <acronym>PF</acronym>, use &man.pfctl.8;.
|
|
Below are some useful options to this command. Review
|
|
&man.pfctl.8; for a description of all available
|
|
options:</para>
|
|
|
|
<informaltable frame="none" pgwide="1">
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Command</entry>
|
|
<entry>Purpose</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><command>pfctl
|
|
<option>-e</option></command></entry>
|
|
<entry>Enable PF.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><command>pfctl
|
|
<option>-d</option></command></entry>
|
|
<entry>Disable PF.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><command>pfctl <option>-F</option> all
|
|
<option>-f</option> /etc/pf.conf</command></entry>
|
|
<entry>Flush all NAT, filter, state, and table
|
|
rules and reload
|
|
<filename>/etc/pf.conf</filename>.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><command>pfctl <option>-s</option> [ rules | nat
|
|
state ]</command></entry>
|
|
<entry>Report on the filter rules, NAT rules, or state
|
|
table.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><command>pfctl <option>-vnf</option>
|
|
/etc/pf.conf</command></entry>
|
|
<entry>Check <filename>/etc/pf.conf</filename> for
|
|
errors, but do not load ruleset.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Enabling <acronym>ALTQ</acronym></title>
|
|
|
|
<para><acronym>ALTQ</acronym> is only available by compiling its
|
|
support into the &os; kernel. <acronym>ALTQ</acronym> is not
|
|
supported by all network card drivers. Refer to &man.altq.4;
|
|
for a list of drivers that are supported by the release of
|
|
&os;.</para>
|
|
|
|
<para>The following kernel options will enable
|
|
<acronym>ALTQ</acronym> and add additional
|
|
functionality:</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)
|
|
options ALTQ_NOPCC # Required for SMP build</programlisting>
|
|
|
|
<para><literal>options ALTQ</literal> enables the
|
|
<acronym>ALTQ</acronym> framework.</para>
|
|
|
|
<para><literal>options ALTQ_CBQ</literal> enables
|
|
<emphasis>Class Based Queuing</emphasis>
|
|
(<acronym>CBQ</acronym>). <acronym>CBQ</acronym>
|
|
can be used to divide a connection's bandwidth into different
|
|
classes or queues to prioritize traffic based on filter
|
|
rules.</para>
|
|
|
|
<para><literal>options ALTQ_RED</literal> enables
|
|
<emphasis>Random Early Detection</emphasis>
|
|
(<acronym>RED</acronym>). <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. If the queue is over the maximum,
|
|
all new packets will be dropped. <acronym>RED</acronym> drops
|
|
packets from different connections randomly.</para>
|
|
|
|
<para><literal>options ALTQ_RIO</literal> enables
|
|
<emphasis>Random Early Detection In and Out</emphasis>.</para>
|
|
|
|
<para><literal>options ALTQ_HFSC</literal> enables the
|
|
<emphasis>Hierarchical Fair Service Curve Packet
|
|
Scheduler</emphasis> <acronym>HFSC</acronym>. For more
|
|
information, refer to <ulink
|
|
url="http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html"></ulink>.</para>
|
|
|
|
<para><literal>options ALTQ_PRIQ</literal> enables
|
|
<emphasis>Priority Queuing</emphasis>
|
|
(<acronym>PRIQ</acronym>). <acronym>PRIQ</acronym> will
|
|
always pass traffic that is in a higher queue first.</para>
|
|
|
|
<para><literal>options ALTQ_NOPCC</literal> enables
|
|
<acronym>SMP</acronym> support for <acronym>ALTQ</acronym>.
|
|
This option is required on <acronym>SMP</acronym>
|
|
systems.</para>
|
|
</sect2>
|
|
|
|
<sect2 id="pf-tutorial">
|
|
<sect2info>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Peter</firstname>
|
|
<surname>Hansteen</surname>
|
|
<othername>N. M.</othername>
|
|
<contrib>Contributed by </contrib>
|
|
</author>
|
|
</authorgroup>
|
|
</sect2info>
|
|
|
|
<title><acronym>PF</acronym> Rule Sets and Tools</title>
|
|
|
|
<para>This section demonstrates some useful
|
|
<acronym>PF</acronym> features and <acronym>PF</acronym>
|
|
related tools in a series of examples. A more thorough
|
|
tutorial is available at <ulink
|
|
url="http://home.nuug.no/~peter/pf/">http://home.nuug.no/~peter/pf/</ulink>.</para>
|
|
|
|
<tip>
|
|
<para><filename role="package">security/sudo</filename> is
|
|
useful for running commands like <command>pfctl</command>
|
|
that require elevated privileges. It can be installed from
|
|
the Ports Collection.</para>
|
|
</tip>
|
|
|
|
<sect3 id="pftut-simplest">
|
|
<title>The Simplest Rule Set Ever</title>
|
|
|
|
<para>The simplest possible setup is for a single machine
|
|
which will not run any services, and which will talk to one
|
|
network which may be the Internet. A minimal
|
|
<filename>/etc/pf.conf</filename> looks like this:</para>
|
|
|
|
<programlisting>block in all
|
|
pass out all keep state</programlisting>
|
|
|
|
<para>Here we deny any incoming traffic, allow traffic we make
|
|
ourselves to pass, and retain state information on our
|
|
connections. Keeping state information allows return
|
|
traffic for all connections we have initiated to pass back
|
|
to us. This rule set is used on machines that can be
|
|
trusted. The rule set can be loaded with</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -e ; pfctl -f /etc/pf.conf</userinput></screen>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Tighter and More Elegant</title>
|
|
|
|
<para>For a slightly more structured and complete setup, we
|
|
start by denying everything and then allowing only those
|
|
things we know that we need
|
|
<footnote><para>Why write the rule set to default deny? The
|
|
short answer is, it gives better control at the expense
|
|
of some thinking. The point of packet filtering is to
|
|
take control, not to run catch-up with what the bad guys
|
|
do. Marcus Ranum has written a very entertaining and
|
|
informative article about this, <ulink
|
|
url="http://www.ranum.com/security/computer_security/editorials/dumb/index.html">The
|
|
Six Dumbest Ideas in Computer Security</ulink>, and
|
|
it is well written too.</para></footnote>. This gives
|
|
us the opportunity to introduce two of the features which
|
|
make <acronym>PF</acronym> such a wonderful tool:
|
|
<firstterm>lists</firstterm> and
|
|
<firstterm>macros</firstterm>.</para>
|
|
|
|
<para>We will make some changes to
|
|
<filename>/etc/pf.conf</filename>, starting with</para>
|
|
|
|
<programlisting>block all</programlisting>
|
|
|
|
<para>Then we back up a little. Macros need to be defined
|
|
before use, so at the very top of the file, we add:</para>
|
|
|
|
<programlisting>tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
|
|
udp_services = "{ domain }"</programlisting>
|
|
|
|
<para>Now we have demonstrated several things at once - what
|
|
macros look like, that macros may be lists, and that
|
|
<acronym>PF</acronym> understands rules using port names
|
|
equally well as it does port numbers. The names are the
|
|
ones listed in <filename>/etc/services</filename>. This
|
|
gives us something to put in our rules, which we edit
|
|
slightly to look like this:</para>
|
|
|
|
<programlisting>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>At this point some of us will point out that UDP is
|
|
stateless, but <acronym>PF</acronym> actually manages to
|
|
maintain state information despite this. Keeping state for
|
|
a UDP connection means that for example when you ask a name
|
|
server about a domain name, you will be able to receive its
|
|
answer.</para>
|
|
|
|
<para>Since we have made changes to our
|
|
<filename>pf.conf</filename>, we load the new
|
|
rules:</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -f /etc/pf.conf</userinput></screen>
|
|
|
|
<para>and the new rules are applied. If there are no syntax
|
|
errors, <command>pfctl</command> will not output any
|
|
messages during the rule load. The <option>-v</option> flag
|
|
will produce more verbose <command>pfctl</command>
|
|
output.</para>
|
|
|
|
<para>If there have been extensive changes to the rule set,
|
|
the rules can be tested before attempting to load them. The
|
|
command to do this is</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -nf /etc/pf.conf</userinput></screen>
|
|
|
|
<para><option>-n</option> causes the rules to be interpreted
|
|
only, but does not load them. This provides an opportunity
|
|
to correct any errors. Under any circumstances, the last
|
|
valid rule set loaded will be in force until
|
|
<acronym>PF</acronym> is disabled or a new rule set is
|
|
loaded.</para>
|
|
|
|
<tip>
|
|
<title>Use <command>pfctl -v</command> to Show the Parsed
|
|
Rule Set</title>
|
|
|
|
<para>Adding the <option>-v</option> to a
|
|
<command>pfctl</command> ruleset load (even a dry run with
|
|
<option>-n</option>) will display the fully parsed rules
|
|
exactly the way they will be loaded. This is extremely
|
|
useful when debugging rules.</para>
|
|
</tip>
|
|
</sect3>
|
|
|
|
<sect3 id="pftut-gateway">
|
|
<title>A Simple Gateway with NAT</title>
|
|
|
|
<para>To most users, a single machine setup will be of limited
|
|
interest, and at this point we move on to more realistic or
|
|
at least more common setups, concentrating on a machine
|
|
which is running <acronym>PF</acronym> and also acts as a
|
|
gateway for at least one other machine.</para>
|
|
|
|
<sect4 id="pftut-gwpitfalls">
|
|
<title>Gateways and the Pitfalls of <literal>in</literal>,
|
|
<literal>out</literal> and <literal>on</literal></title>
|
|
|
|
<para>In the single machine setup, life is relatively
|
|
simple. Traffic created on it should either pass out to
|
|
the rest of the world or not, and the administrator
|
|
decides what to let in from elsewhere.</para>
|
|
|
|
<para>On a gateway, the perspective changes from
|
|
<quote>me versus the network out there</quote> to
|
|
<quote>I am the one who decides what to pass to or from
|
|
all the networks I am connected to</quote>. The machine
|
|
has at least two network interfaces, each connected to a
|
|
separate net.</para>
|
|
|
|
<para>It is very reasonable to think that for traffic to
|
|
pass from the network connected to
|
|
<devicename>xl1</devicename> to hosts on the network
|
|
connected to <devicename>xl0</devicename>, a rule like
|
|
this is needed:</para>
|
|
|
|
<programlisting>pass in on xl1 from xl1:network to xl0:network port $ports keep state</programlisting>
|
|
|
|
<para>This rule keeps track of states as well.</para>
|
|
|
|
<para>However, one of the most common and most
|
|
complained-about mistakes in firewall configuration is not
|
|
realizing that the <quote>to</quote> keyword does not in
|
|
itself guarantee passage all the way there. The rule we
|
|
just wrote only lets the traffic pass in to the gateway on
|
|
the internal interface. To let the packets get a bit
|
|
further, a matching rule is needed which says</para>
|
|
|
|
<programlisting>pass out on xl0 from xl1:network to xl0:network port $ports keep state</programlisting>
|
|
|
|
<para>These rules will work, but they will not necessarily
|
|
achieve the desired effect.</para>
|
|
|
|
<para>Rules this specific are rarely needed. For the basic
|
|
gateway configurations we will be dealing with here, a
|
|
better rule says</para>
|
|
|
|
<programlisting>pass from xl1:network to any port $ports keep state</programlisting>
|
|
|
|
<para>This provides local net access to the Internet and
|
|
leaves the detective work to the
|
|
<firstterm>antispoof</firstterm> and
|
|
<firstterm>scrub</firstterm> code. They are both pretty
|
|
good these days, and we will get back to them later. For
|
|
now we just accept the fact that for simple setups,
|
|
interface-bound rules with in/out rules tend to add more
|
|
clutter than they are worth to rule sets.</para>
|
|
|
|
<para>For a busy network admin, a readable rule set is a
|
|
safer rule set.</para>
|
|
|
|
<para>For the remainder of this section, with some
|
|
exceptions, we will keep the rules as simple as possible
|
|
for readability.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-whatsthelocalnet">
|
|
<title>What is the Local Network, Anyway?</title>
|
|
|
|
<para>Above, we introduced the
|
|
<literal>interface:network</literal> notation. That is a
|
|
nice piece of shorthand, but the rule set can be made even
|
|
more readable and maintainable by taking the macro use a
|
|
tiny bit further.</para>
|
|
|
|
<para>For example, a <literal>$localnet</literal> macro
|
|
could be defined as the network directly attached to your
|
|
internal interface (<literal>$xl1:network</literal> in the
|
|
examples above).</para>
|
|
|
|
<para>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
|
|
and a typical pass rule of the type</para>
|
|
|
|
<programlisting>pass from $localnet to any port $ports keep state</programlisting>
|
|
|
|
<para>could end up saving you a few headaches. We will
|
|
stick to that convention from here on.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-gwsimplesetup">
|
|
<title>Setting Up</title>
|
|
|
|
<para>We assume that the machine has acquired another
|
|
network card or at any rate there is a network
|
|
connection from the local network, via PPP or other
|
|
means. We will not consider the specific interface
|
|
configurations.</para>
|
|
|
|
<para>For the discussion and examples below, only the
|
|
interface names will differ between a PPP setup and an
|
|
Ethernet one, and we will do our best to get rid of the
|
|
actual interface names as quickly as possible.</para>
|
|
|
|
<para>First, we need to turn on gatewaying in order to let
|
|
the machine forward the network traffic it receives on one
|
|
interface to other networks via a separate interface.
|
|
Initially we will do this on the command line with
|
|
&man.sysctl.8;, for traditional
|
|
<emphasis>IP version four</emphasis>.</para>
|
|
|
|
<screen>&prompt.root; <userinput>sysctl net.inet.ip.forwarding=1</userinput></screen>
|
|
|
|
<para>If we need to forward <emphasis>IP version
|
|
six</emphasis> traffic, the command is</para>
|
|
|
|
<screen>&prompt.root; <userinput>sysctl net.inet6.ip6.forwarding=1</userinput></screen>
|
|
|
|
<para>In order for this to continue working after the
|
|
computer has been restarted at some time in the future,
|
|
enter these settings into
|
|
<filename>/etc/rc.conf</filename>:</para>
|
|
|
|
<programlisting>gateway_enable="YES" #for ipv4
|
|
ipv6_gateway_enable="YES" #for ipv6</programlisting>
|
|
|
|
<para>Use <command>ifconfig -a</command>, or
|
|
<command>ifconfig
|
|
<replaceable>interface_name</replaceable></command> to
|
|
find out if both of the interfaces to be used are up and
|
|
running.</para>
|
|
|
|
<para>If all traffic initiated by machines on the inside is
|
|
to be allowed, <filename>/etc/pf.conf</filename> could
|
|
look roughly like this
|
|
<footnote>
|
|
<para>For dialup users, the external interface is the
|
|
<filename>tun0</filename> pseudo-device. Broadband
|
|
users such as ADSL subscribers tend to have an
|
|
Ethernet interface to play with, however for a
|
|
significant subset of ADSL users, specifically those
|
|
using PPP over Ethernet (PPPoE), the correct external
|
|
interface will be the <filename>tun0</filename>
|
|
pseudo-device, not the physical Ethernet
|
|
interface.</para>
|
|
</footnote>:</para>
|
|
|
|
<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 -> ($ext_if)
|
|
block all
|
|
pass from { lo0, $localnet } to any keep state</programlisting>
|
|
|
|
<para>Note the use of macros to assign logical names to the
|
|
network interfaces. Here 3Com cards are used, but this is
|
|
the last time during this tutorial we will find this of
|
|
any interest whatsoever. In truly simple setups like this
|
|
one, we may not gain very much by using macros like these,
|
|
but once the rule sets grow somewhat larger, you will
|
|
learn to appreciate the readability this provides.</para>
|
|
|
|
<para>Also note the <literal>nat</literal> rule. This is
|
|
where we handle the network address translation from the
|
|
non-routable address inside the local net to the sole
|
|
official address we assume has been assigned.</para>
|
|
|
|
<para>The parentheses surrounding the last part of the nat
|
|
rule <literal>($ext_if)</literal> are there to compensate
|
|
for the possibility that the IP address of the external
|
|
interface may be dynamically assigned. This detail will
|
|
ensure that network traffic runs without serious
|
|
interruptions even if the external IP address
|
|
changes.</para>
|
|
|
|
<para>On the other hand, this rule set probably allows more
|
|
traffic to pass out of the network than actually desired.
|
|
One reasonable setup could contain the macro</para>
|
|
|
|
<programlisting>client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, \
|
|
https, cvspserver, 2628, 5999, 8000, 8080 }"</programlisting>
|
|
|
|
<para>and the main pass rule</para>
|
|
|
|
<programlisting>pass inet proto tcp from $localnet to any port $client_out \
|
|
flags S/SA keep state</programlisting>
|
|
|
|
<para>This may be a somewhat peculiar selection of ports,
|
|
but it is based on a real life example. Individual needs
|
|
probably differ at least in some specifics, but this
|
|
should cover at least some of the more useful
|
|
services.</para>
|
|
|
|
<para>In addition, we have a few other pass rules. We will
|
|
be returning to some of the more interesting ones rather
|
|
soon. One pass rule which is useful to those of us who
|
|
want the ability to administer our machines from elsewhere
|
|
is</para>
|
|
|
|
<programlisting>pass in inet proto tcp to port ssh</programlisting>
|
|
|
|
<para>or for that matter</para>
|
|
|
|
<programlisting>pass in inet proto tcp to $ext_if port ssh</programlisting>
|
|
|
|
<para>whichever is preferred. Lastly we need to make the
|
|
name service work for our clients:</para>
|
|
|
|
<programlisting>udp_services = "{ domain, ntp }"</programlisting>
|
|
|
|
<para>This is supplemented with a rule which passes the
|
|
traffic we want through our firewall:</para>
|
|
|
|
<programlisting>pass quick inet proto { tcp, udp } to any port $udp_services keep state</programlisting>
|
|
|
|
<para>Note the <literal>quick</literal> keyword in this
|
|
rule. We have started writing rule sets which consist of
|
|
several rules, and it is time to take a look at the
|
|
relationships between the rules in a rule set. The rules
|
|
are evaluated from top to bottom, in the sequence they are
|
|
written in the configuration file. For each packet or
|
|
connection evaluated by <acronym>PF</acronym>,
|
|
<emphasis>the last matching rule</emphasis> in the rule
|
|
set is the one which is applied. The
|
|
<literal>quick</literal> keyword offers an escape from the
|
|
ordinary sequence. When a packet matches a quick rule,
|
|
the packet is treated according to the present rule. The
|
|
rule processing stops without considering any further
|
|
rules which might have matched the packet. This is very
|
|
useful when a few isolated exceptions to the general rules
|
|
are needed.</para>
|
|
|
|
<para>This rule also takes care of <acronym>NTP</acronym>,
|
|
which is used for time synchronization. One thing common
|
|
to both protocols is that they may under certain
|
|
circumstances communicate alternately over TCP and
|
|
UDP.</para>
|
|
</sect4>
|
|
</sect3>
|
|
|
|
<sect3 id="pftut-ftp">
|
|
<title>That Sad Old <acronym>FTP</acronym> Thing</title>
|
|
|
|
<para>The short list of real life <acronym>TCP</acronym> ports
|
|
above contained, among other things, <acronym>FTP</acronym>.
|
|
<acronym>FTP</acronym> is a sad old thing and a problem
|
|
child, emphatically so for anyone trying to combine
|
|
<acronym>FTP</acronym> and firewalls.
|
|
<acronym>FTP</acronym> is an old and weird protocol, with a
|
|
lot to not like. The most common points against it
|
|
are</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
|
|
via ports selected at random</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>All of these points make for challenges security-wise,
|
|
even before considering any potential weaknesses in client
|
|
or server software which may lead to security issues. These
|
|
things have tended to happen.</para>
|
|
|
|
<para>Under any circumstances, other more modern and more
|
|
secure options for file transfer exist, such as &man.sftp.1;
|
|
or &man.scp.1;, which feature both authentication and data
|
|
transfer via encrypted connections. Competent
|
|
<acronym>IT</acronym> professionals should have a preference
|
|
for some other form of file transfer than
|
|
<acronym>FTP</acronym>.</para>
|
|
|
|
<para>Regardless of our professionalism and preferences, we
|
|
are all too aware that at times we will need to handle
|
|
things we would prefer not to. In the case of
|
|
<acronym>FTP</acronym> through firewalls, the main part of
|
|
our handling consists of redirecting the traffic to a small
|
|
program which is written specifically for this
|
|
purpose.</para>
|
|
|
|
<sect4 id="pftut-ftp-proxy">
|
|
<title><acronym>FTP</acronym> Via Redirect:
|
|
<application>ftp-proxy</application></title>
|
|
|
|
<para>Enabling <acronym>FTP</acronym> transfers through your
|
|
gateway is amazingly simple, thanks to the
|
|
<acronym>FTP</acronym> proxy program (called
|
|
&man.ftp-proxy.8;) included in the base system on &os; and
|
|
other systems which offer <acronym>PF</acronym>. </para>
|
|
|
|
<para>The <acronym>FTP</acronym> protocol being what it is,
|
|
the proxy needs to dynamically insert rules in your rule
|
|
set. &man.ftp-proxy.8; interacts with your configuration
|
|
via a set of anchors where the proxy inserts and deletes
|
|
the rules it constructs to handle your
|
|
<acronym>FTP</acronym> traffic.</para>
|
|
|
|
<para>To enable &man.ftp-proxy.8;, add this line to
|
|
<filename>/etc/rc.conf</filename>:</para>
|
|
|
|
<programlisting>ftpproxy_flags=""</programlisting>
|
|
|
|
<para>Starting the proxy manually by running
|
|
<command>/usr/sbin/ftp-proxy</command> allows testing of
|
|
the <acronym>PF</acronym> configuration changes we are
|
|
about to make.</para>
|
|
|
|
<para>For a basic configuration, only three elements need to
|
|
be added to <filename>/etc/pf.conf</filename>. First, the
|
|
anchors:</para>
|
|
|
|
<programlisting>nat-anchor "ftp-proxy/*"
|
|
rdr-anchor "ftp-proxy/*"</programlisting>
|
|
|
|
<para>The proxy will insert the rules it generates for the
|
|
<acronym>FTP</acronym> sessions here. A pass rule is
|
|
needed to let <acronym>FTP</acronym> traffic in to the
|
|
proxy.</para>
|
|
|
|
<para>Now for the actual redirection. Redirection rules and
|
|
<acronym>NAT</acronym> rules fall into the same rule
|
|
class. These rules may be referenced directly by other
|
|
rules, and filtering rules may depend on these rules.
|
|
Logically, <literal>rdr</literal> and
|
|
<literal>nat</literal> rules need to be defined before the
|
|
filtering rules.</para>
|
|
|
|
<para>We insert our <literal>rdr</literal> rule immediately
|
|
after the <literal>nat</literal> rule in
|
|
<filename>/etc/pf.conf</filename></para>
|
|
|
|
<programlisting>rdr pass on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021</programlisting>
|
|
|
|
<para>In addition, the redirected traffic must be allowed to
|
|
pass. We achieve this with</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>pf.conf</filename>, then load the new
|
|
rules with</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -f /etc/pf.conf</userinput></screen>
|
|
|
|
<para>At this point, users will probably begin noticing
|
|
that <acronym>FTP</acronym> works before they have been
|
|
told.</para>
|
|
|
|
<para>This example covers a basic setup where the clients in
|
|
the local net need to contact <acronym>FTP</acronym>
|
|
servers elsewhere. The basic configuration here should
|
|
work well with most combinations of <acronym>FTP</acronym>
|
|
clients and servers. As shown in the man page, 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. For these and other finer points of
|
|
&man.ftp-proxy.8; configuration, start by studying the man
|
|
page.</para>
|
|
|
|
<para>For ways to run an <acronym>FTP</acronym> server
|
|
protected by <acronym>PF</acronym> and &man.ftp-proxy.8;,
|
|
look into running a separate <command>ftp-proxy</command>
|
|
in reverse mode (using <option>-R</option>), on a separate
|
|
port with its own redirecting pass rule.</para>
|
|
</sect4>
|
|
</sect3>
|
|
|
|
<sect3 id="pftut-icmp">
|
|
<title>Easing Troubleshooting</title>
|
|
|
|
<para>Making network troubleshooting friendly is a potentially
|
|
large subject. At most times, the debugging or
|
|
troubleshooting friendliness of a <acronym>TCP/IP</acronym>
|
|
network depends on treatment of the Internet protocol which
|
|
was designed specifically with debugging in mind, the
|
|
<emphasis>Internet Control Message Protocol</emphasis>, or
|
|
<acronym>ICMP</acronym> as it is usually abbreviated.</para>
|
|
|
|
<para><acronym>ICMP</acronym> is the protocol for sending and
|
|
receiving <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.</para>
|
|
|
|
<para>There is a lot of <acronym>ICMP</acronym> traffic which
|
|
usually just happens in the background while users are
|
|
surfing the web, reading mail or transferring files.
|
|
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>Some admins refer to <acronym>ICMP</acronym> as either
|
|
<quote>just evil</quote>, or, if their understanding runs a
|
|
little deeper, <quote>a necessary evil</quote>. The reason
|
|
for this attitude is purely historical. The reason can be
|
|
found a few years back when it was discovered that several
|
|
operating systems contained code in their networking stack
|
|
which could make a machine running one of the affected
|
|
systems crash and fall over, or in some cases just do really
|
|
strange things, with a sufficiently large
|
|
<acronym>ICMP</acronym> request.</para>
|
|
|
|
<para>One of the companies which was hit hard was Microsoft,
|
|
and you can find rather a lot of material on the
|
|
<quote>ping of death</quote> bug by using your favorite
|
|
search engine. This all happened in the second half of the
|
|
1990s, and all modern operating systems, at least the ones
|
|
we can read, have thoroughly sanitized their network code
|
|
since then. At least that is what we are led to
|
|
believe.</para>
|
|
|
|
<para>One of the early workarounds was to simply block either
|
|
all <acronym>ICMP</acronym> traffic or at least
|
|
<acronym>ICMP</acronym> ECHO, which is what ping uses. Now
|
|
these rule sets have been around for roughly fifteen years,
|
|
and the people who put them there are still scared.</para>
|
|
|
|
<sect4 id="pftut-dowepass">
|
|
<title>Then, Do We Let it All Through?</title>
|
|
|
|
<para>The obvious question then becomes, if
|
|
<acronym>ICMP</acronym> is such a good and useful thing,
|
|
should we not let it all through, all the time? The
|
|
answer is <quote>It depends</quote>.</para>
|
|
|
|
<para>Letting diagnostic traffic pass unconditionally of
|
|
course makes debugging easier, but also makes it
|
|
relatively easy for others to extract information about
|
|
your network. That means that a rule like</para>
|
|
|
|
<programlisting>pass inet proto icmp from any to any</programlisting>
|
|
|
|
<para>might not be optimal if the internal workings of the
|
|
local network should be cloaked in a bit of mystery. In
|
|
all fairness it should also be said that some
|
|
<acronym>ICMP</acronym> traffic might be found quite
|
|
harmlessly riding piggyback on
|
|
<literal>keep state</literal> rules.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-icmpstopatgw">
|
|
<title>The Easy Way Out: the Buck Stops Here</title>
|
|
|
|
<para>The easiest solution could very well be to let all
|
|
<acronym>ICMP</acronym> traffic from the local net through
|
|
and stop probes from elsewhere at the gateway:</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>Stopping probes at the gateway might be an attractive
|
|
option anyway, but let us have a look at a few other
|
|
options which will show some of <acronym>PF</acronym>'s
|
|
flexibility.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-letpingthru">
|
|
<title>Letting <command>ping</command> Through</title>
|
|
|
|
<para>The rule set we have developed so far has one clear
|
|
disadvantage: common troubleshooting commands such as
|
|
&man.ping.8; and &man.traceroute.8; will not work. That
|
|
may not matter too much to end users, and since it was
|
|
<command>ping</command> which scared people into
|
|
filtering or blocking <acronym>ICMP</acronym> traffic in
|
|
the first place, there are apparently some people who feel
|
|
we are better off without it. If you are in my perceived
|
|
target audience, you will be rather fond of having those
|
|
troubleshooting tools avalable. With a couple of small
|
|
additions to the rule set, they will be. &man.ping.8;
|
|
uses <acronym>ICMP</acronym>, and in order to keep our
|
|
rule set tidy, we start by defining another macro:</para>
|
|
|
|
<programlisting>icmp_types = "echoreq"</programlisting>
|
|
|
|
<para>and a rule which uses the definition,</para>
|
|
|
|
<programlisting>pass inet proto icmp all icmp-type $icmp_types keep state</programlisting>
|
|
|
|
<para>More or other types of <acronym>ICMP</acronym> packets
|
|
may need to go through, and <literal>icmp_types</literal>
|
|
can be expanded to a list of those packet types that are
|
|
allowed.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-helptraceroute">
|
|
<title>Helping &man.traceroute.8;</title>
|
|
|
|
<para>&man.traceroute.8; is another command which is quite
|
|
useful when users claim that the Internet is not working.
|
|
By default, Unix <command>traceroute</command> uses UDP
|
|
connections according to a set formula based on
|
|
destination. The rule below works with
|
|
<command>traceroute</command> on all unixes I've had
|
|
access to, including GNU/Linux:</para>
|
|
|
|
<programlisting># allow out the default range for traceroute(8):
|
|
# "base+nhops*nqueries-1" (33434+64*3-1)
|
|
pass out on $ext_if inet proto udp from any to any port 33433 >< 33626 keep state</programlisting>
|
|
|
|
<para>Experience so far indicates that
|
|
<command>traceroute</command> implementations on other
|
|
operating systems work roughly the same. Except, of
|
|
course, on Microsoft Windows. On that platform,
|
|
<command>TRACERT.EXE</command> uses ICMP ECHO for this
|
|
purpose. So to let Windows traceroutes through, only the
|
|
first rule is needed. Unix <command>traceroute</command>
|
|
can be instructed to use other protocols as well, and will
|
|
behave remarkably like its Microsoft counterpart if
|
|
<option>-I</option> is used. Check the &man.traceroute.8;
|
|
man page (or its source code, for that matter) for all the
|
|
details.</para>
|
|
|
|
<para>Under any circumstances, this solution was lifted
|
|
from an openbsd-misc post. I've found that list, and
|
|
the searchable list archives (accessible among other
|
|
places from <ulink
|
|
url="http://marc.theaimsgroup.com/">http://marc.theaimsgroup.com/</ulink>),
|
|
to be a very valuable resource whenever you need OpenBSD
|
|
or <acronym>PF</acronym> related information.</para>
|
|
</sect4>
|
|
|
|
<sect4 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 called the
|
|
<firstterm>Maximum Transmission Unit</firstterm>, or
|
|
<acronym>MTU</acronym>, which sets the upper limit on the
|
|
packet size for an interface. &man.ifconfig.8; shows the
|
|
<acronym>MTU</acronym> for the network interfaces.</para>
|
|
|
|
<para>Modern TCP/IP implementations expect to be able to
|
|
determine the right packet size for a connection through a
|
|
process which, simply put, involves sending packets of
|
|
varying sizes with the <quote>Do not fragment</quote> flag
|
|
set, expecting an <acronym>ICMP</acronym> return packet
|
|
indicating <quote>type 3, code 4</quote> when the upper
|
|
limit has been reached. Now do not dive for the RFCs
|
|
right away. Type 3 means <quote>destination
|
|
unreachable</quote>, while code 4 is short for
|
|
<quote>fragmentation needed, but the do-not-fragment flag
|
|
is set</quote>. So if connections to networks which may
|
|
have other <acronym>MTU</acronym>s than the local network
|
|
seem sub-optimal, and there is no need to be that
|
|
specific, the list of <acronym>ICMP</acronym> types can be
|
|
changed slightly to let the
|
|
<quote>destination unreachable</quote> packets through,
|
|
too:</para>
|
|
|
|
<programlisting>icmp_types = "{ echoreq, unreach }"</programlisting>
|
|
|
|
<para>As we can see, this means we do not need to change
|
|
the pass rule itself:</para>
|
|
|
|
<programlisting>pass inet proto icmp all icmp-type $icmp_types keep state</programlisting>
|
|
|
|
<para><acronym>PF</acronym> allows filtering on all
|
|
variations of <acronym>ICMP</acronym> types and codes.
|
|
For those who want to delve into what to pass (or not) of
|
|
<acronym>ICMP</acronym> traffic, the list of possible
|
|
types and codes are documented in the &man.icmp.4; and
|
|
&man.icmp6.4; man pages. The background information is
|
|
available in the <acronym>RFC</acronym>s
|
|
<footnote><para>The main internet <acronym>RFC</acronym>s
|
|
describing <acronym>ICMP</acronym> and
|
|
some related techhiques are RFC792, RFC950, RFC1191,
|
|
RFC1256, RFC2521, rfc2765, while necessary updates for
|
|
ICMP for IPv6 are found in RFC1885, RFC2463, RFC2466.
|
|
These documents are available in a number of places on
|
|
the net, such as the
|
|
<ulink url="http://www.ietf.org">ietf.org</ulink>
|
|
and
|
|
<ulink url="http://www.faqs.org">faqs.org</ulink>
|
|
web sites.</para></footnote>.</para>
|
|
</sect4>
|
|
</sect3>
|
|
|
|
<sect3 id="pftut-tables">
|
|
<title>Tables Make Life Easier</title>
|
|
|
|
<para>By this time it may appear that this gets awfully static
|
|
and rigid. There will after all be some kinds of data which
|
|
are relevant to filtering and redirection at a given time,
|
|
but do not deserve to be put into a configuration file!
|
|
Quite right, and <acronym>PF</acronym> offers mechanisms for
|
|
handling these situations as well. Tables are one such
|
|
feature, mainly useful as lists which can be manipulated
|
|
without needing to reload the entire rule set, and where
|
|
fast lookups are desirable. Table names are always enclosed
|
|
in <literal>< ></literal>, like this:</para>
|
|
|
|
<programlisting>table <clients> { 192.168.2.0/24, !192.168.2.5 }</programlisting>
|
|
|
|
<para>Here, the network <literal>192.168.2.0/24</literal>
|
|
is part of the table, except the address
|
|
<literal>192.168.2.5</literal>, which is excluded using
|
|
the <literal>!</literal> operator (logical NOT). It is
|
|
also possible to load tables from files where each item is
|
|
on a separate line, such as the file
|
|
<filename>/etc/clients</filename>.</para>
|
|
|
|
<programlisting>192.168.2.0/24
|
|
!192.168.2.5</programlisting>
|
|
|
|
<para>which in turn is used to initialize the table in
|
|
<filename>/etc/pf.conf</filename>:</para>
|
|
|
|
<programlisting>table <clients> persist file /etc/clients</programlisting>
|
|
|
|
<para>Then, for example, one of our earlier rules can be
|
|
changed to read</para>
|
|
|
|
<programlisting>pass inet proto tcp from <clients> to any port $client_out flags S/SA keep state</programlisting>
|
|
|
|
<para>to manage outgoing traffic from client computers. With
|
|
this in hand, the table's contents can be manipulated live,
|
|
such as</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -t clients -T add 192.168.1/16</userinput></screen>
|
|
|
|
<para>Note that this changes the in-memory copy of the table
|
|
only, meaning that the change will not survive a power
|
|
failure or other reboot unless there are arrangements to
|
|
store the changes.</para>
|
|
|
|
<para>One might opt to maintain the on-disk copy of the table
|
|
using a &man.cron.8; job which dumps the table content to
|
|
disk at regular intervals, using a command such as
|
|
<command>pfctl -t clients -T show
|
|
>/etc/clients</command>. Alternatively,
|
|
<filename>/etc/clients</filename> could be edited, replacing
|
|
the in-memory table contents with the file data:</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -t clients -T replace -f /etc/clients</userinput></screen>
|
|
|
|
<para>For operations performed frequently, administrators will
|
|
sooner or later end up writing shell scripts for tasks
|
|
such as inserting or removing items or replacing table
|
|
contents. The only real limitations lie in individual needs
|
|
and creativity.</para>
|
|
</sect3>
|
|
|
|
<sect3 id="pftut-overload">
|
|
<title>Overload Tables</title>
|
|
|
|
<para>Those who run a Secure Shell login service which is
|
|
accessible from the Internet 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>And so on. This is what a brute force attack looks
|
|
like. Essentially somebody, or more likely, a cracked
|
|
computer somewhere, is trying by brute force to find a
|
|
combination of user name and password which will let them
|
|
into your system.</para>
|
|
|
|
<para>The simplest response would be to write a
|
|
<filename>pf.conf</filename> rule which blocks all access.
|
|
This leads to another class of problems, including what to
|
|
do in order to let people with legitimate business on the
|
|
system access it anyway. Some might consider moving the
|
|
service to another port, but then again, the ones flooding
|
|
on port 22 would probably be able to scan their way to port
|
|
22222 for a repeat performance.</para>
|
|
|
|
<para>Since OpenBSD 3.7, and soon after in &os; version 6.0,
|
|
<acronym>PF</acronym> has offered a slightly more elegant
|
|
solution. Pass rules can be written so they maintain
|
|
certain limits on what connecting hosts can do. For good
|
|
measure, violators can be banished to a table of addresses
|
|
which are denied some or all access. If desired, it's even
|
|
possible to drop all existing connections from machines
|
|
which overreach the limits. Here is how it is done:</para>
|
|
|
|
<para>First, set up the table. In the tables section,
|
|
add</para>
|
|
|
|
<programlisting>table <bruteforce> persist</programlisting>
|
|
|
|
<para>Then somewhere fairly early in the rule set, add a rule
|
|
to block the bruteforcers:</para>
|
|
|
|
<programlisting>block quick from <bruteforce></programlisting>
|
|
|
|
<para>And finally, the pass rule.</para>
|
|
|
|
<programlisting>pass inet proto tcp from any to $localnet port $tcp_services \
|
|
flags S/SA keep state \
|
|
(max-src-conn 100, max-src-conn-rate 15/5, \
|
|
overload <bruteforce> flush global)</programlisting>
|
|
|
|
<para>The first part here is identical to the main rule we
|
|
constructed earlier. The part in parentheses is the new
|
|
stuff which will ease network load even further.</para>
|
|
|
|
<para><literal>max-src-conn</literal> is the number of
|
|
simultaneous connections allowed from one host. In this
|
|
example, it is set at 100. Other setups may want a slightly
|
|
higher or lower value.</para>
|
|
|
|
<para><literal>max-src-conn-rate</literal> is the rate of new
|
|
connections allowed from any single host, here 15
|
|
connections per 5 seconds. Again, the administrator is the
|
|
one to judge what suits their setup.</para>
|
|
|
|
<para><literal>overload <bruteforce></literal> means
|
|
that any host which exceeds these limits gets its address
|
|
added to the table <literal>bruteforce</literal>. Our rule
|
|
set blocks all traffic from addresses in the bruteforce
|
|
table.</para>
|
|
|
|
<para>Finally, <literal>flush global</literal> says that when
|
|
a host reaches the limit, that host's connections will be
|
|
terminated (flushed). The global part says that for good
|
|
measure, this applies to connections which match other pass
|
|
rules too.</para>
|
|
|
|
<para>The effect is dramatic. From here on, bruteforcers
|
|
more often than not will end up with
|
|
<computeroutput>"Fatal: timeout before
|
|
authentication"</computeroutput> messages, getting
|
|
nowhere.</para>
|
|
|
|
<note>
|
|
<para>These rules will <emphasis>not</emphasis> block slow
|
|
bruteforcers, sometimes referred to as <ulink
|
|
url="http://home.nuug.no/~peter/hailmary2013/">the Hail
|
|
Mary Cloud</ulink>.</para>
|
|
</note>
|
|
|
|
<para>Once again, please keep in mind that this example rule
|
|
is intended mainly as an illustration. It is not unlikely
|
|
that a particular network's needs are better served by
|
|
rather different rules or combinations of rules.</para>
|
|
|
|
<para>If, for example, a generous number of connections in
|
|
general are wanted, but the desire is to be a little more
|
|
tight fisted 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 <bruteforce> flush global)</programlisting>
|
|
|
|
<para>It should be possible to find the set of parameters
|
|
which is just right for individual situations by reading the
|
|
relevant man pages and the
|
|
<ulink url="http://www.openbsd.org/faq/pf/">PF User
|
|
Guide</ulink>, and perhaps a bit of
|
|
experimentation.</para>
|
|
|
|
<note>
|
|
<title>It May Not be Necessary to Block All
|
|
Overloaders</title>
|
|
|
|
<para>It is probably worth noting at this point that the
|
|
<emphasis>overload</emphasis> mechanism is a general
|
|
technique which does not have to apply exclusively to the
|
|
<emphasis>ssh</emphasis> service, and it is not always
|
|
optimal to block all traffic from offenders
|
|
entirely.</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, in the web
|
|
case, to redirect to a specific web page.</para>
|
|
</note>
|
|
|
|
<sect4 id="pftut-expire">
|
|
<title>Expiring Table Entries with
|
|
<application>pfctl</application></title>
|
|
|
|
<para>At this point, we have tables which will be filled by
|
|
our <literal>overload</literal> rules, and since we could
|
|
reasonably expect our gateways to have months of uptime,
|
|
the tables will grow incrementally, taking up more memory
|
|
as time goes by.</para>
|
|
|
|
<para>Sometimes an IP address that was blocked last week due
|
|
to a brute force attack was in fact a dynamically assigned
|
|
one, which is now assigned to a different ISP customer who
|
|
has a legitimate reason to try communicating with hosts in
|
|
the local network.</para>
|
|
|
|
<para>Situations like these were what caused Henning Brauer
|
|
to add to <application>pfctl</application> the ability to
|
|
expire table entries not referenced in a specified number
|
|
of seconds (in OpenBSD 4.1). For example, the
|
|
command</para>
|
|
|
|
<screen>&prompt.root; <userinput>pfctl -t bruteforce -T expire 86400</userinput></screen>
|
|
|
|
<para>will remove <literal><bruteforce></literal>
|
|
table entries which have not been referenced for 86400
|
|
seconds.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-expiretable">
|
|
<title>The <application>expiretable</application>
|
|
Tool</title>
|
|
|
|
<para>Before <application>pfctl</application> acquired the
|
|
ability to expire table entries, Henrik Gustafsson had
|
|
written <application>expiretable</application>, which
|
|
removes table entries which have not been accessed for a
|
|
specified period of time.</para>
|
|
|
|
<para>One useful example is to use the
|
|
<application>expiretable</application> program as a way of
|
|
removing outdated <literal><bruteforce></literal>
|
|
table entries.</para>
|
|
|
|
<para>For example, let
|
|
<application>expiretable</application> remove
|
|
<literal><bruteforce></literal> table entries older
|
|
than 24 hours by adding an entry containing the following
|
|
to <filename>/etc/rc.local</filename>:</para>
|
|
|
|
<programlisting>/usr/local/sbin/expiretable -v -d -t 24h bruteforce</programlisting>
|
|
|
|
<para><application>expiretable</application> is in the
|
|
Ports Collection on &os; as <filename
|
|
role="package">security/expiretable</filename>.</para>
|
|
</sect4>
|
|
</sect3>
|
|
|
|
<sect3 id="pftut-tools">
|
|
<title>Other <acronym>PF</acronym> Tools</title>
|
|
|
|
<para>Over time, a number of tools have been developed which
|
|
interact with <acronym>PF</acronym> in various ways.</para>
|
|
|
|
<sect4 id="pftut-pftop">
|
|
<title>The <application>pftop</application> Traffic
|
|
Viewer</title>
|
|
|
|
<para>Can Erkin Acar's <application>pftop</application>
|
|
makes it possible to keep an eye on what passes into and
|
|
out of the network. <application>pftop</application> is
|
|
available through the ports system as
|
|
<filename role="package">sysutils/pftop</filename>. The
|
|
name is a strong hint at what it does -
|
|
<application>pftop</application> shows a running snapshot
|
|
of traffic in a format which is strongly inspired by
|
|
&man.top.1;.</para>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-spamd">
|
|
<title>The <application>spamd</application> Spam Deferral
|
|
Daemon</title>
|
|
|
|
<para>Not to be confused with the
|
|
<application>spamd</application> daemon which comes
|
|
bundled with <application>spamassassin</application>, the
|
|
<acronym>PF</acronym> companion
|
|
<application>spamd</application> was designed to run on a
|
|
PF gateway to form part of the outer defense against spam.
|
|
<application>spamd</application> hooks into the
|
|
<acronym>PF</acronym> configuration via a set of
|
|
redirections.</para>
|
|
|
|
<para>The main point underlying the
|
|
<application>spamd</application> design is the fact that
|
|
spammers send a large number of messages, and the
|
|
probability that you are the first person receiving a
|
|
particular message is incredibly small. In addition,
|
|
spam is mainly sent via a few spammer friendly networks
|
|
and a large number of hijacked machines. Both the
|
|
individual messages and the machines will be reported to
|
|
blacklists fairly quickly, and this is the kind of data
|
|
<application>spamd</application> can use to our advantage
|
|
with <firstterm>blacklists</firstterm>.</para>
|
|
|
|
<para>What <application>spamd</application> does to SMTP
|
|
connections from addresses in the blacklist is to
|
|
present its banner and immediately switch to a mode
|
|
where it answers SMTP traffic one byte at the time. This
|
|
technique, which is intended to waste as much time as
|
|
possible on the sending end while costing the receiver
|
|
pretty much nothing, is called
|
|
<firstterm>tarpitting</firstterm>. The specific
|
|
implementation with one byte SMTP replies is often
|
|
referred to as <firstterm>stuttering</firstterm>.</para>
|
|
|
|
<sect5 id="pftut-spamd-allblack">
|
|
<title>A Basic Blacklisting
|
|
<application>spamd</application></title>
|
|
|
|
<para>Here is the basic procedure for setting up
|
|
<application>spamd</application> with automatically
|
|
updated blacklists:</para>
|
|
|
|
<procedure>
|
|
<step>
|
|
<para>Install the <filename
|
|
role="package">mail/spamd/</filename> port. In
|
|
particular, be sure to read the package message and
|
|
act upon what it says. Specifically, to use
|
|
<application>spamd</application>'s greylisting
|
|
features, a file descriptor file system (see <ulink
|
|
url="http://www.freebsd.org/cgi/man.cgi?query=fdescfs&sektion=5">fdescfs(5)</ulink>)
|
|
must be mounted at <filename>/dev/fd/</filename>.
|
|
Do this by adding the following line to
|
|
<filename>/etc/fstab</filename>:</para>
|
|
|
|
<programlisting> fdescfs /dev/fd fdescfs rw 0 0</programlisting>
|
|
|
|
<para>Make sure the <filename>fdescfs</filename> code
|
|
is in the kernel, either compiled in or by loading
|
|
the module with &man.kldload.8;.</para>
|
|
</step>
|
|
|
|
<step>
|
|
<para>Next, edit the rule set to include</para>
|
|
|
|
<programlisting>table <spamd> persist
|
|
table <spamd-white> persist
|
|
rdr pass on $ext_if inet proto tcp from <spamd> to \
|
|
{ $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025
|
|
rdr pass on $ext_if inet proto tcp from !<spamd-white> to \
|
|
{ $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025</programlisting>
|
|
|
|
<para>The two tables <spamd> and
|
|
<spamd-white> are essential. SMTP traffic
|
|
from the addresses in the first table plus the ones
|
|
which are not in the other table are redirected to a
|
|
daemon listening at port 8025.</para>
|
|
</step>
|
|
|
|
<step>
|
|
<para>The next step is to set up
|
|
<application>spamd</application>'s own configuration
|
|
in <filename>/usr/local/etc/spamd.conf</filename>
|
|
supplemented by <filename>rc.conf</filename>
|
|
parameters.</para>
|
|
|
|
<para>The supplied sample file offers quite a bit of
|
|
explanation, and the man page offers additional
|
|
information, but we will recap the essentials
|
|
here.</para>
|
|
|
|
<para>One of the first lines without a
|
|
<literal>#</literal> comment sign at the start
|
|
contains the block which defines the
|
|
<literal>all</literal> list, which specifies the
|
|
lists actually used:</para>
|
|
|
|
<programlisting>all:\
|
|
:traplist:whitelist:</programlisting>
|
|
|
|
<para>Here, all the desired black lists are added,
|
|
separated by colons (<literal>:</literal>). To use
|
|
whitelists to subtract addresses from the blacklist,
|
|
add the name of the whitelist immediately after the
|
|
name of each blacklist, i.e.,
|
|
<literal>:blacklist:whitelist:</literal>.</para>
|
|
|
|
<para>Next up is a blacklist 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>Following the name, the first data field
|
|
specifies the list type, in this case
|
|
<literal>black</literal>. The
|
|
<literal>msg</literal> field contains the message to
|
|
display to blacklisted senders during the SMTP
|
|
dialogue. The <literal>method</literal> field
|
|
specifies how spamd-setup fetches the list data,
|
|
here <literal>http</literal>. The other options are
|
|
fetching via <literal>ftp</literal>, from a
|
|
<literal>file</literal> in a mounted file system or
|
|
via <literal>exec</literal> of an external program.
|
|
Finally the <literal>file</literal> field specifies
|
|
the name of the file spamd expects to
|
|
receive.</para>
|
|
|
|
<para>The definition of a whitelist follows much the
|
|
same pattern:</para>
|
|
|
|
<programlisting>whitelist:\
|
|
:white:\
|
|
:method=file:\
|
|
:file=/var/mail/whitelist.txt</programlisting>
|
|
|
|
<para>but omits the message parameters since a
|
|
message is not needed.</para>
|
|
|
|
<tip>
|
|
<title>Choose Data Sources with Care</title>
|
|
|
|
<para>Using all the blacklists in the sample
|
|
<filename>spamd.conf</filename> will end up
|
|
blacklisting large blocks of the Internet,
|
|
including several Asian nations. Administrators
|
|
need to edit the file to end up with an optimal
|
|
configuration. The administrator is the judge of
|
|
which data sources to use, and using lists other
|
|
than the ones suggested in the sample file is
|
|
possible.</para>
|
|
</tip>
|
|
|
|
<para>Put the lines for spamd and any startup
|
|
parameters desired in
|
|
<filename>/etc/rc.conf</filename>, for
|
|
example:</para>
|
|
|
|
<programlisting>spamd_flags="-v" # for normal use: "" and see spamd-setup(8)</programlisting>
|
|
|
|
<para>When done with editing the setup,
|
|
reload the rule set, start
|
|
<application>spamd</application> with the options
|
|
desired using the
|
|
<filename>/usr/local/etc/rc.d/obspamd</filename>
|
|
script, 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 start getting trapped within a few seconds to
|
|
several minutes.</para>
|
|
</sect5>
|
|
|
|
<sect5 id="pftut-spamd-greylist">
|
|
<title>Adding Greylisting to the
|
|
<application>spamd</application> Setup</title>
|
|
|
|
<para><application>spamd</application> also supports
|
|
<firstterm>greylisting</firstterm>, which works by
|
|
rejecting messages from unknown hosts temporarily with
|
|
<replaceable>45n</replaceable> codes, letting messages
|
|
from hosts which try again within a reasonable time
|
|
through. Traffic from well behaved hosts, that is,
|
|
senders which are set up to behave within the limits set
|
|
up in the relevant RFCs
|
|
<footnote><para>The relevant RFCs are mainly RFC1123
|
|
and RFC2821.</para></footnote>, will be let
|
|
through.</para>
|
|
|
|
<para>Greylisting as a technique was presented in a 2003
|
|
paper by Evan Harris
|
|
<footnote><para>The original
|
|
Harris paper and a number of other useful articles
|
|
and resources can be found at the <ulink
|
|
url="http://www.greylisting.org/">greylisting.org</ulink>
|
|
web site.</para></footnote>, and a number of
|
|
implementations followed over the next few months.
|
|
OpenBSD's <application>spamd</application> acquired its
|
|
ability to greylist in OpenBSD 3.5, which was released
|
|
in May 2004.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>The basic procedure for adding greylisting to your
|
|
setup follows below.</para>
|
|
|
|
<procedure>
|
|
<step>
|
|
<para>If not done already, make sure the
|
|
file descriptor file system (see &man.fdescfs.5;) is
|
|
mounted at <filename>/dev/fd/</filename>. Do this
|
|
by adding the following line to
|
|
<filename>/etc/fstab</filename>:</para>
|
|
|
|
<programlisting>fdescfs /dev/fd fdescfs rw 0 0</programlisting>
|
|
|
|
<para>and make sure the &man.fdescfs.5; code is in the
|
|
kernel, either compiled in or by loading the module
|
|
with &man.kldload.8;.</para>
|
|
</step>
|
|
|
|
<step>
|
|
<para>To run <application>spamd</application> in
|
|
greylisting mode, <filename>/etc/rc.conf</filename>
|
|
must be changed slightly by adding</para>
|
|
|
|
<programlisting>spamd_grey="YES" # use spamd greylisting if YES</programlisting>
|
|
|
|
<para>Several greylisting related parameters can be
|
|
fine-tuned with <command>spamd</command>'s command
|
|
line parameters and the corresponding
|
|
<filename>/etc/rc.conf</filename> settings. Check
|
|
the <application>spamd</application> man page to see
|
|
what the parameters mean.</para>
|
|
</step>
|
|
|
|
<step>
|
|
<para>To complete the greylisting setup, restart
|
|
<application>spamd</application> using the
|
|
<filename>/usr/local/etc/rc.d/obspamd</filename>
|
|
script.</para>
|
|
</step>
|
|
</procedure>
|
|
|
|
<para>Behind the scenes, rarely mentioned and barely
|
|
documented are two of <application>spamd</application>'s
|
|
helpers, the <application>spamdb</application> database
|
|
tool and the <application>spamlogd</application>
|
|
whitelist updater, which both perform essential
|
|
functions for the greylisting feature. Of the two
|
|
<application>spamlogd</application> works quietly in the
|
|
background, while <application>spamdb</application> has
|
|
been developed to offer some interesting
|
|
features.</para>
|
|
|
|
<note>
|
|
<title>Restart <application>spamd</application> to
|
|
Enable Greylisting</title>
|
|
|
|
<para>After following all steps in the tutorial
|
|
exactly up to this point,
|
|
<application>spamlogd</application> has been started
|
|
automatically already. However, if the initial
|
|
<application>spamd</application> configuration did not
|
|
include greylisting,
|
|
<application>spamlogd</application> may not have been
|
|
started, and there may be strange symptoms, such as
|
|
greylists and whitelists not getting updated
|
|
properly.</para>
|
|
|
|
<para>Under normal circumstances, it should not be
|
|
necessary to start <application>spamlogd</application>
|
|
by hand. Restarting <application>spamd</application>
|
|
after enabling greylisting ensures
|
|
<application>spamlogd</application> is loaded and
|
|
available too.</para>
|
|
</note>
|
|
|
|
<para><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>
|
|
</sect5>
|
|
</sect4>
|
|
|
|
<sect4 id="pftut-hygiene">
|
|
<title>Network Hygiene: Blocking, Scrubbing and so
|
|
On</title>
|
|
|
|
<para>Our gateway does not feel quite complete without a few
|
|
more items in the configuration which will make it behave
|
|
a bit more sanely towards hosts on the wide net and our
|
|
local network.</para>
|
|
|
|
<sect5 id="pftut-blockpolicy">
|
|
<title><literal>block-policy</literal></title>
|
|
|
|
<para><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,
|
|
<acronym>PF</acronym> will give to hosts which try to
|
|
create connections which are subsequently blocked. The
|
|
option has two possible values, <literal>drop</literal>,
|
|
which drops blocked packets with no feedback, and
|
|
<literal>return</literal>, which returns with status
|
|
codes such as <computeroutput>Connection
|
|
refused</computeroutput> or similar.</para>
|
|
|
|
<para>The correct strategy for block policies has been the
|
|
subject of rather a lot of discussion. We choose to
|
|
play nicely and instruct our firewall to issue
|
|
returns:</para>
|
|
|
|
<programlisting>set block-policy return</programlisting>
|
|
</sect5>
|
|
|
|
<sect5 id="pftut-scrub">
|
|
<title><literal>scrub</literal></title>
|
|
|
|
<para>In <acronym>PF</acronym> versions up to OpenBSD 4.5
|
|
inclusive, <literal>scrub</literal> is a keyword which
|
|
enables network packet normalization, causing fragmented
|
|
packets to be assembled and removing ambiguity.
|
|
Enabling <literal>scrub</literal> provides a measure of
|
|
protection against certain kinds of attacks based on
|
|
incorrect handling of packet fragments. A number of
|
|
supplementing options are available, but we choose the
|
|
simplest form which is suitable for most
|
|
configurations.</para>
|
|
|
|
<programlisting>scrub in all</programlisting>
|
|
|
|
<para>Some services, such as NFS, require some specific
|
|
fragment handling options. This is extensively
|
|
documented in the <acronym>PF</acronym> user guide and
|
|
man pages provide all the information you could
|
|
need.</para>
|
|
|
|
<para>One fairly common example is this,</para>
|
|
|
|
<programlisting>scrub in all fragment reassemble no-df max-mss 1440</programlisting>
|
|
|
|
<para>meaning, we reassemble fragments, clear the
|
|
<quote>do not fragment</quote> bit and set the maximum
|
|
segment size to 1440 bytes. Other variations are
|
|
possible, and you should be able to cater to various
|
|
specific needs by consulting the man pages and some
|
|
experimentation.</para>
|
|
</sect5>
|
|
|
|
<sect5 id="pftut-antispoof">
|
|
<title><literal>antispoof</literal></title>
|
|
|
|
<para><literal>antispoof</literal> is a common special
|
|
case of filtering and blocking. This mechanism protects
|
|
against activity from spoofed or forged IP addresses,
|
|
mainly by blocking packets appearing on interfaces and
|
|
in directions which are logically not possible.</para>
|
|
|
|
<para>We specify that we want to weed out spoofed traffic
|
|
coming in from the rest of the world and any spoofed
|
|
packets which, however unlikely, were to originate in
|
|
our own network:</para>
|
|
|
|
<programlisting>antispoof for $ext_if
|
|
antispoof for $int_if</programlisting>
|
|
</sect5>
|
|
|
|
<sect5 id="pftut-unrouteables">
|
|
<title>Handling Non-Routable Addresses from
|
|
Elsewhere</title>
|
|
|
|
<para>Even with a properly configured gateway to handle
|
|
network address translation for your own network, you
|
|
may find yourself in the unenviable position of having
|
|
to compensate for other people's
|
|
misconfigurations.</para>
|
|
|
|
<para>One depressingly common class of misconfigurations
|
|
is the kind which lets traffic with non-routable
|
|
addresses out to the Internet. Traffic from
|
|
non-routeable addresses have also played a part in
|
|
several DOS attack techniques, so it may be worth
|
|
considering explicitly blocking traffic from
|
|
non-routeable addresses from entering your
|
|
network.</para>
|
|
|
|
<para>One possible solution is the one outlined below,
|
|
which for good measure also blocks any attempt to
|
|
initiate contact to non-routable addresses through 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>
|
|
|
|
<para>Here, the <literal>martians</literal> macro denotes
|
|
the RFC 1918 addresses and a few other ranges which are
|
|
mandated by various RFCs not to be in circulation on the
|
|
open Internet. Traffic to and from such addresses is
|
|
quietly dropped on the gateway's external
|
|
interface.</para>
|
|
|
|
<para>The specific details of how to implement this kind
|
|
of protection will vary, among other things according to
|
|
your specific network configuration. Your network
|
|
design could for example dictate that you include or
|
|
exclude other address ranges than these.</para>
|
|
|
|
<para>This completes our simple NATing firewall for a
|
|
small local network. A more thorough tutorial is
|
|
available at <ulink
|
|
url="http://home.nuug.no/~peter/pf/">http://home.nuug.no/~peter/pf/</ulink>,
|
|
where you will also find slides from related
|
|
presentations.</para>
|
|
</sect5>
|
|
</sect4>
|
|
</sect3>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="firewalls-ipf">
|
|
<title>The IPFILTER (IPF) Firewall</title>
|
|
|
|
<indexterm>
|
|
<primary>firewall</primary>
|
|
|
|
<secondary>IPFILTER</secondary>
|
|
</indexterm>
|
|
|
|
<para>IPFILTER is a cross-platform, open source firewall which
|
|
has been ported to &os;, NetBSD, OpenBSD, &sunos;, HP/UX, and
|
|
&solaris; operating systems.</para>
|
|
|
|
<para>IPFILTER is based on a kernel-side firewall and
|
|
<acronym>NAT</acronym> mechanism that can be controlled and
|
|
monitored by userland interface programs. The firewall rules
|
|
can be set or deleted using &man.ipf.8;. The
|
|
<acronym>NAT</acronym> rules can be set or deleted using
|
|
&man.ipnat.8;. Run-time statistics for the kernel parts of
|
|
IPFILTER can be printed using &man.ipfstat.8;. To log IPFILTER
|
|
actions to the system log files, use &man.ipmon.8;.</para>
|
|
|
|
<para>IPF was originally written using a rule processing logic
|
|
of <quote>the last matching rule wins</quote> and only used
|
|
stateless rules. Over time, IPF has been enhanced to include a
|
|
<quote>quick</quote> option and a stateful
|
|
<quote>keep state</quote> option which modernized the rules
|
|
processing logic. IPF's official documentation covers only the
|
|
legacy rule coding parameters and rule file processing logic and
|
|
the modernized functions are only included as additional
|
|
options.</para>
|
|
|
|
<para>The instructions contained in this section are based on
|
|
using rules that contain <quote>quick</quote> and
|
|
<quote>keep state</quote> as these provide the basic framework
|
|
for configuring an inclusive firewall ruleset.</para>
|
|
|
|
<para>For a detailed explanation of the legacy rules processing
|
|
method, refer to <ulink
|
|
url="http://www.munk.me.uk/ipf/ipf-howto.html"></ulink>
|
|
and <ulink
|
|
url="http://coombs.anu.edu.au/~avalon/ip-filter.html"></ulink>.</para>
|
|
|
|
<para>The IPF FAQ is at <ulink
|
|
url="http://www.phildev.net/ipf/index.html"></ulink>.</para>
|
|
|
|
<para>A searchable archive of the IPFilter mailing list is
|
|
available at <ulink
|
|
url="http://marc.theaimsgroup.com/?l=ipfilter"></ulink>.</para>
|
|
|
|
<sect2>
|
|
<title>Enabling IPF</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFILTER</primary>
|
|
|
|
<secondary>enabling</secondary>
|
|
</indexterm>
|
|
|
|
<para>IPF is included in the basic &os; install as a kernel
|
|
loadable module. The system will dynamically load
|
|
this module at boot time when
|
|
<varname>ipfilter_enable="YES"</varname> is added to
|
|
<filename>rc.conf</filename>. The module enables logging and
|
|
<literal>default pass all</literal>. To change the
|
|
default to <literal>block all</literal>, add a
|
|
<literal>block all</literal> rule at the end of the
|
|
ruleset.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Kernel Options</title>
|
|
|
|
<indexterm>
|
|
<primary>kernel options</primary>
|
|
|
|
<secondary>IPFILTER</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>IPFILTER</primary>
|
|
|
|
<secondary>kernel options</secondary>
|
|
</indexterm>
|
|
|
|
<para>For users who prefer to statically compile IPF support
|
|
into a custom kernel, the following IPF option statements,
|
|
listed in <filename>/usr/src/sys/conf/NOTES</filename>, are
|
|
available:</para>
|
|
|
|
<programlisting>options IPFILTER
|
|
options IPFILTER_LOG
|
|
options IPFILTER_DEFAULT_BLOCK</programlisting>
|
|
|
|
<para><literal>options IPFILTER</literal> enables support for
|
|
the <quote>IPFILTER</quote> firewall.</para>
|
|
|
|
<para><literal>options IPFILTER_LOG</literal> enables IPF
|
|
logging using the <devicename>ipl</devicename> packet logging
|
|
pseudo—device for every rule that has the
|
|
<literal>log</literal> keyword.</para>
|
|
|
|
<para><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>These settings will take effect only after installing a
|
|
kernel that has been built with the above options set.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Available <filename>rc.conf</filename> Options</title>
|
|
|
|
<para>To activate IPF at boot time, the following statements
|
|
need to be added to <filename>/etc/rc.conf</filename>:</para>
|
|
|
|
<programlisting>ipfilter_enable="YES" # Start ipf firewall
|
|
ipfilter_rules="/etc/ipf.rules" # loads rules definition text file
|
|
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 & port to names</programlisting>
|
|
|
|
<para>If there is a LAN behind the firewall that uses the
|
|
reserved private IP address ranges, the following lines have
|
|
to be added to enable <acronym>NAT</acronym>
|
|
functionality:</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>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>IPF</title>
|
|
|
|
<indexterm><primary><command>ipf</command></primary></indexterm>
|
|
|
|
<para>To load the ruleset file, use &man.ipf.8;. Custom rules
|
|
are normally placed in a file, and 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><option>-Fa</option> flushes all the internal rules
|
|
tables.</para>
|
|
|
|
<para><option>-f</option> specifies the file containing the
|
|
rules to load.</para>
|
|
|
|
<para>This provides the ability to make changes to a custom
|
|
rules file, run the above IPF command, and thus 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>
|
|
|
|
<para>&man.ipf.8; expects the rules file to be a standard text
|
|
file. It will not accept a rules file written as a script
|
|
with symbolic substitution.</para>
|
|
|
|
<para>There is a way to build IPF rules that utilize the power
|
|
of script symbolic substitution. For more information, see
|
|
<xref linkend="firewalls-ipf-rules-script"/>.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>IPFSTAT</title>
|
|
|
|
<indexterm><primary><command>ipfstat</command></primary></indexterm>
|
|
|
|
<indexterm>
|
|
<primary>IPFILTER</primary>
|
|
|
|
<secondary>statistics</secondary>
|
|
</indexterm>
|
|
|
|
<para>The default behavior of &man.ipfstat.8; is to retrieve
|
|
and display the totals of the accumulated statistics gathered
|
|
by applying the rules against packets going in and out of the
|
|
firewall since it was last started, or since the last time the
|
|
accumulators were reset to zero using <command>ipf
|
|
-Z</command>.</para>
|
|
|
|
<para>Refer to &man.ipfstat.8; for details.</para>
|
|
|
|
<para>The default &man.ipfstat.8; output will look something
|
|
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 <acronym>TCP</acronym> 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
|
|
<acronym>TCP</acronym> cksum fails(in): 0 (out): 0
|
|
Packet log flags set: (0)</screen>
|
|
|
|
<para>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.</para>
|
|
|
|
<para><command>ipfstat -in</command> displays the inbound
|
|
internal rules table with rule numbers.</para>
|
|
|
|
<para><command>ipfstat -on</command> displays the outbound
|
|
internal rules table with rule numbers.</para>
|
|
|
|
<para>The output will look something like this:</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><command>ipfstat -ih</command> displays the inbound
|
|
internal rules table, prefixing each rule with a count of how
|
|
many times the rule was matched.</para>
|
|
|
|
<para><command>ipfstat -oh</command> displays the outbound
|
|
internal rules table, prefixing each rule with a count of how
|
|
many times the rule was matched.</para>
|
|
|
|
<para>The output will look something like this:</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>One of the most important options of
|
|
<command>ipfstat</command> is <option>-t</option> which
|
|
displays the state table in a way similar to how &man.top.1;
|
|
shows the &os; running process table. When a firewall is
|
|
under attack, this function provides the ability to identify
|
|
and see the attacking packets. The optional sub-flags give
|
|
the ability to select the destination or source IP, port, or
|
|
protocol to be monitored in real time. Refer to
|
|
&man.ipfstat.8; for details.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>IPMON</title>
|
|
|
|
<indexterm><primary><command>ipmon</command></primary></indexterm>
|
|
|
|
<indexterm>
|
|
<primary>IPFILTER</primary>
|
|
|
|
<secondary>logging</secondary>
|
|
</indexterm>
|
|
|
|
<para>In order for <command>ipmon</command> to work properly,
|
|
the kernel option <literal>IPFILTER_LOG</literal> must be
|
|
turned on. This command has two different modes. Native mode
|
|
is the default mode when the command is used without
|
|
<option>-D</option>.</para>
|
|
|
|
<para>Daemon mode provides a continuous system log file so that
|
|
logging of past events may be reviewed. &os; has a built in
|
|
facility to automatically rotate system logs. This is why
|
|
outputting the log information to &man.syslogd.8; is better
|
|
than the default of outputting to a regular file. 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 & 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. These can all
|
|
provide a significant edge in tracking down attackers.</para>
|
|
|
|
<para>Even with the logging facility enabled, IPF will not
|
|
generate any rule logging by default. The firewall
|
|
administrator decides which rules in the ruleset should be
|
|
logged and adds the log keyword to those rules. Normally,
|
|
only deny rules are logged.</para>
|
|
|
|
<para>It is customary to include a <quote>default deny
|
|
everything</quote> rule with the log keyword included as 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>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>IPMON Logging</title>
|
|
|
|
<para>&man.syslogd.8; uses its own method for segregation of log
|
|
data. It uses groupings called <quote>facility</quote> and
|
|
<quote>level</quote>. By default, IPMON in
|
|
<option>-Ds</option> mode uses <literal>local0</literal> as
|
|
the <quote>facility</quote> name. The following 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</screen>
|
|
|
|
<!-- XXX: "can be considered short" == "with incomplete header" -->
|
|
|
|
<para>In order to setup IPFILTER 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>&man.syslogd.8; is controlled by definition statements in
|
|
<filename>/etc/syslog.conf</filename>. This file offers
|
|
considerable flexibility in how
|
|
<application>syslog</application> will deal with system
|
|
messages issued by software applications like IPF.</para>
|
|
|
|
<para>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 change
|
|
<filename>/etc/newsyslog.conf</filename> to rotate the new
|
|
log file.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>The Format of Logged Messages</title>
|
|
|
|
<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>
|
|
</orderedlist>
|
|
|
|
<para>These can be viewed with
|
|
<command>ipfstat -in</command>.</para>
|
|
|
|
<orderedlist>
|
|
<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. The order
|
|
of precedence in showing flags is: <literal>S</literal>,
|
|
<literal>p</literal>, <literal>b</literal>,
|
|
<literal>n</literal>, <literal>L</literal>. A capital
|
|
<literal>P</literal> or <literal>B</literal> means that
|
|
the packet has been logged due to a global logging
|
|
setting, not a particular rule.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The addresses written as three fields: the source
|
|
address and port separated by a comma, the -> symbol,
|
|
and the destination address and port. For example:
|
|
<literal>209.53.17.22,80 ->
|
|
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 ICMP packet, there will be two fields
|
|
at the end: the first always being <quote>ICMP</quote> and
|
|
the next being the ICMP message and sub-message type,
|
|
separated by a slash. For example: ICMP 3/3 for a port
|
|
unreachable message.</para>
|
|
</sect2>
|
|
|
|
<sect2 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>$</literal>.</para>
|
|
|
|
<para>Symbolic fields do not have the $ 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 > /etc/ipf.rules << EOF
|
|
#
|
|
# 2) This can be used to run script "as is":
|
|
/sbin/ipf -Fa -f - << EOF
|
|
|
|
# Allow out access to my ISP's Domain name server.
|
|
pass out quick on $oif proto tcp from any to $odns port = 53 $fks
|
|
pass out quick on $oif proto udp from any to $odns port = 53 $ks
|
|
|
|
# Allow out non-secure standard www function
|
|
pass out quick on $oif proto tcp from $myip to any port = 80 $fks
|
|
|
|
# Allow out secure www function https over TLS SSL
|
|
pass out quick on $oif proto tcp from $myip to any port = 443 $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 IPFILTER 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
|
|
class="directory">/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 <username>root</username>:</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>IPF Rulesets</title>
|
|
|
|
<para>A ruleset contains a group of IPF 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>
|
|
|
|
<indexterm>
|
|
<primary>IPFILTER</primary>
|
|
|
|
<secondary>rule processing order</secondary>
|
|
</indexterm>
|
|
|
|
<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>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Rule Syntax</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFILTER</primary>
|
|
|
|
<secondary>rule syntax</secondary>
|
|
</indexterm>
|
|
|
|
<para>The rule syntax presented here has been simplified to
|
|
only address the modern stateful rule context and <quote>first
|
|
matching rule wins</quote> logic. For the complete legacy
|
|
rule syntax, refer to &man.ipf.8;.</para>
|
|
|
|
<para>A <literal>#</literal> character is used to mark the
|
|
start of a comment and may appear at the end of a rule line
|
|
or on its own line. Blank lines are ignored.</para>
|
|
|
|
<para>Rules contain keywords which must be written in a specific
|
|
order from left to right on the line. Keywords are identified
|
|
in bold type. Some keywords have sub-options which may be
|
|
keywords themselves and also include more sub-options. Each
|
|
of the headings in the below syntax has a bold section header
|
|
which expands on the content.</para>
|
|
|
|
<!-- This section is probably wrong. See the OpenBSD flag -->
|
|
<!-- What is the "OpenBSD flag"? Reference please -->
|
|
|
|
<para><replaceable>ACTION IN-OUT OPTIONS SELECTION STATEFUL
|
|
PROTO SRC_ADDR,DST_ADDR OBJECT PORT_NUM TCP_FLAG
|
|
STATEFUL</replaceable></para>
|
|
|
|
<para><replaceable>ACTION</replaceable> = block | pass</para>
|
|
|
|
<para><replaceable>IN-OUT</replaceable> = in | out</para>
|
|
|
|
<para><replaceable>OPTIONS</replaceable> = log | quick | on
|
|
interface-name</para>
|
|
|
|
<para><replaceable>SELECTION</replaceable> = proto value |
|
|
source/destination IP | port = number | flags
|
|
flag-value</para>
|
|
|
|
<para><replaceable>PROTO</replaceable> = tcp/udp | udp | tcp |
|
|
icmp</para>
|
|
|
|
<para><replaceable>SRC_ADD,DST_ADDR</replaceable> = all | from
|
|
object to object</para>
|
|
|
|
<para><replaceable>OBJECT</replaceable> = IP address |
|
|
any</para>
|
|
|
|
<para><replaceable>PORT_NUM</replaceable> = port number</para>
|
|
|
|
<para><replaceable>TCP_FLAG</replaceable> = S</para>
|
|
|
|
<para><replaceable>STATEFUL</replaceable> = keep state</para>
|
|
|
|
<sect3>
|
|
<title>ACTION</title>
|
|
|
|
<para>The action keyword indicates what to do with the packet
|
|
if it matches the rest of the filter rule. Each rule
|
|
<emphasis>must</emphasis> have an action. The following
|
|
actions are recognized:</para>
|
|
|
|
<para><literal>block</literal> indicates that the packet
|
|
should be dropped if the selection parameters match the
|
|
packet.</para>
|
|
|
|
<para><literal>pass</literal> indicates that the packet should
|
|
exit the firewall if the selection parameters match the
|
|
packet.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>IN-OUT</title>
|
|
|
|
<para>A mandatory requirement is that each filter rule
|
|
explicitly state which side of the I/O it is to be used
|
|
on. The next keyword must be either <literal>in</literal>
|
|
or <literal>out</literal> and one or the other has to be
|
|
included or the rule will not pass syntax checks.</para>
|
|
|
|
<para><literal>in</literal> means this rule is being applied
|
|
against an inbound packet which has just been received on
|
|
the interface facing the public Internet.</para>
|
|
|
|
<para><literal>out</literal> means this rule is being applied
|
|
against an outbound packet destined for the interface facing
|
|
the public Internet.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>OPTIONS</title>
|
|
|
|
<note>
|
|
<para>These options must be used in the order shown
|
|
here.</para>
|
|
</note>
|
|
|
|
<para><literal>log</literal> indicates that the packet header
|
|
will be written to the &man.ipl.4; packet log pseudo-device
|
|
if the selection parameters match the packet.</para>
|
|
|
|
<para><literal>quick</literal> indicates that if the selection
|
|
parameters match the packet, this rule will be the last
|
|
rule checked, and no further processing of any following
|
|
rules will occur for this packet.</para>
|
|
|
|
<para><literal>on</literal> indicates the interface name to
|
|
be incorporated into the selection parameters. Interface
|
|
names are as displayed by &man.ifconfig.8;. Using this
|
|
option, the rule will only match if the packet is going
|
|
through that interface in the specified direction.</para>
|
|
|
|
<para>When a packet is logged, the headers of the packet are
|
|
written to the &man.ipl.4; packet logging pseudo-device.
|
|
Immediately following 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>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>SELECTION</title>
|
|
|
|
<para>The keywords described in this section are used to
|
|
describe attributes of the packet to be checked when
|
|
determining whether or not rules match. There is a
|
|
keyword subject, and it has sub-option keywords, one of
|
|
which has to be selected. The following general-purpose
|
|
attributes are provided for matching, and must be used in
|
|
this order:</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>PROTO</title>
|
|
|
|
<para><literal>proto</literal> is the subject keyword which
|
|
must include one of its corresponding keyword sub-option
|
|
values. The sub-option indicates a specific protocol to be
|
|
matched against.</para>
|
|
|
|
<para><literal>tcp/udp | udp | tcp | icmp</literal> or any
|
|
protocol names found in <filename>/etc/protocols</filename>
|
|
are recognized and may be used. The special protocol
|
|
keyword <literal>tcp/udp</literal> may be used to match
|
|
either a <acronym>TCP</acronym> or a <acronym>UDP</acronym>
|
|
packet, and has been added as a convenience to save
|
|
duplication of otherwise identical rules.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>SRC_ADDR/DST_ADDR</title>
|
|
|
|
<para>The <literal>all</literal> keyword is equivalent to
|
|
<quote>from any to any</quote> with no other match
|
|
parameters.</para>
|
|
|
|
<para><literal>from | to src to dst</literal>: the
|
|
<literal>from</literal> and <literal>to</literal>
|
|
keywords are used to match against IP addresses. Rules
|
|
must specify <emphasis>both</emphasis> the source and
|
|
destination parameters. <literal>any</literal> is a special
|
|
keyword that matches any IP address. Examples include:
|
|
<literal>from any to any</literal>, <literal>from 0.0.0.0/0
|
|
to any</literal>, <literal>from any to
|
|
0.0.0.0/0</literal>, <literal>from 0.0.0.0 to
|
|
any</literal>, and <literal>from any to
|
|
0.0.0.0</literal>.</para>
|
|
|
|
<para>There is no way to match ranges of IP addresses which
|
|
do not express themselves easily using the dotted numeric
|
|
form / mask-length notation. The <filename
|
|
role="package">net-mgmt/ipcalc</filename> port may be
|
|
used to ease the calculation. Additional information
|
|
is available at the utility's web page: <ulink
|
|
url="http://jodies.de/ipcalc"></ulink>.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>PORT</title>
|
|
|
|
<para>If a port match is included, for either or both of
|
|
source and destination, it is only applied to
|
|
<acronym>TCP</acronym> and <acronym>UDP</acronym> packets.
|
|
When composing port comparisons, either the service name
|
|
from <filename>/etc/services</filename> or an integer port
|
|
number may be used. When the port appears as part of the
|
|
<literal>from</literal> object, it matches the source port
|
|
number. When it appears as part of the
|
|
<literal>to</literal> object, it matches the destination
|
|
port number. An example usage is <literal>from any to any
|
|
port = 80</literal></para>
|
|
|
|
<para>Single port comparisons may be done in a number of ways,
|
|
using a number of different comparison operators. Instead
|
|
of the <literal>=</literal> shown in the example above,
|
|
the following operators may be used: <literal>!=</literal>,
|
|
<literal><</literal>, <literal>></literal>,
|
|
<literal><=</literal>, <literal>>=</literal>,
|
|
<literal>eq</literal>, <literal>ne</literal>,
|
|
<literal>lt</literal>, <literal>gt</literal>,
|
|
<literal>le</literal>, and <literal>ge</literal>.</para>
|
|
|
|
<para>To specify port ranges, place the two port numbers
|
|
between <literal><></literal> or
|
|
<literal>><</literal></para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title><acronym>TCP</acronym>_FLAG</title>
|
|
|
|
<para>Flags are only effective for <acronym>TCP</acronym>
|
|
filtering. The letters represent one of the possible flags
|
|
that can be matched against the <acronym>TCP</acronym>
|
|
packet header.</para>
|
|
|
|
<para>The modernized rules processing logic uses the
|
|
<literal>flags S</literal> parameter to identify the TCP
|
|
session start request.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>STATEFUL</title>
|
|
|
|
<para><literal>keep state</literal> indicates that on a pass
|
|
rule, any packets that match the rules selection parameters
|
|
should activate the stateful filtering facility.</para>
|
|
</sect3>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Stateful Filtering</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFILTER</primary>
|
|
|
|
<secondary>stateful filtering</secondary>
|
|
</indexterm>
|
|
|
|
<!-- XXX: duplicated -->
|
|
|
|
<para>Stateful filtering treats traffic as a bi-directional
|
|
exchange of packets comprising a session. When activated,
|
|
<literal>keep-state</literal> 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>IPF stateful filtering will also allow
|
|
<acronym>ICMP</acronym> packets related to an existing
|
|
<acronym>TCP</acronym> or <acronym>UDP</acronym> session. So,
|
|
if an <acronym>ICMP</acronym> type 3 code 4 packet is a
|
|
response in a session started by a keep state rule, it will
|
|
automatically be allowed. Any packet that IPF can be certain
|
|
is part of an active session, even if it is a different
|
|
protocol, will be allowed.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>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>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>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<!-- XXX: This section needs a rewrite -->
|
|
|
|
<title>Inclusive Ruleset Example</title>
|
|
|
|
<para>The following ruleset is an example of an inclusive type
|
|
of firewall which only allows services matching
|
|
<literal>pass</literal> rules and blocks all others by
|
|
default. Network firewalls intended to protect other machines
|
|
should have at least two interfaces, and are generally
|
|
configured to trust the <acronym>LAN</acronym> and to not
|
|
trust the public Internet. Alternatively, a host based
|
|
firewall might be configured to protect only the system it is
|
|
running on, and is appropriate for servers on an untrusted
|
|
network or a desktop system not protected by firewall on the
|
|
network.</para>
|
|
|
|
<para>&os; uses interface <devicename>lo0</devicename> and IP
|
|
address <hostid role="ipaddr">127.0.0.1</hostid> for internal
|
|
communication within the operating system. The firewall rules
|
|
must contain rules to allow free movement of these internally
|
|
used packets.</para>
|
|
|
|
<para>The interface which faces the public Internet is the one
|
|
specified in the rules that authorize and control access of
|
|
the outbound and inbound connections.</para>
|
|
|
|
<para>In cases where one or more NICs are cabled to private
|
|
network segments, those interfaces may require rules to allow
|
|
packets originating from those LAN interfaces transit to each
|
|
other or to the Internet.</para>
|
|
|
|
<para>The rules should be organized into three major
|
|
sections: the trusted interfaces, then the public
|
|
interface outbound, and lastly, the public untrusted interface
|
|
inbound.</para>
|
|
|
|
<para>The rules in each of the public interface 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 on that interface and
|
|
direction.</para>
|
|
|
|
<para>The outbound section in the following ruleset only
|
|
contains <literal>pass</literal> rules which uniquely identify
|
|
the services that are authorized for public Internet access.
|
|
All the rules use <literal>quick</literal>,
|
|
<literal>on</literal>, <literal>proto</literal>,
|
|
<literal>port</literal>, and <literal>keep state</literal>.
|
|
The <literal>proto tcp</literal> rules include
|
|
<literal>flag</literal> to identify the session start request
|
|
as the triggering packet to activate the stateful
|
|
facility.</para>
|
|
|
|
<para>The inbound section blocks undesirable packets first, for
|
|
two different reasons. The first is that malicious packets
|
|
may be partial matches for legitimate traffic. These packets
|
|
have to be discarded rather than allowed, based on their
|
|
partial matches against the <literal>allow</literal> rules.
|
|
The second reason is that known and uninteresting rejects may
|
|
be blocked silently, rather than being logged by the last rule
|
|
in the section.</para>
|
|
|
|
<para>The ruleset should ensure that there is no response
|
|
returned for any undesirable traffic. Invalid packets should
|
|
be silently dropped so that the attacker has no knowledge if
|
|
the packets reached the system. Rules that include a
|
|
<literal>log first</literal> option, will only log the event
|
|
the first time they are triggered. This option is included in
|
|
the sample <literal>nmap OS fingerprint</literal> rule. The
|
|
<filename role="package">security/nmap</filename> utility is
|
|
commonly used by attackers who attempt to identify the
|
|
operating system of the server.</para>
|
|
|
|
<para>Any time there are logged messages on a rule with
|
|
the <literal>log first</literal> option,
|
|
<command>ipfstat -hio</command> should be executed
|
|
to evaluate how many times the rule has been matched. A
|
|
large number of matches usually indicates that the system is
|
|
being flooded or is under attack.</para>
|
|
|
|
<para>To lookup unknown port numbers, refer to
|
|
<filename>/etc/services</filename>. Alternatively, visit
|
|
<ulink
|
|
url="http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers"></ulink>
|
|
and do a port number lookup to find the purpose of a
|
|
particular port number.</para>
|
|
|
|
<para>Check out this link for port numbers used by Trojans
|
|
<ulink
|
|
url="http://www.sans.org/security-resources/idfaq/oddports.php"></ulink>.</para>
|
|
|
|
<para>The following ruleset creates an
|
|
<literal>inclusive</literal> firewall ruleset which can be
|
|
easily customized by commenting out
|
|
<literal>pass</literal> rules for services that should not
|
|
be authorized.</para>
|
|
|
|
<para>To avoid logging unwanted messages, add a
|
|
<literal>block</literal> rule in the inbound section.</para>
|
|
|
|
<para>Change the <devicename>dc0</devicename> interface name in
|
|
every rule to the interface name that connects the system to
|
|
the public Internet.</para>
|
|
|
|
<para>The following statements were added to
|
|
<filename>/etc/ipf.rules</filename>:</para>
|
|
|
|
<programlisting>#################################################################
|
|
# No restrictions on Inside LAN Interface for private network
|
|
# Not needed unless you have LAN
|
|
#################################################################
|
|
|
|
#pass out quick on xl0 all
|
|
#pass in quick on xl0 all
|
|
|
|
#################################################################
|
|
# No restrictions on Loopback Interface
|
|
#################################################################
|
|
pass in quick on lo0 all
|
|
pass out quick on lo0 all
|
|
|
|
#################################################################
|
|
# Interface facing Public Internet (Outbound Section)
|
|
# Match session start requests originating from behind the
|
|
# firewall on the private network
|
|
# or from this gateway server destined for the public Internet.
|
|
#################################################################
|
|
|
|
# Allow out access to my ISP's Domain name server.
|
|
# xxx must be the IP address of your ISP's DNS.
|
|
# Dup these lines if your ISP has more than one DNS server
|
|
# Get the IP addresses from /etc/resolv.conf file
|
|
pass out quick on dc0 proto tcp from any to xxx port = 53 flags S keep state
|
|
pass out quick on dc0 proto udp from any to xxx port = 53 keep state
|
|
|
|
# Allow out access to my ISP's DHCP server for cable or DSL networks.
|
|
# This rule is not needed for 'user ppp' type connection to the
|
|
# public Internet, so you can delete this whole group.
|
|
# Use the following rule and check log for IP address.
|
|
# Then put IP address in commented out rule & delete 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 out non-secure standard www function
|
|
pass out quick on dc0 proto tcp from any to any port = 80 flags S keep state
|
|
|
|
# Allow out secure www function https over TLS SSL
|
|
pass out quick on dc0 proto tcp from any to any port = 443 flags S keep state
|
|
|
|
# Allow out send & get email function
|
|
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 out Time
|
|
pass out quick on dc0 proto tcp from any to any port = 37 flags S keep state
|
|
|
|
# Allow out nntp news
|
|
pass out quick on dc0 proto tcp from any to any port = 119 flags S keep state
|
|
|
|
# Allow out gateway & LAN users' non-secure FTP ( both passive & active modes)
|
|
# This function uses the IP<acronym>NAT</acronym> built in FTP proxy function coded in
|
|
# the nat rules file to make this single rule function correctly.
|
|
# If you want to use the pkg_add command to install application packages
|
|
# on your gateway system you need this rule.
|
|
pass out quick on dc0 proto tcp from any to any port = 21 flags S keep state
|
|
|
|
# Allow out ssh/sftp/scp (telnet/rlogin/FTP replacements)
|
|
# This function is using SSH (secure shell)
|
|
pass out quick on dc0 proto tcp from any to any port = 22 flags S keep state
|
|
|
|
# Allow out insecure Telnet
|
|
pass out quick on dc0 proto tcp from any to any port = 23 flags S keep state
|
|
|
|
# Allow out FreeBSD CVSup
|
|
pass out quick on dc0 proto tcp from any to any port = 5999 flags S keep state
|
|
|
|
# Allow out ping to public Internet
|
|
pass out quick on dc0 proto icmp from any to any icmp-type 8 keep state
|
|
|
|
# Allow out whois from LAN to public Internet
|
|
pass out quick on dc0 proto tcp from any to any port = 43 flags S keep state
|
|
|
|
# Block and log only the first occurrence of everything
|
|
# else that's trying to get out.
|
|
# This rule implements the default block
|
|
block out log first quick on dc0 all
|
|
|
|
#################################################################
|
|
# Interface facing Public Internet (Inbound Section)
|
|
# Match packets originating from the public Internet
|
|
# destined for this gateway server or the private network.
|
|
#################################################################
|
|
|
|
# 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 & E multicast
|
|
|
|
##### Block a bunch of different nasty things. ############
|
|
# That I do not want to see in the log
|
|
|
|
# Block frags
|
|
block in quick on dc0 all with frags
|
|
|
|
# Block short tcp packets
|
|
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 nmap OS fingerprint attempts
|
|
# Log first occurrence of these so I can get their IP address
|
|
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
|
|
block in quick on dc0 proto icmp all icmp-type 8
|
|
|
|
# Block ident
|
|
block in quick on dc0 proto tcp from any to any port = 113
|
|
|
|
# Block all Netbios service. 137=name, 138=datagram, 139=session
|
|
# Netbios is MS/Windows sharing services.
|
|
# Block MS/Windows hosts2 name server requests 81
|
|
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
|
|
|
|
# Allow traffic in from ISP's DHCP server. This rule must contain
|
|
# the IP address of your ISP's DHCP server as it is the only
|
|
# authorized source to send this packet type. Only necessary for
|
|
# cable or DSL configurations. This rule is not needed for
|
|
# 'user ppp' type connection to the public Internet.
|
|
# This is the same IP address you captured and
|
|
# used in the outbound section.
|
|
pass in quick on dc0 proto udp from z.z.z.z to any port = 68 keep state
|
|
|
|
# Allow in standard www function because I have apache server
|
|
pass in quick on dc0 proto tcp from any to any port = 80 flags S keep state
|
|
|
|
# Allow in non-secure Telnet session from public Internet
|
|
# labeled non-secure because ID/PW passed over public Internet as clear text.
|
|
# Delete this sample group if you do not have telnet server enabled.
|
|
#pass in quick on dc0 proto tcp from any to any port = 23 flags S keep state
|
|
|
|
# Allow in secure FTP, Telnet, and SCP from public Internet
|
|
# This function is using SSH (secure shell)
|
|
pass in quick on dc0 proto tcp from any to any port = 22 flags S keep state
|
|
|
|
# Block and log only first occurrence of all remaining traffic
|
|
# coming into the firewall. The logging of only the first
|
|
# occurrence avoids filling up disk with Denial of Service logs.
|
|
# This rule implements the default block.
|
|
block in log first quick on dc0 all
|
|
################### End of rules file #####################################</programlisting>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title><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>
|
|
|
|
<para><acronym>NAT</acronym> stands for <emphasis>Network
|
|
Address Translation</emphasis>. In &linux;, NAT is called
|
|
<quote>IP Masquerading</quote>. The IPF
|
|
<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>
|
|
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>IP<acronym>NAT</acronym></title>
|
|
|
|
<indexterm>
|
|
<primary>NAT</primary>
|
|
|
|
<secondary>and IPFILTER</secondary>
|
|
</indexterm>
|
|
|
|
<indexterm><primary><command>ipnat</command></primary></indexterm>
|
|
|
|
<para><acronym>NAT</acronym> rules are loaded using
|
|
<command>ipnat</command>. Typically, the
|
|
<acronym>NAT</acronym> rules are stored in
|
|
<filename>/etc/ipnat.rules</filename>. See &man.ipnat.8; for
|
|
details.</para>
|
|
|
|
<para>When the file containing the <acronym>NAT</acronym> rules
|
|
is edited after <acronym>NAT</acronym> has been started, run
|
|
<command>ipnat</command> with <option>-CF</option> to delete
|
|
the internal in use <acronym>NAT</acronym> rules and flush the
|
|
contents of the translation table of all active
|
|
entries.</para>
|
|
|
|
<para>To reload the <acronym>NAT</acronym> rules, issue a
|
|
command like this:</para>
|
|
|
|
<screen>&prompt.root; <userinput>ipnat -CF -f
|
|
/etc/ipnat.rules</userinput></screen>
|
|
|
|
<para>To display some <acronym>NAT</acronym> statistics, use
|
|
this command:</para>
|
|
|
|
<screen>&prompt.root; <userinput>ipnat -s</userinput></screen>
|
|
|
|
<para>To list the <acronym>NAT</acronym> table's current
|
|
mappings, use this command:</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/table entries:</para>
|
|
|
|
<screen>&prompt.root; <userinput>ipnat -v</userinput></screen>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>IP<acronym>NAT</acronym> Rules</title>
|
|
|
|
<para><acronym>NAT</acronym> rules are flexible and can
|
|
accomplish many different things to fit the needs of
|
|
commercial and home users.</para>
|
|
|
|
<para>The rule syntax presented here has been simplified to
|
|
what is most commonly used in a non-commercial environment.
|
|
For a complete rule syntax description, refer to
|
|
&man.ipnat.5;.</para>
|
|
|
|
<para>The syntax for a <acronym>NAT</acronym> rule looks like
|
|
this:</para>
|
|
|
|
<programlisting>map <replaceable>IF</replaceable> <replaceable>LAN_IP_RANGE</replaceable> -> <replaceable>PUBLIC_ADDRESS</replaceable></programlisting>
|
|
|
|
<para>The keyword <literal>map</literal> starts the rule.</para>
|
|
|
|
<para>Replace <replaceable>IF</replaceable> with the external
|
|
interface.</para>
|
|
|
|
<para>The <replaceable>LAN_IP_RANGE</replaceable> is used by the
|
|
internal clients use for IP Addressing. Usually, this is
|
|
something like <hostid
|
|
role="ipaddr">192.168.1.0/24</hostid>.</para>
|
|
|
|
<para>The <replaceable>PUBLIC_ADDRESS</replaceable> can either
|
|
be the static external IP address or the special keyword
|
|
<literal>0/32</literal> which uses the IP address assigned to
|
|
<replaceable>IF</replaceable>.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>How <acronym>NAT</acronym> Works</title>
|
|
|
|
<para>In IPF, when a packet arrives at the firewall from the LAN
|
|
with a public destination, it passes through the outbound
|
|
filter rules. <acronym>NAT</acronym> gets its turn at the
|
|
packet and applies its rules top down, where the first
|
|
matching rule wins. <acronym>NAT</acronym> tests each of its
|
|
rules against the packet's interface name and source IP
|
|
address. When a packet's interface name matches a
|
|
<acronym>NAT</acronym> rule, the packet's source IP address in
|
|
the private LAN is checked to see if it falls within the IP
|
|
address range specified to the left of the arrow symbol on the
|
|
<acronym>NAT</acronym> rule. On a match, the packet has its
|
|
source IP address rewritten with the public IP address
|
|
obtained by the <literal>0/32</literal> keyword.
|
|
<acronym>NAT</acronym> posts an entry in its internal
|
|
<acronym>NAT</acronym> table so when the packet returns from
|
|
the public Internet it can be mapped back to its original
|
|
private IP address and then passed to the filter rules for
|
|
processing.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Enabling IP<acronym>NAT</acronym></title>
|
|
|
|
<para>To enable IP<acronym>NAT</acronym>, add these statements
|
|
to <filename>/etc/rc.conf</filename>.</para>
|
|
|
|
<para>To enable the machine to route traffic between
|
|
interfaces:</para>
|
|
|
|
<programlisting>gateway_enable="YES"</programlisting>
|
|
|
|
<para>To start IP<acronym>NAT</acronym> automatically each
|
|
time:</para>
|
|
|
|
<programlisting>ipnat_enable="YES"</programlisting>
|
|
|
|
<para>To specify where to load the IP<acronym>NAT</acronym>
|
|
rules from:</para>
|
|
|
|
<programlisting>ipnat_rules="/etc/ipnat.rules"</programlisting>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title><acronym>NAT</acronym> for a Large LAN</title>
|
|
|
|
<para>For networks that have large numbers of systems on the LAN
|
|
or networks with more than a single LAN, the process of
|
|
funneling all those private IP addresses into a single public
|
|
IP address becomes a resource problem that may cause problems
|
|
with the same port numbers being used many times across many
|
|
connections, causing collisions. There are two ways to
|
|
relieve this resource problem.</para>
|
|
|
|
<sect3>
|
|
<title>Assigning Ports to Use</title>
|
|
|
|
<para>A normal NAT rule would look like:</para>
|
|
|
|
<programlisting>map dc0 192.168.1.0/24 -> 0/32</programlisting>
|
|
|
|
<para>In the above rule, the packet's source port is unchanged
|
|
as the packet passes through IP<acronym>NAT</acronym>. By
|
|
adding the <literal>portmap</literal> keyword,
|
|
IP<acronym>NAT</acronym> can be directed to only use
|
|
source ports in the specified range. For example, the
|
|
following rule will tell IP<acronym>NAT</acronym> to modify
|
|
the source port to be within the range shown:</para>
|
|
|
|
<programlisting>map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:60000</programlisting>
|
|
|
|
<para>Additionally, the <literal>auto</literal> keyword tells
|
|
IP<acronym>NAT</acronym> to determine which ports are
|
|
available for use:</para>
|
|
|
|
<programlisting>map dc0 192.168.1.0/24 -> 0/32 portmap tcp/udp auto</programlisting>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Using a Pool of Public Addresses</title>
|
|
|
|
<para>In very large LANs there comes a point where there are
|
|
just too many LAN addresses to fit into a single public
|
|
address. If a block of public IP addresses is available,
|
|
these addresses can be used as a <quote>pool</quote>, and
|
|
IP<acronym>NAT</acronym> may pick one of the public IP
|
|
addresses as packet addresses are mapped on their way
|
|
out.</para>
|
|
|
|
<para>For example, instead of mapping all packets through a
|
|
single public IP address:</para>
|
|
|
|
<programlisting>map dc0 192.168.1.0/24 -> 204.134.75.1</programlisting>
|
|
|
|
<para>A range of public IP addresses can be specified either
|
|
with a netmask:</para>
|
|
|
|
<programlisting>map dc0 192.168.1.0/24 -> 204.134.75.0/255.255.255.0</programlisting>
|
|
|
|
<para>or using CIDR notation:</para>
|
|
|
|
<programlisting>map dc0 192.168.1.0/24 -> 204.134.75.0/24</programlisting>
|
|
</sect3>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Port Redirection</title>
|
|
|
|
<para>A common practice is to have a web server, email server,
|
|
database server, and DNS server each segregated to a different
|
|
system on the LAN. In this case, the traffic from these
|
|
servers still has to undergo <acronym>NAT</acronym>, but there
|
|
has to be some way to direct the inbound traffic to the
|
|
correct server. For example, a web server operating on LAN
|
|
address <hostid
|
|
role="ipaddr">10.0.10.25</hostid> and using a single public
|
|
IP address of <hostid role="ipaddr">20.20.20.5</hostid>, would
|
|
use this rule:</para>
|
|
|
|
<programlisting>rdr dc0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80</programlisting>
|
|
|
|
<para>or:</para>
|
|
|
|
<programlisting>rdr dc0 0.0.0.0/0 port 80 -> 10.0.10.25 port 80</programlisting>
|
|
|
|
<para>For a LAN DNS server on a private address of <hostid
|
|
role="ipaddr">10.0.10.33</hostid> that needs to receive
|
|
public DNS requests:</para>
|
|
|
|
<programlisting>rdr dc0 20.20.20.5/32 port 53 -> 10.0.10.33 port 53 udp</programlisting>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>FTP and <acronym>NAT</acronym></title>
|
|
|
|
<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 <ulink
|
|
url="http://www.slacksite.com/other/ftp.html"></ulink>.</para>
|
|
|
|
<sect3>
|
|
<title>IP<acronym>NAT</acronym> Rules</title>
|
|
|
|
<para>IP<acronym>NAT</acronym> has a built in FTP proxy option
|
|
which can be specified on the <acronym>NAT</acronym> map
|
|
rule. It can monitor all outbound packet traffic for FTP
|
|
active or passive start session requests and dynamically
|
|
create temporary filter rules containing the port number
|
|
being used by the data channel. This eliminates the
|
|
security risk FTP normally exposes the firewall to as it no
|
|
longer needs to open large ranges of high order ports for
|
|
FTP connections.</para>
|
|
|
|
<para>This rule will handle all the traffic for the internal
|
|
LAN:</para>
|
|
|
|
<programlisting>map dc0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp</programlisting>
|
|
|
|
<para>This rule handles the FTP traffic from the
|
|
gateway:</para>
|
|
|
|
<programlisting>map dc0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp</programlisting>
|
|
|
|
<para>This rule handles all non-FTP traffic from the internal
|
|
LAN:</para>
|
|
|
|
<programlisting>map dc0 10.0.10.0/29 -> 0/32</programlisting>
|
|
|
|
<para>The FTP <literal>map</literal> rules go before the
|
|
<acronym>NAT</acronym> rule so that when a packet matches an
|
|
FTP rule, the FTP proxy creates temporary filter rules to
|
|
let the FTP session packets pass and undergo
|
|
<acronym>NAT</acronym>. All LAN packets that are not FTP
|
|
will not match the FTP rules but will undergo
|
|
<acronym>NAT</acronym> if they match the third rule.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>IP<acronym>NAT</acronym> FTP Filter Rules</title>
|
|
|
|
<para>Only one filter rule is needed for FTP if the
|
|
<acronym>NAT</acronym> FTP proxy is used.</para>
|
|
|
|
<para>Without the FTP proxy, the following three rules will be
|
|
needed:</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 > 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>
|
|
</sect3>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="firewalls-ipfw">
|
|
<title>IPFW</title>
|
|
|
|
<indexterm>
|
|
<primary>firewall</primary>
|
|
|
|
<secondary>IPFW</secondary>
|
|
</indexterm>
|
|
|
|
<para><acronym>IPFW</acronym> is a stateful firewall written for
|
|
&os; which also provides a traffic shaper, packet scheduler,
|
|
and in-kernel NAT.</para>
|
|
|
|
<para>&os; provides a sample ruleset in
|
|
<filename>/etc/rc.firewall</filename>. The sample ruleset
|
|
define several firewall types for common scenarios to assist
|
|
novice users in generating an appropriate ruleset.
|
|
&man.ipfw.8; provides a powerful syntax which advanced users can
|
|
use to craft customized rulesets that meet the security
|
|
requirements of a given environment.</para>
|
|
|
|
<para>IPFW is composed of several components: the kernel firewall
|
|
filter rule processor and its integrated packet accounting
|
|
facility, the logging facility, the
|
|
<literal>divert</literal> rule which triggers
|
|
<acronym>NAT</acronym>, the dummynet traffic shaper facilities,
|
|
the <literal>fwd rule</literal> forward facility, the bridge
|
|
facility, and the ipstealth facility. IPFW supports both IPv4
|
|
and IPv6.</para>
|
|
|
|
<sect2 id="firewalls-ipfw-enable">
|
|
<title>Enabling IPFW</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFW</primary>
|
|
|
|
<secondary>enabling</secondary>
|
|
</indexterm>
|
|
|
|
<para>IPFW is included in the basic &os; install as a run time
|
|
loadable module. The system will dynamically load the kernel
|
|
module when <filename>rc.conf</filename> contains the
|
|
statement <literal>firewall_enable="YES"</literal>. After
|
|
rebooting the system, the following white highlighted message
|
|
is displayed on the screen as part of the boot process:</para>
|
|
|
|
<screen>ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to deny, logging disabled</screen>
|
|
|
|
<para>The loadable module includes logging ability. To enable
|
|
logging and set the verbose logging limit, add these
|
|
statements to
|
|
<filename>/etc/sysctl.conf</filename> before rebooting:</para>
|
|
|
|
<programlisting>net.inet.ip.fw.verbose=1
|
|
net.inet.ip.fw.verbose_limit=5</programlisting>
|
|
</sect2>
|
|
|
|
<sect2 id="firewalls-ipfw-kernel">
|
|
<title>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>IPFW</primary>
|
|
|
|
<secondary>kernel options</secondary>
|
|
</indexterm>
|
|
|
|
<para>For those users who wish to statically compile kernel
|
|
IPFW support, the following options are available for the
|
|
custom kernel configuration file:</para>
|
|
|
|
<programlisting>options IPFIREWALL</programlisting>
|
|
|
|
<para>This option enables IPFW as part of the kernel.</para>
|
|
|
|
<programlisting>options IPFIREWALL_VERBOSE</programlisting>
|
|
|
|
<para>This option enables logging of packets that pass through
|
|
IPFW and have the <literal>log</literal> keyword specified in
|
|
the ruleset.</para>
|
|
|
|
<programlisting>options IPFIREWALL_VERBOSE_LIMIT=5</programlisting>
|
|
|
|
<para>This option limits the number of packets logged through
|
|
&man.syslogd.8;, on a per-entry basis. This option may be
|
|
used in hostile environments, when firewall activity logging
|
|
is desired. This will close a possible denial of service
|
|
attack via syslog flooding.</para>
|
|
|
|
<indexterm>
|
|
<primary>kernel options</primary>
|
|
|
|
<secondary>IPFIREWALL_DEFAULT_TO_ACCEPT</secondary>
|
|
</indexterm>
|
|
|
|
<programlisting>options IPFIREWALL_DEFAULT_TO_ACCEPT</programlisting>
|
|
|
|
<para>This option allows everything to pass through the firewall
|
|
by default, which is a good idea when the firewall is being
|
|
set up for the first time.</para>
|
|
|
|
<indexterm>
|
|
<primary>kernel options</primary>
|
|
|
|
<secondary>IPDIVERT</secondary>
|
|
</indexterm>
|
|
|
|
<programlisting>options IPDIVERT</programlisting>
|
|
|
|
<para>This option enables the use of <acronym>NAT</acronym>
|
|
functionality.</para>
|
|
|
|
<note>
|
|
<para>The firewall will block all incoming and outgoing
|
|
packets if either the
|
|
<literal>IPFIREWALL_DEFAULT_TO_ACCEPT</literal> kernel
|
|
option or a rule to explicitly allow these connections is
|
|
missing.</para>
|
|
</note>
|
|
</sect2>
|
|
|
|
<sect2 id="firewalls-ipfw-rc">
|
|
<title><filename>/etc/rc.conf</filename> Options</title>
|
|
|
|
<para>Enables the firewall:</para>
|
|
|
|
<programlisting>firewall_enable="YES"</programlisting>
|
|
|
|
<para>To select one of the default firewall types provided by
|
|
&os;, select one by reading
|
|
<filename>/etc/rc.firewall</filename> and specify it in
|
|
the following:</para>
|
|
|
|
<programlisting>firewall_type="open"</programlisting>
|
|
|
|
<para>Available values for this setting 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>UNKNOWN</literal>: disables the loading of
|
|
firewall rules.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><filename><replaceable>filename</replaceable></filename>:
|
|
absolute path of the file containing the firewall
|
|
rules.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Two methods are available for loading custom
|
|
<application>ipfw</application> rules. One is to set the
|
|
<literal>firewall_type</literal> variable to the absolute
|
|
path of the file which contains the firewall rules.</para>
|
|
|
|
<para>The other method is to set the
|
|
<literal>firewall_script</literal> variable to the absolute
|
|
path of an executable script that includes
|
|
<command>ipfw</command> commands. A ruleset script that
|
|
blocks all incoming and outgoing traffic would look like
|
|
this:</para>
|
|
|
|
<programlisting>#!/bin/sh
|
|
|
|
ipfw -q flush
|
|
|
|
ipfw add deny in
|
|
ipfw add deny out</programlisting>
|
|
|
|
<note>
|
|
<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. The examples used in this
|
|
section assume that the <literal>firewall_script</literal>
|
|
is set to <filename>/etc/ipfw.rules</filename>.</para>
|
|
</note>
|
|
|
|
<para>Enable logging:</para>
|
|
|
|
<programlisting>firewall_logging="YES"</programlisting>
|
|
|
|
<warning>
|
|
<para><varname>firewall_logging</varname> sets the
|
|
<varname>net.inet.ip.fw.verbose</varname> sysctl
|
|
variable to the value of <literal>1</literal>. There is no
|
|
<filename>rc.conf</filename> variable to set log
|
|
limitations, but the desired value can be set using
|
|
<command>sysctl</command> or by adding the following
|
|
variable and desired value to
|
|
<filename>/etc/sysctl.conf</filename>:</para>
|
|
|
|
<programlisting>net.inet.ip.fw.verbose_limit=5</programlisting>
|
|
</warning>
|
|
|
|
<para>If the machine is acting as a gateway providing
|
|
<acronym>NAT</acronym> using &man.natd.8;,
|
|
refer to <xref linkend="network-natd"/> for information
|
|
regarding the required <filename>/etc/rc.conf</filename>
|
|
options.</para>
|
|
</sect2>
|
|
|
|
<sect2 id="firewalls-ipfw-cmd">
|
|
<title>The IPFW 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 IPFW
|
|
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>
|
|
</sect2>
|
|
|
|
<sect2 id="firewalls-ipfw-rules">
|
|
<title>IPFW Rulesets</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFW</primary>
|
|
|
|
<secondary>rule processing order</secondary>
|
|
</indexterm>
|
|
|
|
<para>When a packet enters the <acronym>IPFW</acronym> firewall,
|
|
it is compared against the first rule in the ruleset and
|
|
progresses one rule at a time, moving from top to bottom of
|
|
the set in ascending rule number sequence order. When the
|
|
packet matches the selection parameters of a rule, the rule's
|
|
action field value 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 IPFW 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>
|
|
|
|
<para>The examples in this section create an inclusive type
|
|
firewall ruleset containing the stateful <literal>keep
|
|
state</literal>, <literal>limit</literal>,
|
|
<literal>in</literal>, <literal>out</literal> and
|
|
<literal>via</literal> options. For a complete rule syntax
|
|
description, refer to &man.ipfw.8;.</para>
|
|
|
|
<warning>
|
|
<para>Be careful when working with firewall rules, as it is
|
|
easy to lock out even the administrator.</para>
|
|
</warning>
|
|
|
|
<sect3 id="firewalls-ipfw-rules-syntax">
|
|
<title>Rule Syntax</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFW</primary>
|
|
|
|
<secondary>rule syntax</secondary>
|
|
</indexterm>
|
|
|
|
<para>This section describes the keywords which comprise an
|
|
<acronym>IPFW</acronym> rule. Keywords must be written in
|
|
the following order. <literal>#</literal> is used to mark
|
|
the start of a comment and may appear at the end of a rule
|
|
line or on its own line. Blank lines are ignored.</para>
|
|
|
|
<para><replaceable>CMD RULE_NUMBER ACTION LOGGING SELECTION
|
|
STATEFUL</replaceable></para>
|
|
|
|
<sect4>
|
|
<title>CMD</title>
|
|
|
|
<para>Each new rule has to be prefixed with
|
|
<parameter>add</parameter> to add the rule to the internal
|
|
table.</para>
|
|
</sect4>
|
|
|
|
<sect4>
|
|
<title>RULE_NUMBER</title>
|
|
|
|
<para>Each rule is associated with a rule_number in the
|
|
range of <literal>1</literal> to
|
|
<literal>65535</literal>.</para>
|
|
</sect4>
|
|
|
|
<sect4>
|
|
<title>ACTION</title>
|
|
|
|
<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></para>
|
|
|
|
<para>These keywords are equivalent as they allow packets
|
|
that match the rule to exit the firewall rule processing.
|
|
The search terminates at this rule.</para>
|
|
|
|
<para><parameter>check-state</parameter></para>
|
|
|
|
<para>Checks the packet against the dynamic rules 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>deny | drop</parameter></para>
|
|
|
|
<para>Both words mean the same thing, which is to discard
|
|
packets that match this rule. The search
|
|
terminates.</para>
|
|
</sect4>
|
|
|
|
<sect4>
|
|
<title>Logging</title>
|
|
|
|
<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 the <literal>logamount</literal> parameter. If no
|
|
<literal>logamount</literal> is specified, the limit is
|
|
taken from the <command>sysctl</command> value of
|
|
<varname>net.inet.ip.fw.verbose_limit</varname>. In both
|
|
cases, 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 reset log</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>
|
|
</sect4>
|
|
|
|
<sect4>
|
|
<title>Selection</title>
|
|
|
|
<para>The keywords described in this section are used to
|
|
describe attributes of the packet to be checked when
|
|
determining whether rules match the packet or not.
|
|
The following general-purpose attributes are provided for
|
|
matching, and must be used in this order:</para>
|
|
|
|
<para><parameter>udp | tcp | icmp</parameter></para>
|
|
|
|
<para>Any other protocol names found in
|
|
<filename>/etc/protocols</filename> can be used. The
|
|
value specified is the protocol to be matched against.
|
|
This is a mandatory keyword.</para>
|
|
|
|
<para><parameter>from src to dst</parameter></para>
|
|
|
|
<para>The <literal>from</literal> and <literal>to</literal>
|
|
keywords are used to match against IP addresses. Rules
|
|
must specify <emphasis>both</emphasis> source and
|
|
destination parameters. <literal>any</literal> is a
|
|
special keyword that matches any IP address.
|
|
<literal>me</literal> is a special keyword that matches
|
|
any IP address configured on an interface in the &os;
|
|
system to represent the PC the firewall is running on.
|
|
Example usage includes <literal>from me to any</literal>,
|
|
<literal>from any to me</literal>, <literal>from 0.0.0.0/0
|
|
to any</literal>, <literal>from any to
|
|
0.0.0.0/0</literal>, <literal>from 0.0.0.0 to
|
|
any</literal>. <literal>from any to 0.0.0.0</literal>,
|
|
and <literal>from me to 0.0.0.0</literal>. IP addresses
|
|
are specified in dotted IP address format followed by the
|
|
mask in CIDR notation, or as a single host in dotted IP
|
|
address format. This keyword is a mandatory requirement.
|
|
The <filename role="package">net-mgmt/ipcalc</filename>
|
|
port may be used to assist the mask calculation.</para>
|
|
|
|
<para><parameter>port number</parameter></para>
|
|
|
|
<para>For protocols which support port numbers, such as
|
|
<acronym>TCP</acronym> and <acronym>UDP</acronym>, it
|
|
is mandatory to include the port number of the service
|
|
that will be matched. Service names from
|
|
<filename>/etc/services</filename> may be used instead
|
|
of numeric port values.</para>
|
|
|
|
<para><parameter>in | out</parameter></para>
|
|
|
|
<para>Matches incoming or outgoing packets. It is mandatory
|
|
that one or the other is included as part of the rule
|
|
matching criterion.</para>
|
|
|
|
<para><parameter>via IF</parameter></para>
|
|
|
|
<para>Matches packets going through the interface specified
|
|
by device name. The <literal>via</literal> keyword causes
|
|
the interface to always be checked as part of the match
|
|
process.</para>
|
|
|
|
<para><parameter>setup</parameter></para>
|
|
|
|
<para>This mandatory keyword identifies the session start
|
|
request for <acronym>TCP</acronym> packets.</para>
|
|
|
|
<para><parameter>keep-state</parameter></para>
|
|
|
|
<para>This is a mandatory keyword. Upon a match, the
|
|
firewall will create a dynamic rule, whose default
|
|
behavior is to match bidirectional traffic between source
|
|
and destination IP/port using the same protocol.</para>
|
|
|
|
<para><parameter>limit {src-addr | src-port | dst-addr |
|
|
dst-port}</parameter></para>
|
|
|
|
<para>The firewall will only allow
|
|
<replaceable>N</replaceable> connections with the same
|
|
set of parameters as specified in the rule. One or more
|
|
of source and destination addresses and ports can be
|
|
specified. <literal>limit</literal> and
|
|
<literal>keep-state</literal> can not be used on the same
|
|
rule as they provide the same stateful function.</para>
|
|
</sect4>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Stateful Rule Option</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFW</primary>
|
|
|
|
<secondary>stateful filtering</secondary>
|
|
</indexterm>
|
|
|
|
<para>The <literal>check-state</literal> option is used to
|
|
identify where in the IPFW ruleset the packet is to be
|
|
tested against the dynamic rules facility. On a match, the
|
|
packet exits the firewall to continue on its way and a new
|
|
rule is dynamically created for the next anticipated packet
|
|
being exchanged during this session. On a no match, the
|
|
packet advances to the next rule in the ruleset for
|
|
testing.</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 <acronym>IPFW</acronym>, use <literal>limit</literal>.
|
|
This keyword limits the number of simultaneous sessions by
|
|
checking that rule's source or destinations fields and using
|
|
the packet's IP address in a search of the open dynamic
|
|
rules, counting the number of times this rule and IP address
|
|
combination occurred. If this count is greater than the
|
|
value specified by <literal>limit</literal>, the packet is
|
|
discarded.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Logging Firewall Messages</title>
|
|
|
|
<indexterm>
|
|
<primary>IPFW</primary>
|
|
|
|
<secondary>logging</secondary>
|
|
</indexterm>
|
|
|
|
<para>Even with the logging facility enabled, IPFW 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 id="firewalls-ipfw-rules-script">
|
|
<title>Building a Rule Script</title>
|
|
|
|
<para>Most experienced IPFW 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
|
|
($). Symbolic fields do not have the $
|
|
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
|
|
$cmd 00500 check-state
|
|
$cmd 00502 deny all from any to any frag
|
|
$cmd 00501 deny tcp from any to any established
|
|
$cmd 00600 allow tcp from any to any 80 out via $oif setup $ks
|
|
$cmd 00610 allow tcp from any to $odns 53 out via $oif setup $ks
|
|
$cmd 00611 allow udp from any to $odns 53 out via $oif $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>
|
|
|
|
<sect3>
|
|
<title>An Example Stateful Ruleset</title>
|
|
|
|
<para>The following sample ruleset is a complete inclusive
|
|
type ruleset. Comment out any
|
|
<literal>pass</literal> rules for services that are not
|
|
required. To avoid logging undesired messages, add a
|
|
<literal>deny</literal> rule in the inbound section.
|
|
Change the <devicename>dc0</devicename> in every rule to the
|
|
device name of the interface that connects the system to the
|
|
Internet.</para>
|
|
|
|
<para>There is a noticeable pattern in the usage of these
|
|
rules.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>All statements that are a request to start a session
|
|
to the Internet use
|
|
<literal>keep-state</literal>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>All the authorized services that originate from
|
|
the Internet use <literal>limit</literal> to prevent
|
|
flooding.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>All rules use <literal>in</literal> or
|
|
<literal>out</literal> to clarify direction.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>All rules use <literal>via</literal>
|
|
<replaceable>interface-name</replaceable> to specify
|
|
the interface the packet is traveling over.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>The following rules go into
|
|
<filename>/etc/ipfw.rules</filename>:</para>
|
|
|
|
<programlisting>################ Start of IPFW rules file ###############################
|
|
# Flush out the list before we begin.
|
|
ipfw -q -f flush
|
|
|
|
# Set rules command prefix
|
|
cmd="ipfw -q add"
|
|
pif="dc0" # public interface name of NIC
|
|
# facing the public Internet
|
|
|
|
#################################################################
|
|
# No restrictions on Inside LAN Interface for private network
|
|
# Not needed unless you have LAN.
|
|
# Change xl0 to your LAN NIC interface name
|
|
#################################################################
|
|
#$cmd 00005 allow all from any to any via xl0
|
|
|
|
#################################################################
|
|
# No restrictions on Loopback Interface
|
|
#################################################################
|
|
$cmd 00010 allow all from any to any via lo0
|
|
|
|
#################################################################
|
|
# Allow the packet through if it has previous been added to the
|
|
# the "dynamic" rules table by a allow keep-state statement.
|
|
#################################################################
|
|
$cmd 00015 check-state
|
|
|
|
#################################################################
|
|
# Interface facing Public Internet (Outbound Section)
|
|
# Interrogate session start requests originating from behind the
|
|
# firewall on the private network or from this gateway server
|
|
# destined for the public Internet.
|
|
#################################################################
|
|
|
|
# Allow out access to my ISP's Domain name server.
|
|
# x.x.x.x must be the IP address of your ISP.s DNS
|
|
# Dup these lines if your ISP has more than one DNS server
|
|
# Get the IP addresses from /etc/resolv.conf file
|
|
$cmd 00110 allow tcp from any to x.x.x.x 53 out via $pif setup keep-state
|
|
$cmd 00111 allow udp from any to x.x.x.x 53 out via $pif keep-state
|
|
|
|
# Allow out access to my ISP's DHCP server for cable/DSL configurations.
|
|
# This rule is not needed for .user ppp. connection to the public Internet.
|
|
# so you can delete this whole group.
|
|
# Use the following rule and check log for IP address.
|
|
# Then put IP address in commented out rule & delete first rule
|
|
$cmd 00120 allow log udp from any to any 67 out via $pif keep-state
|
|
#$cmd 00120 allow udp from any to x.x.x.x 67 out via $pif keep-state
|
|
|
|
# Allow out non-secure standard www function
|
|
$cmd 00200 allow tcp from any to any 80 out via $pif setup keep-state
|
|
|
|
# Allow out secure www function https over TLS SSL
|
|
$cmd 00220 allow tcp from any to any 443 out via $pif setup keep-state
|
|
|
|
# Allow out send & get email function
|
|
$cmd 00230 allow tcp from any to any 25 out via $pif setup keep-state
|
|
$cmd 00231 allow tcp from any to any 110 out via $pif setup keep-state
|
|
|
|
# Allow out FBSD (make install & CVSUP) functions
|
|
# Basically give user root "GOD" privileges.
|
|
$cmd 00240 allow tcp from me to any out via $pif setup keep-state uid root
|
|
|
|
# Allow out ping
|
|
$cmd 00250 allow icmp from any to any out via $pif keep-state
|
|
|
|
# Allow out Time
|
|
$cmd 00260 allow tcp from any to any 37 out via $pif setup keep-state
|
|
|
|
# Allow out nntp news (i.e., news groups)
|
|
$cmd 00270 allow tcp from any to any 119 out via $pif setup keep-state
|
|
|
|
# Allow out secure FTP, Telnet, and SCP
|
|
# This function is using SSH (secure shell)
|
|
$cmd 00280 allow tcp from any to any 22 out via $pif setup keep-state
|
|
|
|
# Allow out whois
|
|
$cmd 00290 allow tcp from any to any 43 out via $pif setup keep-state
|
|
|
|
# deny and log everything else that.s trying to get out.
|
|
# This rule enforces the block all by default logic.
|
|
$cmd 00299 deny log all from any to any out via $pif
|
|
|
|
#################################################################
|
|
# Interface facing Public Internet (Inbound Section)
|
|
# Check packets originating from the public Internet
|
|
# destined for this gateway server or the private network.
|
|
#################################################################
|
|
|
|
# Deny all inbound traffic from non-routable reserved address spaces
|
|
$cmd 00300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
|
|
$cmd 00301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
|
|
$cmd 00302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
|
|
$cmd 00303 deny all from 127.0.0.0/8 to any in via $pif #loopback
|
|
$cmd 00304 deny all from 0.0.0.0/8 to any in via $pif #loopback
|
|
$cmd 00305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
|
|
$cmd 00306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs
|
|
$cmd 00307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster interconnect
|
|
$cmd 00308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
|
|
|
|
# Deny public pings
|
|
$cmd 00310 deny icmp from any to any in via $pif
|
|
|
|
# Deny ident
|
|
$cmd 00315 deny tcp from any to any 113 in via $pif
|
|
|
|
# Deny all Netbios service. 137=name, 138=datagram, 139=session
|
|
# Netbios is MS/Windows sharing services.
|
|
# Block MS/Windows hosts2 name server requests 81
|
|
$cmd 00320 deny tcp from any to any 137 in via $pif
|
|
$cmd 00321 deny tcp from any to any 138 in via $pif
|
|
$cmd 00322 deny tcp from any to any 139 in via $pif
|
|
$cmd 00323 deny tcp from any to any 81 in via $pif
|
|
|
|
# Deny any late arriving packets
|
|
$cmd 00330 deny all from any to any frag in via $pif
|
|
|
|
# Deny ACK packets that did not match the dynamic rule table
|
|
$cmd 00332 deny tcp from any to any established in via $pif
|
|
|
|
# Allow traffic in from ISP's DHCP server. This rule must contain
|
|
# the IP address of your ISP.s DHCP server as it.s the only
|
|
# authorized source to send this packet type.
|
|
# Only necessary for cable or DSL configurations.
|
|
# This rule is not needed for .user ppp. type connection to
|
|
# the public Internet. This is the same IP address you captured
|
|
# and used in the outbound section.
|
|
#$cmd 00360 allow udp from any to x.x.x.x 67 in via $pif keep-state
|
|
|
|
# Allow in standard www function because I have apache server
|
|
$cmd 00400 allow tcp from any to me 80 in via $pif setup limit src-addr 2
|
|
|
|
# Allow in secure FTP, Telnet, and SCP from public Internet
|
|
$cmd 00410 allow tcp from any to me 22 in via $pif setup limit src-addr 2
|
|
|
|
# Allow in non-secure Telnet session from public Internet
|
|
# labeled non-secure because ID & PW are passed over public
|
|
# Internet as clear text.
|
|
# Delete this sample group if you do not have telnet server enabled.
|
|
$cmd 00420 allow tcp from any to me 23 in via $pif setup limit src-addr 2
|
|
|
|
# Reject & Log all incoming connections from the outside
|
|
$cmd 00499 deny log all from any to any in via $pif
|
|
|
|
# Everything else is denied by default
|
|
# deny and log all packets that fell through to see what they are
|
|
$cmd 00999 deny log all from any to any
|
|
################ End of IPFW rules file ###############################</programlisting>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>An Example <acronym>NAT</acronym> and Stateful
|
|
Ruleset</title>
|
|
|
|
<indexterm>
|
|
<primary>NAT</primary>
|
|
|
|
<secondary>and IPFW</secondary>
|
|
</indexterm>
|
|
|
|
<para>There are some additional configuration statements that
|
|
need to be enabled to activate the <acronym>NAT</acronym>
|
|
function of IPFW. For a customized kernel, the kernel
|
|
configuration file needs
|
|
<literal>option IPDIVERT</literal> added to the other
|
|
<literal>IPFIREWALL</literal> options.</para>
|
|
|
|
<para>In addition to the normal IPFW options in
|
|
<filename>/etc/rc.conf</filename>, the following are
|
|
needed:</para>
|
|
|
|
<programlisting>natd_enable="YES" # Enable <acronym>NAT</acronym>D function
|
|
natd_interface="rl0" # interface name of public Internet NIC
|
|
natd_flags="-dynamic -m" # -m = preserve port numbers if possible</programlisting>
|
|
|
|
<para>Utilizing stateful rules with a
|
|
<literal>divert natd</literal> rule complicates the ruleset
|
|
logic. The positioning of the
|
|
<literal>check-state</literal>, and
|
|
<literal>divert natd</literal> rules in the ruleset is
|
|
critical and a new action type is used, called
|
|
<literal>skipto</literal>. When using
|
|
<literal>skipto</literal>, it is mandatory that each rule is
|
|
numbered, so that the <literal>skipto</literal> rule knows
|
|
which rule to jump to.</para>
|
|
|
|
<para>The following is an uncommented example of a ruleset
|
|
which explains the sequence of the packet flow.</para>
|
|
|
|
<para>The processing flow starts with the first rule from the
|
|
top of the ruleset and progresses one rule at a time until
|
|
the end is reached or the packet matches and the packet is
|
|
released out of the firewall. Take note of the location of
|
|
rule numbers 100 101, 450, 500, and 510. These rules
|
|
control the translation of the outbound and inbound packets
|
|
so that their entries in the dynamic keep-state table always
|
|
register the private LAN IP address. All the allow and deny
|
|
rules specify the direction of the packet and the interface.
|
|
All start outbound session requests will
|
|
<literal>skipto rule 500</literal> to undergo NAT.</para>
|
|
|
|
<para>Consider a web browser which initializes a new HTTP
|
|
session over port 80. When the first outbound packet enters
|
|
the firewall, it does not match rule 100 because it is
|
|
headed out rather than in. It passes rule 101 because this
|
|
is the first packet, and it has not been posted to the
|
|
dynamic keep-state table yet. The packet finally matches
|
|
rule 125 as it is outbound through the NIC facing the
|
|
Internet and has a source IP address as a private LAN IP
|
|
address. On matching this rule, two actions take place.
|
|
<literal>keep-state</literal> adds this rule to the dynamic
|
|
keep-state rules table and the specified action is executed
|
|
and posted as part of the info in the dynamic table. In
|
|
this case, the action is <literal>skipto rule 500</literal>.
|
|
Rule 500 <acronym>NAT</acronym>s the packet IP address and
|
|
sends it 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 100 and has it destination IP
|
|
address mapped back to the corresponding LAN IP 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 LAN. It goes to the LAN system that sent it
|
|
and a new packet is sent requesting another segment of the
|
|
data from the remote server. This time it matches the
|
|
<literal>check-state</literal> rule, its outbound entry is
|
|
found, and the associated action,
|
|
<literal>skipto 500</literal>, is executed. The packet
|
|
jumps to rule 500, gets <acronym>NAT</acronym>ed, and is
|
|
released to the Internet.</para>
|
|
|
|
<para>On the inbound side, everything coming in that is part
|
|
of an existing session is automatically handled by the
|
|
<literal>check-state</literal> rule and the properly placed
|
|
<literal>divert natd</literal> rules. The ruleset only has
|
|
to deny bad packets and allow only authorized services.
|
|
Consider a web server running on the firewall where web
|
|
requests from the Internet should have access to the local
|
|
web site. An inbound start request packet will match rule
|
|
100 and its IP address will be mapped to the LAN IP address
|
|
of the firewall. The packet is then matched against all the
|
|
nasty things that need to be checked and finally matches
|
|
rule 425 where two actions occur. The packet rule is posted
|
|
to the dynamic keep-state table but this time, any new
|
|
session requests originating from that source IP address are
|
|
limited to 2. This defends against DoS attacks against the
|
|
service running on the specified port number. The action is
|
|
<literal>allow</literal>, so the packet is released to the
|
|
LAN. The packet generated as a response is recognized by the
|
|
<literal>check-state</literal> as belonging to an existing
|
|
session. It is then sent to rule 500 for
|
|
<acronym>NAT</acronym>ing and released to the outbound
|
|
interface.</para>
|
|
|
|
<para>Example Ruleset #1:</para>
|
|
|
|
<programlisting>#!/bin/sh
|
|
cmd="ipfw -q add"
|
|
skip="skipto 500"
|
|
pif=rl0
|
|
ks="keep-state"
|
|
good_tcpo="22,25,37,43,53,80,443,110,119"
|
|
|
|
ipfw -q -f flush
|
|
|
|
$cmd 002 allow all from any to any via xl0 # exclude LAN traffic
|
|
$cmd 003 allow all from any to any via lo0 # exclude loopback traffic
|
|
|
|
$cmd 100 divert natd ip from any to any in via $pif
|
|
$cmd 101 check-state
|
|
|
|
# Authorized outbound packets
|
|
$cmd 120 $skip udp from any to xx.168.240.2 53 out via $pif $ks
|
|
$cmd 121 $skip udp from any to xx.168.240.5 53 out via $pif $ks
|
|
$cmd 125 $skip tcp from any to any $good_tcpo out via $pif setup $ks
|
|
$cmd 130 $skip icmp from any to any out via $pif $ks
|
|
$cmd 135 $skip udp from any to any 123 out via $pif $ks
|
|
|
|
|
|
# Deny all inbound traffic from non-routable reserved address spaces
|
|
$cmd 300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
|
|
$cmd 301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
|
|
$cmd 302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
|
|
$cmd 303 deny all from 127.0.0.0/8 to any in via $pif #loopback
|
|
$cmd 304 deny all from 0.0.0.0/8 to any in via $pif #loopback
|
|
$cmd 305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
|
|
$cmd 306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs
|
|
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster
|
|
$cmd 308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
|
|
|
|
# Authorized inbound packets
|
|
$cmd 400 allow udp from xx.70.207.54 to any 68 in $ks
|
|
$cmd 420 allow tcp from any to me 80 in via $pif setup limit src-addr 1
|
|
|
|
|
|
$cmd 450 deny log ip from any to any
|
|
|
|
# This is skipto location for outbound stateful rules
|
|
$cmd 500 divert natd ip from any to any out via $pif
|
|
$cmd 510 allow ip from any to any
|
|
|
|
######################## end of rules ##################</programlisting>
|
|
|
|
<para>The next example is functionally equivalent, but uses
|
|
descriptive comments to help the inexperienced IPFW rule
|
|
writer to better understand what the rules are doing.</para>
|
|
|
|
<para>Example Ruleset #2:</para>
|
|
|
|
<programlisting>#!/bin/sh
|
|
################ Start of IPFW rules file ###############################
|
|
# Flush out the list before we begin.
|
|
ipfw -q -f flush
|
|
|
|
# Set rules command prefix
|
|
cmd="ipfw -q add"
|
|
skip="skipto 800"
|
|
pif="rl0" # public interface name of NIC
|
|
# facing the public Internet
|
|
|
|
#################################################################
|
|
# No restrictions on Inside LAN Interface for private network
|
|
# Change xl0 to your LAN NIC interface name
|
|
#################################################################
|
|
$cmd 005 allow all from any to any via xl0
|
|
|
|
#################################################################
|
|
# No restrictions on Loopback Interface
|
|
#################################################################
|
|
$cmd 010 allow all from any to any via lo0
|
|
|
|
#################################################################
|
|
# check if packet is inbound and nat address if it is
|
|
#################################################################
|
|
$cmd 014 divert natd ip from any to any in via $pif
|
|
|
|
#################################################################
|
|
# Allow the packet through if it has previous been added to the
|
|
# the "dynamic" rules table by a allow keep-state statement.
|
|
#################################################################
|
|
$cmd 015 check-state
|
|
|
|
#################################################################
|
|
# Interface facing Public Internet (Outbound Section)
|
|
# Check session start requests originating from behind the
|
|
# firewall on the private network or from this gateway server
|
|
# destined for the public Internet.
|
|
#################################################################
|
|
|
|
# Allow out access to my ISP's Domain name server.
|
|
# x.x.x.x must be the IP address of your ISP's DNS
|
|
# Dup these lines if your ISP has more than one DNS server
|
|
# Get the IP addresses from /etc/resolv.conf file
|
|
$cmd 020 $skip tcp from any to x.x.x.x 53 out via $pif setup keep-state
|
|
|
|
|
|
# Allow out access to my ISP's DHCP server for cable/DSL configurations.
|
|
$cmd 030 $skip udp from any to x.x.x.x 67 out via $pif keep-state
|
|
|
|
# Allow out non-secure standard www function
|
|
$cmd 040 $skip tcp from any to any 80 out via $pif setup keep-state
|
|
|
|
# Allow out secure www function https over TLS SSL
|
|
$cmd 050 $skip tcp from any to any 443 out via $pif setup keep-state
|
|
|
|
# Allow out send & get email function
|
|
$cmd 060 $skip tcp from any to any 25 out via $pif setup keep-state
|
|
$cmd 061 $skip tcp from any to any 110 out via $pif setup keep-state
|
|
|
|
# Allow out FreeBSD (make install & CVSUP) functions
|
|
# Basically give user root "GOD" privileges.
|
|
$cmd 070 $skip tcp from me to any out via $pif setup keep-state uid root
|
|
|
|
# Allow out ping
|
|
$cmd 080 $skip icmp from any to any out via $pif keep-state
|
|
|
|
# Allow out Time
|
|
$cmd 090 $skip tcp from any to any 37 out via $pif setup keep-state
|
|
|
|
# Allow out nntp news (i.e., news groups)
|
|
$cmd 100 $skip tcp from any to any 119 out via $pif setup keep-state
|
|
|
|
# Allow out secure FTP, Telnet, and SCP
|
|
# This function is using SSH (secure shell)
|
|
$cmd 110 $skip tcp from any to any 22 out via $pif setup keep-state
|
|
|
|
# Allow out whois
|
|
$cmd 120 $skip tcp from any to any 43 out via $pif setup keep-state
|
|
|
|
# Allow ntp time server
|
|
$cmd 130 $skip udp from any to any 123 out via $pif keep-state
|
|
|
|
#################################################################
|
|
# Interface facing Public Internet (Inbound Section)
|
|
# Check packets originating from the public Internet
|
|
# destined for this gateway server or the private network.
|
|
#################################################################
|
|
|
|
# Deny all inbound traffic from non-routable reserved address spaces
|
|
$cmd 300 deny all from 192.168.0.0/16 to any in via $pif #RFC 1918 private IP
|
|
$cmd 301 deny all from 172.16.0.0/12 to any in via $pif #RFC 1918 private IP
|
|
$cmd 302 deny all from 10.0.0.0/8 to any in via $pif #RFC 1918 private IP
|
|
$cmd 303 deny all from 127.0.0.0/8 to any in via $pif #loopback
|
|
$cmd 304 deny all from 0.0.0.0/8 to any in via $pif #loopback
|
|
$cmd 305 deny all from 169.254.0.0/16 to any in via $pif #DHCP auto-config
|
|
$cmd 306 deny all from 192.0.2.0/24 to any in via $pif #reserved for docs
|
|
$cmd 307 deny all from 204.152.64.0/23 to any in via $pif #Sun cluster
|
|
$cmd 308 deny all from 224.0.0.0/3 to any in via $pif #Class D & E multicast
|
|
|
|
# Deny ident
|
|
$cmd 315 deny tcp from any to any 113 in via $pif
|
|
|
|
# Deny all Netbios service. 137=name, 138=datagram, 139=session
|
|
# Netbios is MS/Windows sharing services.
|
|
# Block MS/Windows hosts2 name server requests 81
|
|
$cmd 320 deny tcp from any to any 137 in via $pif
|
|
$cmd 321 deny tcp from any to any 138 in via $pif
|
|
$cmd 322 deny tcp from any to any 139 in via $pif
|
|
$cmd 323 deny tcp from any to any 81 in via $pif
|
|
|
|
# Deny any late arriving packets
|
|
$cmd 330 deny all from any to any frag in via $pif
|
|
|
|
# Deny ACK packets that did not match the dynamic rule table
|
|
$cmd 332 deny tcp from any to any established in via $pif
|
|
|
|
# Allow traffic in from ISP's DHCP server. This rule must contain
|
|
# the IP address of your ISP's DHCP server as it is the only
|
|
# authorized source to send this packet type.
|
|
# Only necessary for cable or DSL configurations.
|
|
# This rule is not needed for 'user ppp' type connection to
|
|
# the public Internet. This is the same IP address you captured
|
|
# and used in the outbound section.
|
|
$cmd 360 allow udp from x.x.x.x to any 68 in via $pif keep-state
|
|
|
|
# Allow in standard www function because I have Apache server
|
|
$cmd 370 allow tcp from any to me 80 in via $pif setup limit src-addr 2
|
|
|
|
# Allow in secure FTP, Telnet, and SCP from public Internet
|
|
$cmd 380 allow tcp from any to me 22 in via $pif setup limit src-addr 2
|
|
|
|
# Allow in non-secure Telnet session from public Internet
|
|
# labeled non-secure because ID & PW are passed over public
|
|
# Internet as clear text.
|
|
# Delete this sample group if you do not have telnet server enabled.
|
|
$cmd 390 allow tcp from any to me 23 in via $pif setup limit src-addr 2
|
|
|
|
# Reject & Log all unauthorized incoming connections from the public Internet
|
|
$cmd 400 deny log all from any to any in via $pif
|
|
|
|
# Reject & Log all unauthorized out going connections to the public Internet
|
|
$cmd 450 deny log all from any to any out via $pif
|
|
|
|
# This is skipto location for outbound stateful rules
|
|
$cmd 800 divert natd ip from any to any out via $pif
|
|
$cmd 801 allow ip from any to any
|
|
|
|
# Everything else is denied by default
|
|
# deny and log all packets that fell through to see what they are
|
|
$cmd 999 deny log all from any to any
|
|
################ End of IPFW rules file ###############################</programlisting>
|
|
</sect3>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|