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> </info>
<para>This section demonstrates how to create a customized <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 <para>The simplest possible ruleset is for a single machine
which will not run any services, and which will talk to one that does not run any services and which needs access to one
network which may be the Internet. A minimal network, which may be the Internet. To create this minimal
<filename>/etc/pf.conf</filename> looks like this:</para> ruleset, edit
<filename>/etc/pf.conf</filename> so it looks like this:</para>
<programlisting>block in all <programlisting>block in all
pass out all keep state</programlisting> pass out all keep state</programlisting>
<para>Here we deny any incoming traffic, allow traffic we make <para>The first rule denies all incoming traffic by default.
ourselves to pass, and retain state information on our The second rule allows
connections. Keeping state information allows return connections created by this system
traffic for all connections we have initiated to pass back to pass out, while retaining state information on those
to us. This rule set is used on machines that can be connections. This state information allows return
trusted. The rule set can be loaded with</para> 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> <screen>&prompt.root; <userinput>pfctl -e ; pfctl -f /etc/pf.conf</userinput></screen>
<para>For a slightly more structured and complete setup, we <para>In addition to keeping state,
start by denying everything and then allowing only those <application>PF</application> provides
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:
<firstterm>lists</firstterm> and <firstterm>lists</firstterm> and
<firstterm>macros</firstterm>.</para> <firstterm>macros</firstterm> which can be defined for use
when creating rules. Macros can include lists and need to be defined
<para>We will make some changes to before use. As an example, insert these lines at the
<filename>/etc/pf.conf</filename>, starting with</para> very top of the ruleset:</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 }" <programlisting>tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
udp_services = "{ domain }"</programlisting> udp_services = "{ domain }"</programlisting>
<para>Now we have demonstrated several things at once - what <para><application>PF</application> understands port
macros look like, that macros may be lists, and that names as well as port numbers, as long as the names are listed
<application>PF</application> understands rules using port in <filename>/etc/services</filename>. This example
names equally well as it does port numbers. The names are creates two macros. The first is a list of seven
the ones listed in <filename>/etc/services</filename>. This <acronym>TCP</acronym> port names and the second is one
gives us something to put in our rules, which we edit <acronym>UDP</acronym> port name. Once defined, macros can
slightly to look like this:</para> 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 out proto tcp to any port $tcp_services keep state
pass proto udp to any port $udp_services keep state</programlisting> pass proto udp to any port $udp_services keep state</programlisting>
<para>At this point some of us will point out that UDP is <para>Even though <acronym>UDP</acronym> is considered to be
stateless, but <application>PF</application> actually a stateless protocol, <application>PF</application>
manages to maintain state information despite this. Keeping is able to track some state information. For example, when a
state for a UDP connection means that for example when you <acronym>UDP</acronym> request is passed which
ask a name server about a domain name, you will be able to asks a name server about a domain name, <application>PF</application>
receive its answer.</para> will watch for the response in order to pass it back.</para>
<para>Since we have made changes to our <para>Whenever an edit is made to a ruleset, the new rules
<filename>pf.conf</filename>, we load the new must be loaded so they can be used:</para>
rules:</para>
<screen>&prompt.root; <userinput>pfctl -f /etc/pf.conf</userinput></screen> <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 errors, <command>pfctl</command> will not output any
messages during the rule load. The <option>-v</option> flag messages during the rule load. Rules can also be tested before attempting to load them:</para>
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> <screen>&prompt.root; <userinput>pfctl -nf /etc/pf.conf</userinput></screen>
<para><option>-n</option> causes the rules to be interpreted <para>Including <option>-n</option> causes the rules to be interpreted
only, but does not load them. This provides an opportunity only, but not loaded. This provides an opportunity
to correct any errors. Under any circumstances, the last to correct any errors. At all times, the last
valid rule set loaded will be in force until valid ruleset loaded will be enforced until either
<application>PF</application> is disabled or a new rule set <application>PF</application> is disabled or a new ruleset
is loaded.</para> is loaded.</para>
<tip> <tip>
<title>Use <command>pfctl -v</command> to Show the Parsed <para>Adding <option>-v</option> to a
Rule Set</title> <command>pfctl</command> ruleset verify or load will display the fully parsed rules
<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 exactly the way they will be loaded. This is extremely
useful when debugging rules.</para> useful when debugging rules.</para>
</tip> </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 good these days, and we will get back to them later. For
now we just accept the fact that for simple setups, now we just accept the fact that for simple setups,
interface-bound rules with in/out rules tend to add more 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 <para>For a busy network admin, a readable ruleset is a
safer rule set.</para> safer ruleset.</para>
<para>For the remainder of this section, with some <para>For the remainder of this section, with some
exceptions, we will keep the rules as simple as possible 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 <para>Above, we introduced the
<literal>interface:network</literal> notation. That is a <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 more readable and maintainable by taking the macro use a
tiny bit further.</para> 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 the last time during this tutorial we will find this of
any interest whatsoever. In truly simple setups like this any interest whatsoever. In truly simple setups like this
one, we may not gain very much by using macros like these, 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> learn to appreciate the readability this provides.</para>
<para>Also note the <literal>nat</literal> rule. This is <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 interruptions even if the external IP address
changes.</para> 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. traffic to pass out of the network than actually desired.
One reasonable setup could contain the macro</para> 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> <programlisting>pass quick inet proto { tcp, udp } to any port $udp_services keep state</programlisting>
<para>Note the <literal>quick</literal> keyword in this <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 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 are evaluated from top to bottom, in the sequence they are
written in the configuration file. For each packet or written in the configuration file. For each packet or
connection evaluated by <application>PF</application>, 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 <para>One of the early workarounds was to simply block either
all <acronym>ICMP</acronym> traffic or at least all <acronym>ICMP</acronym> traffic or at least
<acronym>ICMP</acronym> ECHO, which is what ping uses. Now <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> and the people who put them there are still scared.</para>
<sect4 xml:id="pftut-dowepass"> <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"> <sect4 xml:id="pftut-letpingthru">
<title>Letting <command>ping</command> Through</title> <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 disadvantage: common troubleshooting commands such as
&man.ping.8; and &man.traceroute.8; will not work. That &man.ping.8; and &man.traceroute.8; will not work. That
may not matter too much to end users, and since it was 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 we are better off without it. If you are in my perceived
target audience, you will be rather fond of having those target audience, you will be rather fond of having those
troubleshooting tools avalable. With a couple of small 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 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> <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 Quite right, and <application>PF</application> offers
mechanisms for handling these situations as well. Tables mechanisms for handling these situations as well. Tables
are one such feature, mainly useful as lists which can be 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 and where fast lookups are desirable. Table names are
always enclosed in <literal>&lt; &gt;</literal>, like always enclosed in <literal>&lt; &gt;</literal>, like
this:</para> 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> <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> to block the bruteforcers:</para>
<programlisting>block quick from &lt;bruteforce&gt;</programlisting> <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>
<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 <programlisting>table &lt;spamd&gt; persist
table &lt;spamd-white&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> <programlisting>spamd_flags="-v" # for normal use: "" and see spamd-setup(8)</programlisting>
<para>When done with editing the setup, <para>When done with editing the setup,
reload the rule set, start reload the ruleset, start
<application>spamd</application> with the options <application>spamd</application> with the options
desired using the desired using the
<filename>/usr/local/etc/rc.d/obspamd</filename> <filename>/usr/local/etc/rc.d/obspamd</filename>