377 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| <!--
 | |
|      The FreeBSD Documentation Project
 | |
| -->
 | |
| 
 | |
| <!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
 | |
| <!ENTITY % man PUBLIC "-//FreeBSD//ENTITIES DocBook Manual Page Entities//EN">
 | |
| %man;
 | |
| ]>
 | |
| 
 | |
| <article>
 | |
|   <articleinfo>
 | |
|     <title>Dialup firewalling with FreeBSD</title>
 | |
| 
 | |
|     <authorgroup>
 | |
|       <author>
 | |
| 	<firstname>Marc</firstname>
 | |
| 	<surname>Silver</surname>
 | |
| 
 | |
| 	<affiliation>
 | |
| 	  <address><email>marcs@draenor.org</email></address>
 | |
| 	</affiliation>
 | |
|       </author>
 | |
|     </authorgroup>
 | |
| 
 | |
|     <pubdate>$FreeBSD$</pubdate>
 | |
| 
 | |
|     <abstract>
 | |
|       <para>This article documents how to setup a firewall using a PPP
 | |
| 	dialup with FreeBSD and IPFW, and specifically with firewalling over
 | |
| 	a dialup with a dynamically assigned IP address.  This document does
 | |
| 	not cover setting up your PPP connection in the first place.</para>
 | |
|     </abstract>
 | |
|   </articleinfo>
 | |
| 
 | |
|   <sect1 id="preface">
 | |
|     <title>Preface</title>
 | |
|     
 | |
|     <para>Dialup Firewalling with FreeBSD</para>
 | |
| 
 | |
|      <para>This document covers the process that is required to setup
 | |
|        firewalling with FreeBSD when an IP address is assigned dynamically  
 | |
|        by your ISP.  While every effort has been made to make this document
 | |
|        as informative and correct as possible, you are welcome to mail your
 | |
|        comments/suggestions to the <email>marcs@draenor.org</email>.</para>    
 | |
|    </sect1>
 | |
| 
 | |
|   <sect1 id="kernel">
 | |
|     <title>Kernel Options</title>
 | |
|     
 | |
|     <para>The first thing you will need to do is recompile your kernel
 | |
|       If you need more information on how to recompile the kernel,
 | |
|       then the best place to start is the <ulink
 | |
| 	URL="../../books/handbook/kernelconfig.html">kernel
 | |
| 	configuration section in the Handbook</ulink>. You need to add the
 | |
|       following options into your kernel configuration file:</para>
 | |
| 
 | |
|     <variablelist>
 | |
|       <varlistentry>
 | |
| 	<term><literal>options IPFIREWALL</literal></term>
 | |
| 
 | |
| 	<listitem>
 | |
| 	  <para>Enables the kernel's firewall code.</para>
 | |
| 	</listitem>
 | |
|       </varlistentry>
 | |
| 
 | |
|       <varlistentry>
 | |
| 	<term><literal>options IPFIREWALL_VERBOSE</literal></term>
 | |
| 
 | |
| 	<listitem>
 | |
| 	  <para>Sends logged packets to the system logger.</para>
 | |
| 	</listitem>
 | |
|       </varlistentry>
 | |
| 
 | |
|       <varlistentry>
 | |
| 	<term><literal>options
 | |
| 	    IPFIREWALL_VERBOSE_LIMIT=<replaceable>100</replaceable></literal></term>
 | |
| 
 | |
| 	<listitem>
 | |
| 	  <para>Limits the number of times a matching entry is logged.  This
 | |
|             prevents your log file from filling up with lots of repetitive
 | |
| 	    entries.
 | |
| 	    <replaceable>100</replaceable> is a reasonable number to use, but
 | |
| 	    you can adjust it based on your requirements.</para>
 | |
| 	</listitem>
 | |
|       </varlistentry>
 | |
| 
 | |
|       <varlistentry>
 | |
| 	<term><literal>options IPDIVERT</literal></term>
 | |
| 
 | |
| 	<listitem>
 | |
| 	  <para>Enables <emphasis>divert</emphasis> sockets, which will be
 | |
| 	    shown later.</para>
 | |
| 	</listitem>
 | |
|       </varlistentry>
 | |
|     </variablelist>
 | |
| 
 | |
|     <para>There are some other <emphasis>optional</emphasis> items that you can compile
 | |
|      into the kernel for some added security.  These are not required in
 | |
|      order to get firewalling to work, but some more paranoid users may
 | |
|      want to use them.</para>
 | |
| 
 | |
|     <variablelist>
 | |
|       <varlistentry>
 | |
| 	<term><literal>options TCP_DROP_SYNFIN</literal></term>
 | |
| 
 | |
| 	<listitem>
 | |
| 	  <para>This option ignores TCP packets with SYN and FIN.  This
 | |
| 	   prevents tools such as nmap etc from identifying the TCP/IP
 | |
|  	   stack of the machine, but breaks support for RFC1644
 | |
| 	   extensions.  This is <emphasis>not</emphasis> recommended if the machine will be
 | |
| 	   running a web server.</para>
 | |
| 	</listitem>
 | |
|       </varlistentry>
 | |
|      </variablelist>
 | |
| 
 | |
|     <para>Do not reboot once you have recompiled the kernel. Hopefully, 
 | |
|       we will only need to reboot once to complete the installation of the
 | |
|       firewall.</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="rcconf">
 | |
|     <title>Changing <filename>/etc/rc.conf</filename> to load the
 | |
|       firewall</title>
 | |
|     
 | |
|     <para>We now need to make some changes to
 | |
|       <filename>/etc/rc.conf</filename> in order to tell it about the
 | |
|       firewall.  Simply add the following lines:</para>
 | |
|     
 | |
|     <programlisting>firewall_enable="YES"
 | |
| firewall_script="/etc/firewall/fwrules"
 | |
| natd_enable="YES"
 | |
| natd_interface="tun0"
 | |
| natd_flags="-dynamic"</programlisting>
 | |
| 
 | |
|     <para>For more information on the functions of these statements take 
 | |
|      a look at <filename>/etc/defaults/rc.conf</filename> and read
 | |
|       &man.rc.conf.5;</para>
 | |
|   </sect1>
 | |
|   
 | |
|   <sect1>
 | |
|     <title>Disable PPP's network address translation</title>
 | |
|     
 | |
|     <para>You may already be using PPP's built in network address
 | |
|       translation (NAT).  If that is the case then you will have to disable 
 | |
|       it, as these examples use &man.natd.8; to do the same.</para>
 | |
| 
 | |
|     <para>If you already have a block of entries to
 | |
|       automatically start PPP, it probably looks like this:</para>
 | |
| 
 | |
|     <programlisting>ppp_enable="YES"
 | |
| ppp_mode="auto"
 | |
| ppp_nat="YES"
 | |
| ppp_profile="<replaceable>profile</replaceable>"</programlisting>
 | |
| 
 | |
|     <para>If so, remove the <literal>ppp_nat="YES"</literal> line.  You will 
 | |
|       also need to remove any <literal>nat enable yes</literal> or
 | |
|       <literal>alias enable yes</literal> in
 | |
|       <filename>/etc/ppp/ppp.conf</filename>.</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="rules">
 | |
|     <title>The ruleset for the firewall</title>
 | |
|     
 | |
|     <para>We are nearly done now.  All that remains now is to define
 | |
|       the firewall rules and then we can reboot and the firewall
 | |
|       should be up and running.  I realize that everyone will want
 | |
|       something slightly different when it comes to their rulebase.
 | |
|       What I have tried to do is write a rulebase that suits most dialup
 | |
|       users.  You can obviously modify it to your needs by using the
 | |
|       following rules as the foundation for your own rulebase.  First,
 | |
|       let's start with the basics of closed firewalling.  What you
 | |
|       want to do is deny everything by default and then only open up
 | |
|       for the things you really need.  Rules should be in the order of
 | |
|       allow first and then deny.  The premise is that you add the
 | |
|       rules for your allows, and then everything else is
 | |
|       denied. :)</para>
 | |
| 
 | |
|     <para>Now, let's make the dir <filename
 | |
|       class="directory">/etc/firewall</filename>. Change into the
 | |
|       directory and edit the file <filename>fwrules</filename> as we
 | |
|       specified in <filename>rc.conf</filename>.  Please note that you
 | |
|       can change this filename to anything you wish.  This guide just
 | |
|       gives an example of a filename. </para>
 | |
| 
 | |
|     <para>Now, let's look at a sample firewall file, that is commented
 | |
|       nicely.</para>
 | |
| 
 | |
|     <programlisting># Firewall rules
 | |
| # Written by Marc Silver (marcs@draenor.org)
 | |
| # http://draenor.org/ipfw
 | |
| # Freely distributable 
 | |
| 
 | |
| 
 | |
| # Define the firewall command (as in /etc/rc.firewall) for easy
 | |
| # reference.  Helps to make it easier to read.
 | |
| fwcmd="/sbin/ipfw"
 | |
| 
 | |
| # Force a flushing of the current rules before we reload.
 | |
| $fwcmd -f flush
 | |
| 
 | |
| # Divert all packets through the tunnel interface.
 | |
| $fwcmd add divert natd all from any to any via tun0
 | |
| 
 | |
| # Allow all data from my network card and localhost.  Make sure you
 | |
| # change your network card (mine was fxp0) before you reboot.  :)
 | |
| $fwcmd add allow ip from any to any via lo0
 | |
| $fwcmd add allow ip from any to any via fxp0
 | |
| 
 | |
| # Allow all connections that I initiate.
 | |
| $fwcmd add allow tcp from any to any out xmit tun0 setup
 | |
| 
 | |
| # Once connections are made, allow them to stay open.
 | |
| $fwcmd add allow tcp from any to any via tun0 established
 | |
| 
 | |
| # Everyone on the internet is allowed to connect to the following
 | |
| # services on the machine.  This example specifically allows connections
 | |
| # to ssh and apache.
 | |
| $fwcmd add allow tcp from any to any 80 setup
 | |
| $fwcmd add allow tcp from any to any 22 setup
 | |
| 
 | |
| # This sends a RESET to all ident packets.
 | |
| $fwcmd add reset log tcp from any to any 113 in recv tun0
 | |
| 
 | |
| # Allow outgoing DNS queries ONLY to the specified servers.
 | |
| $fwcmd add allow udp from any to <replaceable>x.x.x.x</replaceable> 53 out xmit tun0
 | |
| 
 | |
| # Allow them back in with the answers...  :)
 | |
| $fwcmd add allow udp from <replaceable>x.x.x.x</replaceable> 53 to any in recv tun0
 | |
| 
 | |
| # Allow ICMP (for ping and traceroute to work).  You may wish to
 | |
| # disallow this, but I feel it suits my needs to keep them in.
 | |
| $fwcmd add 65435 allow icmp from any to any
 | |
| 
 | |
| # Deny all the rest.
 | |
| $fwcmd add 65435 deny log ip from any to any</programlisting>
 | |
| 
 | |
|     <para>You now have a fully functional firewall that will allow on
 | |
|       connections to ports 80 and 22 and will log any other connection
 | |
|       attempts. Now, you should be able to safely reboot and your firewall 
 | |
|       should come up fine. If you find this incorrect in anyway or experience 
 | |
|       any problems, or have any suggestions to improve this page, please 
 | |
|       email me.</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1>
 | |
|     <title>Questions</title>
 | |
|     
 | |
|     <qandaset>
 | |
|       <qandaentry>
 | |
| 	<question>
 | |
| 	  <para>Why are you using &man.natd.8; and &man.ipfw.8; when
 | |
| 	    you could be using the built in &man.ppp.8;
 | |
| 	    filters?</para>
 | |
| 	</question>
 | |
| 	
 | |
| 	<answer>
 | |
| 	  <para>I will have to be honest and say there is no definitive
 | |
| 	    reason why I use <command>ipfw</command> and
 | |
| 	    <command>natd</command> instead of the built in
 | |
| 	    <command>ppp</command> filters.  From the discussions I have
 | |
| 	    had with people the consensus seems to be that while
 | |
| 	    <command>ipfw</command> is certainly more powerful and
 | |
| 	    more configurable than the <command>ppp</command> filters,
 | |
| 	    what it makes up for in functionality it loses in being
 | |
| 	    easy to customize.  One of the reasons I use it is because
 | |
| 	    I prefer firewalling to be done at a kernel level rather
 | |
| 	    than by a userland program.</para>
 | |
| 	</answer>
 | |
|       </qandaentry>
 | |
| 
 | |
|       <qandaentry>
 | |
|         <question>
 | |
| 	  <para>I get messages like <errorname>limit 100 reached on entry
 | |
| 	    2800</errorname> and after that I never see more denies in my
 | |
| 	    logs.  Is my firewall still working?</para>
 | |
|         </question>
 | |
| 
 | |
| 	<answer>
 | |
| 	  <para>This merely means that the maximum logging count for
 | |
|             the rule has been reached.  The rule itself is still
 | |
|             working, but it will no longer log until such time as you
 | |
|             reset the logging counters.  You can reset the logging
 | |
|             counters with the <command>ipfw resetlog</command>
 | |
|             command.  Alternatively, you may increase the log limit in
 | |
|             your kernel configuration with the
 | |
|             <option>IPFIREWALL_VERBOSE_LIMIT</option> option as
 | |
|             described above.  You may also change this limit (without
 | |
| 	    recompiling your kernel and having to reboot) by using the
 | |
| 	    net.inet.ip.fw.verbose_limit &man.sysctl.8; value.</para>
 | |
|         </answer>
 | |
|       </qandaentry>
 | |
| 
 | |
|       <qandaentry>
 | |
| 	<question>
 | |
| 	  <para>If I am using private addresses internally, such as in the
 | |
| 	    192.168.0.0 range, could I add a command like <literal>$fwcmd add
 | |
| 	      deny all from any to 192.168.0.0:255.255.0.0 via tun0</literal>
 | |
| 	    to the firewall rules to prevent outside attempts to connect to
 | |
| 	    internal machines?</para>
 | |
| 	</question>
 | |
| 
 | |
| 	<answer>
 | |
| 	  <para>The simple answer is no. The reason for this is that
 | |
| 	    <command>natd</command> is doing address translation for
 | |
| 	    <emphasis>anything</emphasis> being diverted through the
 | |
| 	    <devicename>tun0</devicename> device. As far as it is
 | |
| 	    concerned incoming packets will speak only to the
 | |
| 	    dynamically assigned IP address and <emphasis>not</emphasis> to the internal
 | |
| 	    network. Note though that you can add a rule like
 | |
| 	    <literal>$fwcmd add deny all from 192.168.0.4:255.255.0.0
 | |
| 	    to any via tun0</literal> which would limit a host on your
 | |
| 	    internal network from going out via the firewall.</para>
 | |
| 	</answer>
 | |
|       </qandaentry>
 | |
| 
 | |
|       <qandaentry>
 | |
| 	<question>
 | |
| 	  <para>There must be something wrong.  I followed your instructions
 | |
| 	    to the letter and now I am locked out.</para>
 | |
|         </question>
 | |
| 
 | |
| 	<answer>
 | |
| 	  <para>This tutorial assumes that you are running
 | |
| 	    <emphasis>userland-ppp</emphasis>, therefore the supplied ruleset
 | |
| 	    operates on the <devicename>tun0</devicename> interface, which
 | |
| 	    corresponds to the first connection made with &man.ppp.8; (a.k.a.
 | |
| 	    <emphasis>user-ppp</emphasis>).  Additional connections would use
 | |
| 	    <devicename>tun1</devicename>, <devicename>tun2</devicename> and so
 | |
| 	    on.</para>
 | |
| 
 | |
| 	  <para>You should also note that &man.pppd.8; uses the
 | |
| 	    <devicename>ppp0</devicename> interface instead, so if you
 | |
| 	    start the connection with &man.pppd.8; you must substitute
 | |
| 	    <devicename>tun0</devicename> for
 | |
| 	    <devicename>ppp0</devicename>.  A quick way to edit the
 | |
| 	    firewall rules to reflect this change is shown below. The
 | |
| 	    original ruleset is backed up as
 | |
| 	    <filename>fwrules_tun0</filename>.</para>
 | |
| 
 | |
| 	  <screen>	    &prompt.user; <userinput>cd /etc/firewall</userinput>
 | |
| 	    /etc/firewall&prompt.user; <userinput>su</userinput>
 | |
| 	    <prompt>Password:</prompt>
 | |
| 	    /etc/firewall&prompt.root; <userinput>mv fwrules fwrules_tun0</userinput>
 | |
| 	    /etc/firewall&prompt.root; <userinput>cat fwrules_tun0 | sed s/tun0/ppp0/g > fwrules</userinput>
 | |
| 	  </screen>
 | |
| 
 | |
| 	  <para>To know whether you are currently using &man.ppp.8; or
 | |
| 	    &man.pppd.8; you can examine the output of
 | |
| 	    &man.ifconfig.8; once the connection is up. E.g., for a
 | |
| 	    connection made with &man.pppd.8; you would see something
 | |
| 	    like this (showing only the relevant lines):</para>
 | |
| 
 | |
| 	  <screen>	    &prompt.user; <userinput>ifconfig</userinput>
 | |
| 	    <emphasis>(skipped...)</emphasis>
 | |
| 	    ppp0: flags=<replaceable>8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1524</replaceable>
 | |
|                     inet <replaceable>xxx.xxx.xxx.xxx</replaceable> --> <replaceable>xxx.xxx.xxx.xxx</replaceable> netmask <replaceable>0xff000000</replaceable>
 | |
| 	    <emphasis>(skipped...)</emphasis>
 | |
| 	    </screen>
 | |
| 
 | |
| 	  <para>On the other hand, for a connection made with
 | |
| 	    &man.ppp.8; (<emphasis>user-ppp</emphasis>) you should see
 | |
| 	    something similar to this:</para>
 | |
| 
 | |
| 	  <screen>	    &prompt.user; <userinput>ifconfig</userinput>
 | |
| 	    <emphasis>(skipped...)</emphasis>
 | |
| 	    ppp0: flags=<replaceable>8010<POINTOPOINT,MULTICAST> mtu 1500</replaceable>
 | |
| 	    <emphasis>(skipped...)</emphasis>
 | |
| 	    tun0: flags=<replaceable>8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1524</replaceable>
 | |
| 	            <emphasis>(IPv6 stuff skipped...)</emphasis>
 | |
|                     inet <replaceable>xxx.xxx.xxx.xxx</replaceable> --> <replaceable>xxx.xxx.xxx.xxx</replaceable> netmask <replaceable>0xffffff00</replaceable>
 | |
|                     Opened by PID <replaceable>xxxxx</replaceable>
 | |
|             <emphasis>(skipped...)</emphasis></screen>
 | |
| 	</answer>
 | |
|       </qandaentry>
 | |
|     </qandaset>
 | |
|   </sect1>
 | |
| </article>
 |