Tighten up this subsection.

Sponsored by: iXsystems
This commit is contained in:
Dru Lavigne 2014-02-14 20:37:25 +00:00
parent c4a79914aa
commit 68e4a86d99
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=43928

View file

@ -540,104 +540,87 @@ options ALTQ_PRIQ # Priority Queuing (PRIQ)</programlisting>
</info>
<para>This section demonstrates how to create a customized
ruleset, using several examples.</para>
ruleset. It starts with the simplest of rulesets and builds
upon its concepts using several examples to demonstrate
real-world usage of <application>PF</application>'s many
features.</para>
<para>The simplest possible 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>
<para>The simplest possible ruleset is for a single machine
that does not run any services and which needs access to one
network, which may be the Internet. To create this minimal
ruleset, edit
<filename>/etc/pf.conf</filename> so it looks like this:</para>
<programlisting>block in all
pass out all keep state</programlisting>
<para>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>
<para>The first rule denies all incoming traffic by default.
The second rule allows
connections created by this system
to pass out, while retaining state information on those
connections. This state information allows return
traffic for those connections to pass back and
should only be used on machines that can be
trusted. The ruleset can be loaded with:</para>
<screen>&prompt.root; <userinput>pfctl -e ; pfctl -f /etc/pf.conf</userinput></screen>
<para>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, <link
xlink:href="http://www.ranum.com/security/computer_security/editorials/dumb/index.html">The
Six Dumbest Ideas in Computer Security</link>, and
it is well written too.</para></footnote>. This gives
us the opportunity to introduce two of the features which
make <application>PF</application> such a wonderful tool:
<para>In addition to keeping state,
<application>PF</application> provides
<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>
<firstterm>macros</firstterm> which can be defined for use
when creating rules. Macros can include lists and need to be defined
before use. As an example, insert these lines at the
very top of the ruleset:</para>
<programlisting>tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
udp_services = "{ domain }"</programlisting>
<para>Now we have demonstrated several things at once - what
macros look like, that macros may be lists, and that
<application>PF</application> 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>
<para><application>PF</application> understands port
names as well as port numbers, as long as the names are listed
in <filename>/etc/services</filename>. This example
creates two macros. The first is a list of seven
<acronym>TCP</acronym> port names and the second is one
<acronym>UDP</acronym> port name. Once defined, macros can
be used in rules. In this example, all traffic is blocked
except for the connections initiated by this system for the
seven specified <acronym>TCP</acronym> services and the one
specified <acronym>UDP</acronym> service:</para>
<programlisting>block all
<programlisting>tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
udp_services = "{ domain }"
block all
pass out proto tcp to any port $tcp_services keep state
pass proto udp to any port $udp_services keep state</programlisting>
<para>At this point some of us will point out that UDP is
stateless, but <application>PF</application> 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>Even though <acronym>UDP</acronym> is considered to be
a stateless protocol, <application>PF</application>
is able to track some state information. For example, when a
<acronym>UDP</acronym> request is passed which
asks a name server about a domain name, <application>PF</application>
will watch for the response in order to pass it back.</para>
<para>Since we have made changes to our
<filename>pf.conf</filename>, we load the new
rules:</para>
<para>Whenever an edit is made to a ruleset, the new rules
must be loaded so they can be used:</para>
<screen>&prompt.root; <userinput>pfctl -f /etc/pf.conf</userinput></screen>
<para>and the new rules are applied. If there are no syntax
<para>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>
messages during the rule load. Rules can also be tested before attempting to load them:</para>
<screen>&prompt.root; <userinput>pfctl -nf /etc/pf.conf</userinput></screen>
<para><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
<application>PF</application> is disabled or a new rule set
<para>Including <option>-n</option> causes the rules to be interpreted
only, but not loaded. This provides an opportunity
to correct any errors. At all times, the last
valid ruleset loaded will be enforced until either
<application>PF</application> is disabled or a new ruleset
is loaded.</para>
<tip>
<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
<para>Adding <option>-v</option> to a
<command>pfctl</command> ruleset verify or load will display the fully parsed rules
exactly the way they will be loaded. This is extremely
useful when debugging rules.</para>
</tip>
@ -699,10 +682,10 @@ pass proto udp to any port $udp_services keep state</programlisting>
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>
clutter than they are worth to rulesets.</para>
<para>For a busy network admin, a readable rule set is a
safer rule set.</para>
<para>For a busy network admin, a readable ruleset is a
safer ruleset.</para>
<para>For the remainder of this section, with some
exceptions, we will keep the rules as simple as possible
@ -713,7 +696,7 @@ pass proto udp to any port $udp_services keep state</programlisting>
<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
nice piece of shorthand, but the ruleset can be made even
more readable and maintainable by taking the macro use a
tiny bit further.</para>
@ -809,7 +792,7 @@ pass from { lo0, $localnet } to any keep state</programlisting>
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
but once the rulesets grow somewhat larger, you will
learn to appreciate the readability this provides.</para>
<para>Also note the <literal>nat</literal> rule. This is
@ -825,7 +808,7 @@ pass from { lo0, $localnet } to any keep state</programlisting>
interruptions even if the external IP address
changes.</para>
<para>On the other hand, this rule set probably allows more
<para>On the other hand, this ruleset probably allows more
traffic to pass out of the network than actually desired.
One reasonable setup could contain the macro</para>
@ -866,9 +849,9 @@ pass from { lo0, $localnet } to any keep state</programlisting>
<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
rule. We have started writing rulesets 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
relationships between the rules in a ruleset. 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 <application>PF</application>,
@ -1083,7 +1066,7 @@ rdr-anchor "ftp-proxy/*"</programlisting>
<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,
these rulesets have been around for roughly fifteen years,
and the people who put them there are still scared.</para>
<sect4 xml:id="pftut-dowepass">
@ -1128,7 +1111,7 @@ pass inet proto icmp from any to $ext_if keep state</programlisting>
<sect4 xml:id="pftut-letpingthru">
<title>Letting <command>ping</command> Through</title>
<para>The rule set we have developed so far has one clear
<para>The ruleset 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
@ -1138,9 +1121,9 @@ pass inet proto icmp from any to $ext_if keep state</programlisting>
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;
additions to the ruleset, 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>
ruleset tidy, we start by defining another macro:</para>
<programlisting>icmp_types = "echoreq"</programlisting>
@ -1261,7 +1244,7 @@ pass out on $ext_if inet proto udp from any to any port 33433 &gt;&lt; 33626 kee
Quite right, and <application>PF</application> 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,
manipulated without needing to reload the entire ruleset,
and where fast lookups are desirable. Table names are
always enclosed in <literal>&lt; &gt;</literal>, like
this:</para>
@ -1361,7 +1344,7 @@ Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user admin from
<programlisting>table &lt;bruteforce&gt; persist</programlisting>
<para>Then somewhere fairly early in the rule set, add a rule
<para>Then somewhere fairly early in the ruleset, add a rule
to block the bruteforcers:</para>
<programlisting>block quick from &lt;bruteforce&gt;</programlisting>
@ -1598,7 +1581,7 @@ Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user admin from
</step>
<step>
<para>Next, edit the rule set to include</para>
<para>Next, edit the ruleset to include</para>
<programlisting>table &lt;spamd&gt; persist
table &lt;spamd-white&gt; persist
@ -1698,7 +1681,7 @@ rdr pass on $ext_if inet proto tcp from !&lt;spamd-white&gt; to \
<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
reload the ruleset, start
<application>spamd</application> with the options
desired using the
<filename>/usr/local/etc/rc.d/obspamd</filename>