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:
Giorgos Keramidas 2002-04-01 23:42:04 +00:00
parent fae01820c8
commit a61bd0b16d
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=12650

View file

@ -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&mdash;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&mdash;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&mdash;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>