Bring in the english translation of the new filtering-bridges article,
that is already in the italian part of our docs. PR: docs/34821 Submitted by: Alex Dupre <sysadmin@@alexdupre.com>
This commit is contained in:
parent
fae01820c8
commit
a61bd0b16d
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=12650
1 changed files with 299 additions and 270 deletions
|
|
@ -9,348 +9,377 @@
|
|||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Nick</firstname>
|
||||
<surname>Sayer</surname>
|
||||
|
||||
<firstname>Alex</firstname>
|
||||
<surname>Dupre</surname>
|
||||
<affiliation>
|
||||
<address><email>nsayer@FreeBSD.org</email></address>
|
||||
<address><email>sysadmin@alexdupre.com</email></address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
|
||||
<pubdate>$FreeBSD$</pubdate>
|
||||
|
||||
<abstract>
|
||||
<para>For those of you who do not know, DSL differs from more traditional
|
||||
connectivity methods in that the <quote>connectivity spigot</quote> that comes
|
||||
out of the wall has no possibility for packet filtering. If you get
|
||||
a T1 line or some such it will come with a router that can generally
|
||||
include a packet filter. If you get ISDN or a dialup link, you also
|
||||
either have a software routing component (a PPP daemon, specifically)
|
||||
that can do some filtering or can be combined with a filter on the
|
||||
machine running the link. But with DSL you only get a little white
|
||||
box with some Blinkenlights on it and an Ethernet port that takes
|
||||
your traffic back and forth from the Internet and nothing else (to
|
||||
some extent the same can be said of other mass-market high speed
|
||||
connectivity methods, like cable modems or high speed wireless links
|
||||
as well. The same technique I plan to describe works just as well
|
||||
for them, or for any other technology that provides an Ethernet
|
||||
port with no filtering).</para>
|
||||
<para>Often it is useful to divide one physical network (like an
|
||||
Ethernet) into two separate segments without having to create subnets,
|
||||
and use a router to link them together. The device that connects the
|
||||
two networks in this way is called a bridge. A FreeBSD system with
|
||||
two network interfaces is enough in order to act as a bridge.</para>
|
||||
|
||||
<para>A bridge works by scanning the addresses of <acronym>MAC</acronym>
|
||||
level (Ethernet addresses) of the devices connected to each of its
|
||||
network interfaces and then forwarding the traffic between the two
|
||||
networks only if the source and the destination are on different
|
||||
segments. Under many points of view a brigde is similar to an Ethernet
|
||||
switch with only two ports.</para>
|
||||
</abstract>
|
||||
</articleinfo>
|
||||
|
||||
<sect1 id="filtering-bridges-why">
|
||||
<title>Why use a filtering bridge?</title>
|
||||
|
||||
<para>Bridging is not the only conceivable option. It is possible to
|
||||
set up a two Ethernet machine as a router instead of a bridge.
|
||||
Where it is possible to do so, it is actually a better idea.
|
||||
Bridges run their interfaces in promiscuous mode, meaning they
|
||||
must process every packet presented to them. The problem is
|
||||
that routers can only route traffic between different subnets.
|
||||
Also, subnets can only be made by by cutting an existing space in
|
||||
half or defining a new space that is typically unroutable (see
|
||||
<ulink url="ftp://nis.nsf.net/internet/documents/rfc/rfc1918.txt">RFC 1918</ulink>).
|
||||
This wastes half of the useful addresses (or at least puts
|
||||
them on the <quote>wrong</quote> side of the router—the thing that is
|
||||
doing the packet filtering that makes the inside network safe).
|
||||
Using a bridge costs some CPU cycles, but makes all of the
|
||||
problems of adding a 2nd router go away.</para>
|
||||
<para>More and more frequently, thanks to the lowering costs of broad band
|
||||
Internet connections (xDSL) and also because of the reduction of
|
||||
available IPv4 addresses, many companies are connected to the Internet
|
||||
24 hours on 24 and with few (sometimes not even a power of 2) IP
|
||||
addresses. In these situations it is often desirable to have a firewall
|
||||
that filters incoming and outgoing traffic from and towards Internet,
|
||||
but a packet filtering solution based on router may not be applicable,
|
||||
either due to subnetting issues, the router is owned by the connectivity
|
||||
supplier (<acronym>ISP</acronym>), or because it doesn't support such
|
||||
functionalities. In these scenarios the use of a filtering bridge is
|
||||
highly advised.</para>
|
||||
|
||||
<para>A bridge-based firewall can be configured and inserted between the
|
||||
xDSL router and your Ethernet hub/switch without any IP numbering
|
||||
issues.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="filtering-bridges-kernel">
|
||||
<title>Configuring a Kernel</title>
|
||||
|
||||
<sect1 id="filtering-bridges-how">
|
||||
<title>How to Install</title>
|
||||
|
||||
<para>Adding bridge functionalities to a FreeBSD system is not difficult.
|
||||
Since 4.5 release it is possible to load such functionalities as modules
|
||||
instead of having to rebuild the kernel, simplifying the procedure a
|
||||
great deal. In the following subsections I will explain both
|
||||
installation ways.</para>
|
||||
|
||||
<important>
|
||||
<para>After configuring and installing a kernel as shown here, you
|
||||
should carry out the other
|
||||
<link linkend="filtering-bridges-finalprep">final preperation</link>
|
||||
tasks <emphasis>before</emphasis> booting into your new kernel.</para>
|
||||
<para><emphasis>Do not</emphasis> follow both instructions: a procedure
|
||||
<emphasis>excludes</emphasis> the other one. Select the best choice
|
||||
according to your needs and abilities.</para>
|
||||
</important>
|
||||
|
||||
<para>Adding bridging to a FreeBSD machine is not hard to do. It means
|
||||
having 2 (or more, but we will just use 2 here) Ethernet cards and adding
|
||||
a couple of lines to the kernel configuration. Since May of 2000,
|
||||
RELENG_4 and -current have had bridging support for all Ethernet
|
||||
interfaces. This does not mean that any Ethernet interface will work.
|
||||
For them to work, they have to support a working promiscuous mode for
|
||||
both reception and transmission—that is, they have to be able to
|
||||
transmit Ethernet packets with any source address, not just their own.
|
||||
In order to get good throughput, the cards should also be PCI bus
|
||||
mastering cards. The best choices still are the Intel EtherExpress Pro
|
||||
100 cards, with 3com 3c9xx cards being second.</para>
|
||||
<para>Before going on, be sure to have at least two Ethernet cards that
|
||||
support the promiscuous mode for both reception and transmission, since
|
||||
they must be able to send Ethernet packets with any address, not just
|
||||
their own. Moreover, to have a good throughput, the cards should be PCI
|
||||
bus mastering cards. The best choices are still the Intel EtherExpress
|
||||
Pro, followed by the 3Com 3c9xx series. To simplify the firewall
|
||||
configuration it may be useful to have two cards of different
|
||||
manufacturers (using different drivers) in order to distinguish clearly
|
||||
which interface is connected to the router and which to the inner
|
||||
network.</para>
|
||||
|
||||
<para>So you will want to add the following to your kernel configuration
|
||||
file:</para>
|
||||
|
||||
<programlisting>device fxp (or whatever is appropriate for the cards you are using)
|
||||
options BRIDGE
|
||||
<sect2 id="filtering-bridges-kernel">
|
||||
<title>Kernel Configuration</title>
|
||||
|
||||
<para>So you have decided to use the older but well tested installation
|
||||
method. To begin, you have to add the following rows to your kernel
|
||||
configuration file:</para>
|
||||
|
||||
<programlisting>options BRIDGE
|
||||
options IPFIREWALL
|
||||
options IPFIREWALL_VERBOSE</programlisting>
|
||||
|
||||
<para>Note that recent versions of FreeBSD support dynamically loading the
|
||||
IP Firewall code into the kernel. You can not do this, however, with
|
||||
bridging, as the bridge code itself needs to interact with IPFIREWALL
|
||||
in a special way.</para>
|
||||
<para>The first line is to compile the bridge support, the second one is
|
||||
the firewall and the third one is the logging functions of the
|
||||
firewall.</para>
|
||||
|
||||
<para>It is also a good idea at this point to see if Luigi has updated
|
||||
versions of the bridge code available that are more recent than what is
|
||||
in the distribution. As an example, 3.3-RELEASE comes with 981214, but
|
||||
as of this writing, the most up-to-date bridge code is 990810. You can
|
||||
fetch the latest version from
|
||||
<ulink url="http://www.iet.unipi.it/~luigi/">http://www.iet.unipi.it/~luigi/</ulink>. You will want to fetch <filename>bridge.c</filename> and <filename>bridge.h</filename> and drop them into <filename>sys/net/</filename>.</para>
|
||||
<para>Now it is necessary to build and install the new kernel. You may
|
||||
find detailed instructions in the <ulink
|
||||
url="../../books/handbook/kernelconfig-building.html">Building
|
||||
and Installing a Custom Kernel</ulink> section of the FreeBSD
|
||||
Handbook.</para>
|
||||
</sect2>
|
||||
|
||||
<para>For instructions on how to build and install a new kernel, refer to
|
||||
the
|
||||
<ulink url="../../books/handbook/kernelconfig-building.html">Building and Installing a Custom Kernel</ulink> section of the handbook</para>
|
||||
<sect2 id="filtering-bridges-modules">
|
||||
<title>Modules Loading</title>
|
||||
|
||||
<para>If you have choosen to use the new and simpler installation
|
||||
method, the only thing to do now is add the following row to
|
||||
<filename>/boot/loader.conf</filename>:</para>
|
||||
|
||||
<programlisting>bridge_load="YES"</programlisting>
|
||||
|
||||
<para>In this way, during the system startup, the
|
||||
<filename>bridge.ko</filename> module will be loaded together with the
|
||||
kernel. It is not required to add a similar row for the
|
||||
<filename>ipfw.ko</filename> module, since it will be loaded
|
||||
automatically after the execution of the steps in the following
|
||||
section.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="filtering-bridges-finalprep">
|
||||
<title>Final Preperation</title>
|
||||
|
||||
<para>Before you boot the new kernel, you must make some preparations in
|
||||
<filename>rc.boot</filename> and <filename>rc.firewall</filename>. The
|
||||
default rule for the firewall is to drop all packets on the floor. You
|
||||
will want to override this by setting up the <quote>open</quote> firewall in
|
||||
<filename>/etc/rc.conf</filename>. Put these lines in
|
||||
<filename>/etc/rc.conf</filename> to achieve this:</para>
|
||||
<para>Before rebooting in order to load the new kernel or the required
|
||||
modules (according to the previously choosen installation method), you
|
||||
have to make some changes to the <filename>/etc/rc.conf</filename>
|
||||
configuration file. The default rule of the firewall is to reject all IP
|
||||
packets. Initially we'll set up an 'open' firewall, in order to verify
|
||||
its operation without any issue related to packet filtering (in case you
|
||||
are going to execute this procedure remotely, such configuration will
|
||||
avoid you to remain isolated from the network). Put these lines in
|
||||
<filename>/etc/rc.conf</filename>:</para>
|
||||
|
||||
<programlisting>firewall_enable="YES"
|
||||
firewall_type="open"</programlisting>
|
||||
<programlisting>firewall_enable="YES"
|
||||
firewall_type="open"
|
||||
firewall_quiet="YES"
|
||||
firewall_logging="YES"</programlisting>
|
||||
|
||||
<para>There is one more thing that is necessary. When running IP over
|
||||
Ethernet, there are actually two Ethernet protocols in use. One
|
||||
is IP, the other is ARP. ARP is used when a machine must figure out
|
||||
what Ethernet address corresponds to a given IP address. ARP is not
|
||||
a part of the IP layer, since it only applies to IP when run over
|
||||
Ethernet. The standard ipfirewall rule for the open firewall is</para>
|
||||
<para>The first row will enable the firewall (and will load the module
|
||||
<filename>ipfw.ko</filename> if it is not compiled in the kernel), the
|
||||
second one to set up it in 'open' mode (as explained in
|
||||
<filename>/etc/rc.firewall</filename>), the third one to not show rules
|
||||
loading and the fourth one to enable logging support.</para>
|
||||
|
||||
<programlisting>pass ip from any to any</programlisting>
|
||||
<para>About the configuration of the network interfaces, the most used way
|
||||
is to assign an IP to only one of the network cards, but the bridge will
|
||||
work equally even if both interfaces or none has a configured IP. In the
|
||||
last case (IP-less) the bridge machine will be still more hidden, as
|
||||
inaccessible from the network: to configure it, you have to login from
|
||||
console or through a third network interface separated from the bridge.
|
||||
Sometimes, during the system startup, some programs require network
|
||||
access, say for domain resolution: in this case it is necessary to
|
||||
assign an IP to the external interface (the one connected to Internet,
|
||||
where <acronym>DNS</acronym> server resides), since the bridge will be
|
||||
activated at the end of the startup procedure. It means that the
|
||||
<devicename>fxp0</devicename> interface (in our case) must be mentioned
|
||||
in the ifconfig section of the <filename>/etc/rc.conf</filename> file,
|
||||
while the <devicename>xl0</devicename> is not. Assigning an IP to both
|
||||
the network cards does not make much sense, unless, during the start
|
||||
procedure, applications should access to services on both Ethernet
|
||||
segments.</para>
|
||||
|
||||
<para>but what about ARP? If ARP is not passed, no IP traffic can flow at
|
||||
all. But IPFIREWALL has no provisions for dealing with non-IP
|
||||
protocols, and that includes ARP. Fortunately, a hackish extension was
|
||||
made to the ipfirewall code to assist filtering bridges. If you set up
|
||||
a special rule for UDP packets from IP address
|
||||
<hostid role="ipaddr">0.0.0.0</hostid>, the UDP port number will be used
|
||||
to match the Ethernet protocol number for bridged packets. In this way
|
||||
your bridge can be configured to pass or reject non IP protocols. So add
|
||||
this line just below the two lines near the top of
|
||||
<filename>/etc/rc.firewall</filename> that deal with
|
||||
<devicename>lo0</devicename> (the ones that say that you should almost
|
||||
never change those two rules).</para>
|
||||
<para>There is another important thing to know. When running IP over
|
||||
Ethernet, there are actually two Ethernet protocols in use: one is IP,
|
||||
the other is <acronym>ARP</acronym>. <acronym>ARP</acronym> does the
|
||||
conversion of the IP address of a host into its Ethernet address
|
||||
(<acronym>MAC</acronym> layer). In order to allow the communication
|
||||
between two hosts separated by the bridge, it is necessary that the
|
||||
bridge will forward <acronym>ARP</acronym> packets. Such protocol is not
|
||||
included in the IP layer, since it exists only with IP over Ethernet.
|
||||
The FreeBSD firewall filters exclusively on the IP layer and therefore
|
||||
all non-IP packets (<acronym>ARP</acronym> included) will be forwarded
|
||||
without being filtered, even if the firewall is configured to not permit
|
||||
anything.</para>
|
||||
|
||||
<programlisting>${fwcmd} add allow udp from 0.0.0.0 2054 to 0.0.0.0</programlisting>
|
||||
<para>Now it's time to reboot the system and use it as before: there will
|
||||
be some new messages about the bridge and the firewall, but the bridge
|
||||
will not be activated and the firewall, being in 'open' mode, will not
|
||||
avoid any operations.</para>
|
||||
|
||||
<para>This rule makes almost no sense at all from a normal perspective on
|
||||
IPFIREWALL, but the bridge code will use it to pass ARP packets without
|
||||
restriction (which you almost certainly want to do).</para>
|
||||
|
||||
<para>Now you should be able to reboot your machine and have it act no
|
||||
differently than it did before. There will be some new boot messages
|
||||
about bridging, but the bridging will not be enabled. If there are any
|
||||
problems, you should try and sort them out at this point before
|
||||
proceeding.</para>
|
||||
<para>If there are any problems, you should try and sort them out now
|
||||
before proceeding.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="filtering-bridges-enabling">
|
||||
<title>Enabling The Bridge</title>
|
||||
|
||||
<para>Next, you should do this:</para>
|
||||
<title>Enabling the Bridge</title>
|
||||
|
||||
<screen>&prompt.root; <userinput>sysctl -w net.link.ether.bridge_ipfw=1</userinput>
|
||||
&prompt.root; <userinput>sysctl -w net.link.ether.bridge=1</userinput></screen>
|
||||
<para>At this point, to enable the bridge, you have to execute the
|
||||
following commands (having the shrewdness to replace the names of the
|
||||
two network interfaces <devicename>fxp0</devicename> and
|
||||
<devicename>xl0</devicename> with your own ones):</para>
|
||||
|
||||
<para>At this point, the bridge should be enabled, and because of the
|
||||
previous changes to <filename>/etc/rc.conf</filename>, the firewall
|
||||
should be wide open. At this point, you should be able to insert the
|
||||
machine between two sets of hosts and go back and forth without
|
||||
difficulty. If so, the next step is to add those two sysctl lines to
|
||||
either <filename>/etc/rc.local</filename> or add the net.link.[blah
|
||||
blah]=1 portions of the lines to <filename>/etc/sysctl.conf</filename>
|
||||
(which path you take depends on what version of FreeBSD you
|
||||
have).</para>
|
||||
<screen>&prompt.root; <userinput>sysctl net.link.ether.bridge_cfg=fxp0:0,xl0:0</userinput>
|
||||
&prompt.root; <userinput>sysctl net.link.ether.bridge_ipfw=1</userinput>
|
||||
&prompt.root; <userinput>sysctl net.link.ether.bridge=1</userinput></screen>
|
||||
|
||||
<para>Now before we started all of this, you should have had a machine
|
||||
with two Ethernet interfaces, but with only one of them configured. That
|
||||
is, there should only be one ifconfig line
|
||||
<filename>/etc/rc.conf</filename>. With the bridge in place, that is
|
||||
still true. But there is a detail that deserves some thought. The
|
||||
bridge is not in place by default. That means that until the sysctls
|
||||
are run that turn the bridge on, rather late in the startup, it is still
|
||||
an ordinary machine with two interfaces, only one of which is configured
|
||||
by <filename>/etc/rc.conf</filename>. This becomes important for those
|
||||
portions of the startup that require network access, say for DNS
|
||||
resolution. Some care must be made in picking which interface is going
|
||||
to be the configured one. In most cases, you are best to pick the
|
||||
<quote>outside</quote> one (that is, the interface connected to the Internet). Let's
|
||||
presume for the sake of the examples to come, that
|
||||
<devicename>fxp0</devicename> is the <quote>outside</quote> interface, and
|
||||
<devicename>fxp1</devicename> is the <quote>inside</quote> one. That means that fxp0
|
||||
should be mentioned in <filename>/etc/rc.conf</filename>'s ifconfig
|
||||
sections, but <devicename>fxp1</devicename> should not be. The sysctl
|
||||
that turns the bridge on will make <devicename>fxp1</devicename> start
|
||||
working automagically.</para>
|
||||
<para>The first row specifies which interfaces should be activated by the
|
||||
bridge, the second one will enable the firewall on the bridge and
|
||||
finally the third one will enable the bridge.</para>
|
||||
|
||||
<para>At this point you should be able to insert the machine between two
|
||||
sets of hosts without compromising any communication abilities between
|
||||
them. If so, the next step is to add the
|
||||
<literal>net.link.ether.<replaceable>[blah]</replaceable>=<replaceable>[blah]</replaceable></literal>
|
||||
portions of these rows to the <filename>/etc/sysctl.conf</filename>
|
||||
file, in order to have them execute at startup.</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="filtering-bridges-ipfirewall">
|
||||
<title>Configuring The Firewall</title>
|
||||
|
||||
<para>Now it is time to start adding ipfirewall rules to secure the inside
|
||||
network. There are some complications in doing this because not all of
|
||||
the ipfirewall functionality is available on bridged packets. Also,
|
||||
there is a difference between packets that are in the process of being
|
||||
bridged and packets that are being received by the local machine. In
|
||||
general, packets being bridged are only run through ipfirewall once, not
|
||||
twice as is usually the case. Bridged packets are filtered while they
|
||||
are being received, so rules that use <literal>out</literal> or <literal>xmit</literal> will never match.
|
||||
I usually use <literal>in via</literal> which is an older syntax, but one that makes
|
||||
sense as you read it. Another limitation is that you are restricted
|
||||
only to <literal>pass</literal> or <literal>drop</literal> for filtering bridged packets. Sophisticated
|
||||
things like <literal>divert</literal> or <literal>forward</literal> or <literal>reject</literal> are not available. Such
|
||||
options can still be used, but only on traffic to or from the bridge
|
||||
machine itself.</para>
|
||||
|
||||
<para>New in FreeBSD 4.0 is the concept of stateful filtering. This is a
|
||||
big boost for UDP traffic, which typically is a request going out,
|
||||
followed shortly thereafter by a response with the exact same set of IP
|
||||
addresses and port numbers (but with source and dest reversed, of
|
||||
course). For firewalls that have no statekeeping, there is almost no
|
||||
way to deal with this sort of traffic short of setting up proxies. But
|
||||
a firewall that can <quote>remember</quote> an outgoing UDP packet and for the next
|
||||
few minutes allow a response, handling UDP services is trivial. The
|
||||
example to follow shows how to do this. The truly paranoid can also set
|
||||
up rules like this to handle TCP. This allows you to avoid some sorts
|
||||
of denial of service attacks or other nasty tricks, but it also
|
||||
typically makes your state table mushroom in size.</para>
|
||||
<para>Now it is time to create your own file with custom firewall rules,
|
||||
in order to secure the inside network. There will be some complication
|
||||
in doing this because not all of the firewall functionalities are
|
||||
available on bridged packets. Furthermore, there is a difference between
|
||||
the packets that are in the process of being forwarded and packets that
|
||||
are being received by the local machine. In general, incoming packets
|
||||
are run through the firewall only once, not twice as is normally the
|
||||
case; in fact they are filtered only upon receipt, so rules that use
|
||||
'out' or 'xmit' will never match. Personally, I use 'in via' which is an
|
||||
older syntax, but one that has a sense when you read it. Another
|
||||
limitation is that you are restricted to use only 'pass' or 'drop'
|
||||
commands for packets filtered by a bridge. Sophisticated things like
|
||||
'divert', 'forward' or 'reject' are not available. Such options can
|
||||
still be used, but only on traffic to or from the bridge machine itself
|
||||
(if it has an IP address).</para>
|
||||
|
||||
<para>Let's look at an example setup. Note first that at the top of
|
||||
<filename>/etc/rc.firewall</filename> we should already have taken care
|
||||
of the loopback interface and the special hack for ARP should still be
|
||||
in place. So we will not worry about them any further.</para>
|
||||
<para>New in FreeBSD 4.0, is the concept of stateful filtering. This is a
|
||||
big improvement for <acronym>UDP</acronym> traffic, which typically is a
|
||||
request going out, followed shortly thereafter by a response with the
|
||||
exact same set of IP addresses and port numbers (but with source and
|
||||
destination reversed, of course). For firewalls that have no
|
||||
statekeeping, there is almost no way to deal with this sort of traffic
|
||||
as a single session. But with a firewall that can "remember" an outgoing
|
||||
<acronym>UDP</acronym> packet and, for the next few minutes, allow a
|
||||
response, handling <acronym>UDP</acronym> services is trivial. The
|
||||
following example shows how to do it. It's possible to do the same thing
|
||||
with <acronym>TCP</acronym> packets. This allows you to avoid some
|
||||
denial of service attacks and other nasty tricks, but it also typically
|
||||
makes your state table grow quickly in size.</para>
|
||||
|
||||
<programlisting>us_ip=192.168.1.1
|
||||
oif=fxp0
|
||||
iif=fxp1
|
||||
<para>Let's look at an example setup. Note first that at the top of
|
||||
<filename>/etc/rc.firewall</filename> there are already standard rules
|
||||
for the loopback interface <devicename>lo0</devicename>, so we shouldn't
|
||||
have to care for them anymore. Custom rules should be put in a separate
|
||||
file (say <filename>/etc/rc.firewall.local</filename>) and loaded at
|
||||
system startup, by modifying the row of
|
||||
<filename>/etc/rc.conf</filename> where we defined the 'open'
|
||||
firewall:</para>
|
||||
|
||||
# Things that we've kept state on before get to go through in a hurry.
|
||||
${ipfw} add check-state
|
||||
<programlisting>firewall_type="/etc/rc.firewall.local"</programlisting>
|
||||
|
||||
<important>
|
||||
<para>You have to specify the <emphasis>full</emphasis> path, otherwise
|
||||
it will not be loaded with the risk to remain isolated from the
|
||||
network.</para>
|
||||
</important>
|
||||
|
||||
<para>For our example imagine to have the <devicename>fxp0</devicename>
|
||||
interface connected towards the outside (Internet) and the
|
||||
<devicename>xl0</devicename> towards the inside
|
||||
(<acronym>LAN</acronym>). The bridge machine has the IP <hostid
|
||||
role="ipaddr">1.2.3.4</hostid> (it is not possible that your
|
||||
<acronym>ISP</acronym> can give you a class A address like this, but for
|
||||
our example it is good).</para>
|
||||
|
||||
<programlisting># Things that we have kept state on before get to go through in a hurry
|
||||
add check-state
|
||||
|
||||
# Throw away RFC 1918 networks
|
||||
${ipfw} add deny log ip from 10.0.0.0/8 to any in via ${oif}
|
||||
${ipfw} add deny log ip from 172.16.0.0/12 to any in via ${oif}
|
||||
${ipfw} add deny log ip from 192.68.0.0/16 to any in via ${oif}
|
||||
add drop all from 10.0.0.0/8 to any in via fxp0
|
||||
add drop all from 172.16.0.0/12 to any in via fxp0
|
||||
add drop all from 192.68.0.0/16 to any in via fxp0
|
||||
|
||||
# Allow the bridge machine to say anything it wants (keep state if UDP)
|
||||
${ipfw} add pass udp from ${us_ip} to any keep-state
|
||||
${ipfw} add pass ip from ${us_ip} to any
|
||||
# Allow the bridge machine to say anything it wants
|
||||
# (if the machine is IP-less don't include these rows)
|
||||
add pass tcp from 1.2.3.4 to any setup keep-state
|
||||
add pass udp from 1.2.3.4 to any keep-state
|
||||
add pass ip from 1.2.3.4 to any
|
||||
|
||||
# Allow the inside net to say anything it wants (keep state if UDP)
|
||||
${ipfw} add pass udp from any to any in via ${iif} keep-state
|
||||
${ipfw} add pass ip from any to any in via ${iif}
|
||||
|
||||
# Allow all manner of ICMP
|
||||
${ipfw} add pass icmp from any to any
|
||||
# Allow the inside hosts to say anything they want
|
||||
add pass tcp from any to any in via xl0 setup keep-state
|
||||
add pass udp from any to any in via xl0 keep-state
|
||||
add pass ip from any to any in via xl0
|
||||
|
||||
# TCP section
|
||||
# established TCP sessions are ok everywhere.
|
||||
${ipfw} add pass tcp from any to any established
|
||||
# Pass the "quarantine" range.
|
||||
${ipfw} add pass tcp from any to any 49152-65535 in via ${oif}
|
||||
# Allow SSH
|
||||
add pass tcp from any to any 22 in via fxp0 setup keep-state
|
||||
# Allow SMTP only towards the mail server
|
||||
add pass tcp from any to relay 25 in via fxp0 setup keep-state
|
||||
# Allow zone transfers only by the slave name server [dns2.nic.it]
|
||||
add pass tcp from 193.205.245.8 to ns 53 in via fxp0 setup keep-state
|
||||
# Pass ident probes. It's better than waiting for them to timeout
|
||||
${ipfw} add pass tcp from any to any 113 in via ${oif}
|
||||
# Pass SSH.
|
||||
${ipfw} add pass tcp from any to any 22 in via ${oif}
|
||||
# Pass DNS. Only if you have name servers inside.
|
||||
#${ipfw} add pass tcp from any to any 53 in via ${oif}
|
||||
# Pass SMTP to the mail server only
|
||||
${ipfw} add pass tcp from any to mailhost 25 in via ${oif}
|
||||
add pass tcp from any to any 113 in via fxp0 setup keep-state
|
||||
# Pass the "quarantine" range
|
||||
add pass tcp from any to any 49152-65535 in via fxp0 setup keep-state
|
||||
|
||||
# UDP section
|
||||
# Pass the "quarantine" range.
|
||||
${ipfw} add pass udp from any to any 49152-65535 in via ${oif}
|
||||
# Pass DNS. Only if you have name servers inside.
|
||||
#${ipfw} add pass udp from any to any 53 in via ${oif}
|
||||
# Allow DNS only towards the name server
|
||||
add pass udp from any to ns 53 in via fxp0 keep-state
|
||||
# Pass the "quarantine" range
|
||||
add pass udp from any to any 49152-65535 in via fxp0 keep-state
|
||||
|
||||
# ICMP section
|
||||
# Pass 'ping'
|
||||
add pass icmp from any to any icmptypes 8 keep-state
|
||||
# Pass error messages generated by 'traceroute'
|
||||
add pass icmp from any to any icmptypes 3
|
||||
add pass icmp from any to any icmptypes 11
|
||||
|
||||
# Everything else is suspect
|
||||
${ipfw} add deny log ip from any to any</programlisting>
|
||||
add drop log all from any to any</programlisting>
|
||||
|
||||
<para>Those of you who have set up firewalls before may notice some things
|
||||
missing. In particular, there are no anti-spoofing rules. That is,
|
||||
we did <emphasis>not</emphasis> add:</para>
|
||||
missing. In particular, there are no anti-spoofing rules, in fact we did
|
||||
<emphasis>not</emphasis> add:</para>
|
||||
|
||||
<programlisting>${ipfw} add deny ip from ${us_ip}/24 to any in via ${oif}</programlisting>
|
||||
<programlisting>add deny all from 1.2.3.4/8 to any in via fxp0</programlisting>
|
||||
|
||||
<para>That is, drop packets claiming to be from our network that are
|
||||
coming in from the outside. This is something that you would commonly
|
||||
do to make sure that someone does not try and evade the packet filter by
|
||||
<para>That is, drop packets that are coming in from the outside claiming
|
||||
to be from our network. This is something that you would commonly do to
|
||||
be sure that someone does not try and evade the packet filter, by
|
||||
generating nefarious packets that look like they are from the inside.
|
||||
The problem with that is that there is at least one host on the outside
|
||||
interface that you do not want to ignore—your router. In my
|
||||
particular case, I have some machines on the outside and some on the
|
||||
inside, but I do not necessarily want the outside machines to have
|
||||
routine access to the inside. At the same time, I do not want to throw
|
||||
their traffic away. In my own case, my ISP anti-spoofs at their router,
|
||||
so I do not need to bother. And in general, the fewer rules the better,
|
||||
since it will take time and CPU to process each one.</para>
|
||||
The problem with that is that there is <emphasis>at least</emphasis> one
|
||||
host on the outside interface that you do not want to ignore: the
|
||||
router. But usually, the <acronym>ISP</acronym> anti-spoofs at their
|
||||
router, so we do not need to bother that much.</para>
|
||||
|
||||
<para>Note also that the last rule is almost an exact duplicate of the
|
||||
default rule 65536. There are two major differences when it comes to
|
||||
bridging, however. Our rule logs what it drops, of course, but our rule
|
||||
will only apply to IP traffic. Apart from the UDP
|
||||
<hostid role="ipaddr">0.0.0.0</hostid> trick there is no way to deal
|
||||
with non IP traffic, so the default rule at 65536 will drop ALL traffic,
|
||||
not merely all non-IP traffic. So the net effect is that unmatched IP
|
||||
traffic will be logged, but not non-IP traffic. If you want, you can
|
||||
add option <literal>IPFIREWALL_DEFAULT_TO_ACCEPT</literal> to your
|
||||
<link linkend="filtering-bridges-kernel">kernel configuration</link> and
|
||||
non-IP traffic will be passed instead of dropped. But in the case of a
|
||||
filtering bridge between you and the Internet, it is unlikely that you
|
||||
would want to do this (if you are sufficiently paranoid).</para>
|
||||
<para>The last rule seems to be an exact duplicate of the default rule,
|
||||
that is, do not let anything pass that is not specifically allowed. But
|
||||
there is a difference: all suspected traffic will be logged.</para>
|
||||
|
||||
<para>There is a rule for passing SMTP to a mailhost if you have one.
|
||||
Obviously the whole ruleset above should be flavored to taste, and
|
||||
that is an example of a specific service exemption. Note that
|
||||
in order for <quote>mailhost</quote> to work, name service lookups must work
|
||||
BEFORE the bridge is enabled. This is an example of making sure
|
||||
that you enable the correct interface.</para>
|
||||
<para>There are two rules for passing <acronym>SMTP</acronym> and
|
||||
<acronym>DNS</acronym> traffic towards the mail server and the name
|
||||
server, if you have them. Obviously the whole rule set should be
|
||||
flavored to personal taste, this is only a specific example (rule format
|
||||
is described accurately in the &man.ipfw.8; man page). Note that in
|
||||
order for 'relay' and 'ns' to work, name service lookups must work
|
||||
<emphasis>before</emphasis> the bridge is enabled. This is an example of
|
||||
making sure that you set the IP on the correct network card.
|
||||
Alternatively it is possible to specify the IP address instead of the
|
||||
host name (required if the machine is IP-less).</para>
|
||||
|
||||
<para>Another item to note is that the DNS rules are set up only to
|
||||
allow DNS servers to work. This means that if do not set up a
|
||||
DNS server, you do not need them.</para>
|
||||
|
||||
<para>Folks used to setting up IP firewalls also probably are used to
|
||||
either having a <literal>reset</literal> or a <literal>forward</literal> rule for ident packets
|
||||
(TCP port 113). Unfortunately, this is not an option with the
|
||||
bridging code, so the path of least resistance is to simply pass
|
||||
them to their destination. As long as that destination machine
|
||||
is not running an ident daemon, this is relatively harmless.
|
||||
The alternative is dropping port 113 connections, which makes
|
||||
firing up things like IRC take forever (the ident probe must
|
||||
<para>People that are used to setting up firewalls are probably also used
|
||||
to either having a 'reset' or a 'forward' rule for ident packets
|
||||
(<acronym>TCP</acronym> port 113). Unfortunately, this is not an
|
||||
applicable option with the bridge, so the best thing is to simply pass
|
||||
them to their destination. As long as that destination machine is not
|
||||
running an ident daemon, this is relatively harmless. The alternative is
|
||||
dropping connections on port 113, which creates some problems with
|
||||
services like <acronym>IRC</acronym> (the ident probe must
|
||||
timeout).</para>
|
||||
|
||||
<para>The only other thing that is a little weird that you may have noticed
|
||||
is that there is a rule to let <literal>${us_ip}</literal> speak and a separate rule to
|
||||
allow the inside network to speak. Remember that this is because the
|
||||
two sets of traffic will be taking different paths through the kernel
|
||||
and into the packet filter. The inside net will be going through the
|
||||
bridge code. The local machine, however, will be using the normal IP
|
||||
stack to speak. Thus the two rules to handle the different cases. The
|
||||
in via ${oif} rules work for both paths. In general if you use in via
|
||||
rules throughout the filter, you will need to make an exception for
|
||||
locally generated packets, because they did not <quote>come in</quote> via
|
||||
anything.</para>
|
||||
<para>The only other thing that is a little weird that you may have
|
||||
noticed is that there is a rule to let the bridge machine speak, and
|
||||
another for internal hosts. Remember that this is because the two sets
|
||||
of traffic will take different paths through the kernel and into the
|
||||
packet filter. The inside net will go through the bridge, while the
|
||||
local machine will use the normal IP stack to speak. Thus the two rules
|
||||
to handle the different cases. The 'in via
|
||||
<devicename>fxp0</devicename>' rules work for both paths. In general, if
|
||||
you use 'in via' rules throughout the filter, you will need to make an
|
||||
exception for locally generated packets, because they did not come in
|
||||
via any of our interfaces.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="filtering-bridges-contributors">
|
||||
<title>Contributors</title>
|
||||
|
||||
<para>To some extent the material for this discussion is a combination of
|
||||
the items that were discussed by Luigi Rizzo in his Dummynet lecture at
|
||||
FreeBSDcon '99 and by Mark Murray during his Network Security lecture.
|
||||
In addition, for quite some time now I have been putting together
|
||||
filtering bridges for friends and colleagues who were getting DSL
|
||||
connections for their home.</para>
|
||||
</sect1>
|
||||
</article>
|
||||
<para>Many parts of this article have been taken, updated and adapted from
|
||||
an old text about bridging, edited by Nick Sayer. A pair of inspirations
|
||||
are due to an introduction on bridging by Steve Peterson.</para>
|
||||
|
||||
<para>A big thanks to Luigi Rizzo for the implementation of the bridge
|
||||
code in FreeBSD and for the time he has dedicated to me answering all of
|
||||
my related questions.</para>
|
||||
|
||||
<para>A thanks goes out also to Tom Rhodes who looked over my job of
|
||||
translation from Italian (the original language of this article) into
|
||||
English.</para>
|
||||
</sect1>
|
||||
</article>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue