<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<article>
  <!--$Id$-->

  <articleinfo>
    <title>Bridged Firewalls</title>

    <authorgroup>
      <author>
        <firstname>Tom</firstname>

        <surname>Eastep</surname>
      </author>
    </authorgroup>

    <pubdate><?dbtimestamp format="Y/m/d"?></pubdate>

    <copyright>
      <year>2007</year>

      <year>2009</year>

      <holder>Thomas M. Eastep</holder>
    </copyright>

    <legalnotice>
      <para>Permission is granted to copy, distribute and/or modify this
      document under the terms of the GNU Free Documentation License, Version
      1.2 or any later version published by the Free Software Foundation; with
      no Invariant Sections, with no Front-Cover, and with no Back-Cover
      Texts. A copy of the license is included in the section entitled
      <quote><ulink url="GnuCopyright.htm">GNU Free Documentation
      License</ulink></quote>.</para>
    </legalnotice>
  </articleinfo>

  <caution>
    <para><emphasis role="bold">This article applies to Shorewall 4.4 and
    later.</emphasis></para>
  </caution>

  <section id="Background">
    <title>Background</title>

    <para>Systems where Shorewall runs normally function as
    <firstterm>routers</firstterm>. In the context of the Open System
    Interconnect (OSI) reference model, a router operates at layer 3,
    Shorewall may also be deployed on a GNU Linux System that acts as a
    <firstterm>bridge</firstterm>. Bridges are layer 2 devices in the OSI
    model (think of a bridge as an Ethernet switch).</para>

    <para>Some differences between routers and bridges are:</para>

    <orderedlist>
      <listitem>
        <para>Routers determine packet destination based on the destination IP
        address, while bridges route traffic based on the destination MAC
        address in the Ethernet frame.</para>
      </listitem>

      <listitem>
        <para>As a consequence of the first difference, routers can be
        connected to more than one IP network while a bridge/firewall may be
        part of only a single network (see below).</para>
      </listitem>

      <listitem>
        <para>In most configurations, routers don't forward broadcast packets
        while bridges do.</para>

        <note>
          <para>Section 4 of RFC 1812 describes the conditions under which a
          router may or must forward broadcasts.</para>
        </note>
      </listitem>
    </orderedlist>
  </section>

  <section id="Requirements">
    <title>Requirements</title>

    <para>Note that if you need a bridge but do not need to restrict the
    traffic through the bridge then any version of Shorewall will work. See
    the <ulink url="SimpleBridge.html">Simple Bridge documentation</ulink> for
    details.</para>

    <para>In order to use Shorewall as a bridging firewall:</para>

    <itemizedlist>
      <listitem>
        <para>Your kernel must contain bridge support (CONFIG_BRIDGE=m or
        CONFIG_BRIDGE=y).</para>
      </listitem>

      <listitem>
        <para>Your kernel must contain bridge/netfilter integration
        (CONFIG_BRIDGE_NETFILTER=y).</para>
      </listitem>

      <listitem>
        <para>Your kernel must contain Netfilter physdev match support
        (CONFIG_IP_NF_MATCH_PHYSDEV=m or CONFIG_IP_NF_MATCH_PHYSDEV=y).
        Physdev match is standard in the 2.6 kernel series but must be patched
        into the 2.4 kernels (see <ulink
        url="http://bridge.sf.net">http://bridge.sf.net</ulink>). Bering and
        Bering uCLibc users must find and install ipt_physdev.o for their
        distribution and add <quote>ipt_physdev</quote> to
        /etc/modules.</para>
      </listitem>

      <listitem>
        <para>Your iptables must contain physdev match support and must
        support multiple instances of '-m physdev' in a single rule. iptables
        1.3.6 and later contain this support.</para>
      </listitem>

      <listitem>
        <para>You must have the bridge utilities (bridge-utils) package
        installed.</para>
      </listitem>
    </itemizedlist>
  </section>

  <section id="Application">
    <title>Application</title>

    <para>The following diagram shows a typical application of a
    bridge/firewall. There is already an existing router in place whose
    internal interface supports a network, and you want to insert a firewall
    between the router, and the systems in the local network. In the example
    shown, the network uses RFC 1918 addresses but that is not a requirement;
    the bridge would work exactly the same if public IP addresses were used
    (remember that the bridge doesn't deal with IP addresses).</para>

    <graphic fileref="images/bridge.png" />

    <para>There are a several key differences in this setup and a normal
    Shorewall configuration:</para>

    <itemizedlist>
      <listitem>
        <para>The Shorewall system (the Bridge/Firewall) has only a single IP
        address even though it has two Ethernet interfaces! The IP address is
        configured on the bridge itself, rather than on either of the network
        cards.</para>
      </listitem>

      <listitem>
        <para>The systems connected to the LAN are configured with the
        router's IP address (192.168.1.254 in the above diagram) as their
        default gateway.</para>
      </listitem>

      <listitem>
        <para><command>traceroute</command> doesn't detect the Bridge/Firewall
        as an intermediate router.</para>
      </listitem>

      <listitem>
        <para>If the router runs a DHCP server, the hosts connected to the LAN
        can use that server without having <command>dhcrelay</command> running
        on the Bridge/Firewall.</para>
      </listitem>
    </itemizedlist>

    <warning>
      <para>Inserting a bridge/firewall between a router and a set of local
      hosts only works if those local hosts form a single IP network. In the
      above diagram, all of the hosts in the loc zone are in the
      192.168.1.0/24 network. If the router is routing between several local
      networks through the same physical interface (there are multiple IP
      networks sharing the same LAN), then inserting a bridge/firewall between
      the router and the local LAN won't work.</para>
    </warning>

    <para>There are other possibilities here -- there could be a hub or switch
    between the router and the Bridge/Firewall and there could be other
    systems connected to that switch. All of the systems on the local side of
    the <emphasis role="bold">router</emphasis> would still be configured with
    IP addresses in 192.168.1.0/24 as shown below.<graphic
    fileref="images/bridge3.png" /></para>
  </section>

  <section id="Bridge">
    <title>Configuring the Bridge</title>

    <para>Configuring the bridge itself is quite simple and uses the
    <command>brctl</command> utility from the bridge-utils package. Bridge
    configuration information may be found at <ulink
    url="http://bridge.sf.net">http://bridge.sf.net</ulink>.</para>

    <para>Unfortunately, many Linux distributions don't have good bridge
    configuration tools, and the network configuration GUIs don't detect the
    presence of bridge devices. Here is an excerpt from a Debian
    <filename>/etc/network/interfaces</filename> file for a two-port bridge
    with a static IP address:</para>

    <blockquote>
      <programlisting>auto br0
iface br0 inet static
        address 192.168.1.253
        netmask 255.255.255.0
        network 192.168.1.0
        broadcast 192.168.1.255

        pre-up /sbin/ip link set eth0 up
        pre-up /sbin/ip link set eth1 up
        pre-up /usr/sbin/brctl addbr br0
        pre-up /usr/sbin/brctl addif br0 eth0
        pre-up /usr/sbin/brctl addif br0 eth1
        
        pre-down /usr/sbin/brctl delif br0 eth0
        pre-down /sbin/ip link set eth0 down
        pre-down /usr/sbin/brctl delif br0 eth1
        pre-down /sbin/ip link set eth1 down
        
        post-down /usr/sbin/brctl delbr br0</programlisting>
    </blockquote>

    <para>While it is not a requirement to give the bridge an IP address,
    doing so allows the bridge/firewall to access other systems and allows the
    bridge/firewall to be managed remotely. The bridge must also have an IP
    address for REJECT rules and policies to work correctly — otherwise REJECT
    behaves the same as DROP. It is also a requirement for bridges to have an
    IP address if they are part of a <link
    linkend="bridge-router">bridge/router</link>.</para>

    <important>
      <para>Get your bridge configuration working first, including bridge
      startup at boot, before you configure and start Shorewall.</para>
    </important>

    <para>The bridge may have its IP address assigned via DHCP. Here's an
    example of an /etc/sysconfig/network/ifcfg-br0 file from a
    <trademark>SUSE</trademark> system:</para>

    <blockquote>
      <programlisting>BOOTPROTO='dhcp'
REMOTE_IPADDR=''
STARTMODE='onboot'
UNIQUE='3hqH.MjuOqWfSZ+C'
WIRELESS='no'
MTU=''</programlisting>
    </blockquote>

    <para>Here's an /etc/sysconfig/network-scripts/ifcfg-br0 file for a
    <trademark>Mandriva</trademark> system:</para>

    <blockquote>
      <programlisting>DEVICE=br0
BOOTPROTO=dhcp
ONBOOT=yes</programlisting>
    </blockquote>

    <para>On both the <trademark>SUSE</trademark> and Mandriva systems, a
    separate script is required to configure the bridge itself.</para>

    <para>Here are scripts that I used on a <trademark>SUSE</trademark> 9.1
    system.</para>

    <blockquote>
      <para><filename>/etc/sysconfig/network/ifcfg-br0</filename></para>

      <programlisting>BOOTPROTO='dhcp'
REMOTE_IPADDR=''
STARTMODE='onboot'
UNIQUE='3hqH.MjuOqWfSZ+C'
WIRELESS='no'
MTU=''</programlisting>

      <para><filename>/etc/init.d/bridge</filename><programlisting>#!/bin/sh

################################################################################
#   Script to create a bridge
#
#     (c) 2004 - Tom Eastep (teastep@shorewall.net)
#
#   Modify the following variables to match your configuration
#
#### BEGIN INIT INFO
# Provides:       bridge
# Required-Start: coldplug
# Required-Stop:
# Default-Start:  2 3 5
# Default-Stop:   0 1 6
# Description:    starts and stops a bridge
### END INIT INFO
#
# chkconfig: 2345 05 89
# description: GRE/IP Tunnel
#
################################################################################


PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin

INTERFACES="eth1 eth0"
BRIDGE="br0"
MODULES="tulip"

do_stop() {
    echo "Stopping Bridge $BRIDGE"
    brctl delbr $BRIDGE
    for interface in $INTERFACES; do
        ip link set $interface down
    done
}

do_start() {

      echo "Starting Bridge $BRIDGE"
      for module in $MODULES; do
          modprobe $module
      done

      sleep 5

      for interface in $INTERFACES; do
          ip link set $interface up
      done

      brctl addbr $BRIDGE

      for interface in $INTERFACES; do
          brctl addif $BRIDGE $interface
      done
}

case "$1" in
  start)
      do_start
    ;;
  stop)
      do_stop
    ;;
  restart)
      do_stop
      sleep 1
      do_start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac
exit 0</programlisting></para>
    </blockquote>

    <para>Axel Westerhold has contributed this example of configuring a bridge
    with a static IP address on a Fedora System (Core 1 and Core 2 Test 1).
    Note that these files also configure the bridge itself, so there is no
    need for a separate bridge config script.</para>

    <blockquote>
      <para><filename>/etc/sysconfig/network-scripts/ifcfg-br0:</filename></para>

      <programlisting>DEVICE=br0
TYPE=Bridge
IPADDR=192.168.50.14
NETMASK=255.255.255.0
ONBOOT=yes</programlisting>

      <para><filename>/etc/sysconfig/network-scripts/ifcfg-eth0:</filename><programlisting>DEVICE=eth0
TYPE=ETHER
BRIDGE=br0
ONBOOT=yes</programlisting><filename>/etc/sysconfig/network-scripts/ifcfg-eth1:</filename><programlisting>DEVICE=eth1
TYPE=ETHER
BRIDGE=br0
ONBOOT=yes</programlisting></para>
    </blockquote>

    <para>Florin Grad at <trademark>Mandriva</trademark> provides this script
    for configuring a bridge:</para>

    <blockquote>
      <programlisting>#!/bin/sh
# chkconfig: 2345 05 89
# description: Layer 2 Bridge
#

[ -f /etc/sysconfig/bridge ] &amp;&amp; . /etc/sysconfig/bridge

PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin

do_stop() {
    echo "Stopping Bridge"
    for i in $INTERFACES $BRIDGE_INTERFACE ; do
    	ip link set $i down
    done
    brctl delbr $BRIDGE_INTERFACE
}

do_start() {

   echo "Starting Bridge"
   for i in $INTERFACES ; do
        ip link set $i up
   done
   brctl addbr br0
   for i in $INTERFACES ; do
        ip link set $i up
        brctl addif br0 $i 
   done
   ifup $BRIDGE_INTERFACE 
}

case "$1" in
  start)
      do_start
    ;;
  stop)
      do_stop
    ;;
  restart)
      do_stop
      sleep 1
      do_start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac
exit 0</programlisting>

      <para>The <filename>/etc/sysconfig/bridge file</filename>:</para>

      <programlisting>BRIDGE_INTERFACE=br0          #The name of your Bridge
INTERFACES="eth0 eth1"        #The physical interfaces to be bridged</programlisting>
    </blockquote>

    <para>Andrzej Szelachowski contributed the following.</para>

    <blockquote>
      <programlisting>Here is how I configured bridge in Slackware:

1) I had to compile bridge-utils (It's not in the standard distribution)
2) I've created rc.bridge in /etc/rc.d:

#########################
#! /bin/sh

ifconfig eth0 0.0.0.0
ifconfig eth1 0.0.0.0
#ifconfig lo 127.0.0.1 #this line should be uncommented if you don't use rc.inet1

brctl addbr most

brctl addif most eth0
brctl addif most eth1

ifconfig most 192.168.1.31 netmask 255.255.255.0 up 
#route add default gw 192.168.1.1 metric 1 #this line should be uncommented if
                                           #you don't use rc.inet1
#########################

3) I made rc.bridge executable and added the following line to /etc/rc.d/rc.local

/etc/rc.d/rc.bridge </programlisting>
    </blockquote>

    <para>Joshua Schmidlkofer writes:</para>

    <blockquote>
      <programlisting>Bridge Setup for Gentoo

#install bridge-utils
emerge bridge-utils

## create a link for net.br0
cd /etc/init.d
ln -s net.eth0 net.br0

# Remove net.eth*, add net.br0 and bridge.
rc-update del net.eth0
rc-update del net.eth1
rc-update add net.br0 default
rc-update add bridge boot



/etc/conf.d/bridge:

  #bridge contains the name of each bridge you want created.
  bridge="br0"

  # bridge_&lt;bridge&gt;_devices contains the devices to use at bridge startup.
  bridge_br0_devices="eth0 eth1"

/etc/conf.d/net

   iface_br0="10.0.0.1     broadcast 10.0.0.255 netmask 255.255.255.0"
   #for dhcp:
   #iface_br0="dhcp"
   #comment this out if you use dhcp.
   gateway="eth0/10.0.0.1" </programlisting>
    </blockquote>

    <para>Users who successfully configure bridges on other distributions,
    with static or dynamic IP addresses, are encouraged to send <ulink
    url="mailto:webmaster@shorewall.net">me</ulink> their configuration so I
    can post it here.</para>
  </section>

  <section id="Shorewall">
    <title>Configuring Shorewall</title>

    <para>As described above, Shorewall bridge support requires the
    <firstterm>physdev match</firstterm> feature of Netfilter/iptables.
    Physdev match allows rules to be triggered based on the bridge port that a
    packet arrived on and/or the bridge port that a packet will be sent over.
    The latter has proved to be problematic because it requires that the
    evaluation of rules be deferred until the destination bridge port is
    known. This deferral has the unfortunate side effect that it makes IPSEC
    Netfilter filtration incompatible with bridges. To work around this
    problem, in kernel version 2.6.20 the Netfilter developers decided to
    remove the deferred processing in two cases:</para>

    <itemizedlist>
      <listitem>
        <para>When a packet being sent through a bridge entered the firewall
        on another interface and was being forwarded to the bridge.</para>
      </listitem>

      <listitem>
        <para>When a packet originating on the firewall itself is being sent
        through a bridge.</para>
      </listitem>
    </itemizedlist>

    <para>Notice that physdev match was only weakened with respect to the
    destination bridge port -- it remains fully functional with respect to the
    source bridge port.</para>

    <para>To deal with the asymmetric nature of the new physdev match,
    Shorewall supports a new type of zone - a <firstterm>Bridge
    Port</firstterm> (BP) zone. Bridge port zones have a number of
    restrictions:</para>

    <itemizedlist>
      <listitem>
        <para>BP zones may only be associated with bridge ports.</para>
      </listitem>

      <listitem>
        <para>All ports associated with a given BP zone must be on the same
        bridge.</para>
      </listitem>

      <listitem>
        <para>Policies from a non-BP zone to a BP are disallowed.</para>
      </listitem>

      <listitem>
        <para>Rules where the SOURCE is a non-BP zone and the DEST is a BP
        zone are disallowed.</para>
      </listitem>
    </itemizedlist>

    <para>In /etc/shorewall/zones, BP zones are specified using the <emphasis
    role="bold">bport</emphasis> (or <emphasis role="bold">bport4</emphasis>)
    keyword. If your version of <filename>shorewall.conf</filename> contains
    the <emphasis role="bold">BRIDGING</emphasis> option, it must be set to
    <emphasis role="bold">No</emphasis>.</para>

    <para>In the scenario pictured above, there would probably be two BP zones
    defined -- one for the Internet and one for the local LAN so in
    <filename>/etc/shorewall/zones</filename>:</para>

    <programlisting>#ZONE           TYPE            OPTIONS
fw              firewall
world           ipv4  
net:world       bport
loc:world       bport
#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE</programlisting>

    <para>The <emphasis>world</emphasis> zone can be used when defining rules
    whose source zone is the firewall itself (remember that fw-&gt;&lt;BP
    zone&gt; rules are not allowed).</para>

    <para>A conventional two-zone policy file is appropriate here —
    <filename>/etc/shorewall/policy</filename>:</para>

    <programlisting>#SOURCE     DEST        POLICY        LOG       LIMIT:BURST
loc         net         ACCEPT
net         all         DROP          info
all         all         REJECT        info
#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE</programlisting>

    <para>Bridges use a special syntax in
    <filename>/etc/shorewall/interfaces</filename>. Assuming that the router
    is connected to <filename class="devicefile">eth0</filename> and the
    switch to <filename class="devicefile">eth1</filename>:</para>

    <programlisting>#ZONE    INTERFACE      BROADCAST       OPTIONS
world    br0            detect          bridge
net      br0:eth0
loc      br0:eth1
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>

    <para>The <emphasis>world</emphasis> zone is associated with the bridge
    itself which is defined with the <emphasis role="bold">bridge</emphasis>
    option. Bridge port entries may not have any OPTIONS.</para>

    <note>
      <para>When a bridge is configured without an IP address, the
      <option>optional</option> option must also be specified.</para>
    </note>

    <para>When Shorewall is stopped, you want to allow only local traffic
    through the bridge —
    <filename><filename>/etc/shorewall/routestopped</filename></filename>:</para>

    <programlisting>#INTERFACE      HOST(S)         OPTIONS
br0             192.168.1.0/24  routeback
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>

    <para>The <filename>/etc/shorewall/rules</filename> file from the
    two-interface sample is a good place to start for defining a set of
    firewall rules.</para>
  </section>

  <section id="Multiple">
    <title>Multiple Bridges with Wildcard Ports</title>

    <para>It is sometimes required to configure multiple bridges on a single
    firewall/gateway. The following seemingly valid configuration results in a
    compile-time error</para>

    <simplelist>
      <member>ERROR: Duplicate Interface Name (p+)</member>
    </simplelist>

    <para><filename>/etc/shorewall/zones</filename>:</para>

    <programlisting>       #ZONE            TYPE    
       fw               firewall
       world            ipv4
       z1:world         bport4
       z2:world         bport4</programlisting>

    <para><filename>/etc/shorewall/interfaces</filename>:</para>

    <programlisting>       #ZONE            INTERFACE       BROADCAST       OPTIONS
       world            br0             -               bridge
       world            br1             -               bridge
       z1               br0:p+
       z2               br1:p+</programlisting>

    <para>The reason is that the Shorewall implementation requires each bridge
    port to have a unique name. The <option>physical</option> interface option
    was added in Shorewall 4.4.4 to work around this problem. The above
    configuration may be defined using the following in
    <filename>/etc/shorewall/interfaces</filename>:</para>

    <programlisting>       #ZONE            INTERFACE       BROADCAST       OPTIONS
       world            br0             -               bridge
       world            br1             -               bridge
       z1               br0:x+          -               physical=p+
       z2               br1:y+          -               physical=p+</programlisting>

    <para>In this configuration, 'x+' is the logical name for ports p+ on
    bridge br0 while 'y+' is the logical name for ports p+ on bridge
    br1.</para>

    <para>If you need to refer to a particular port on br1 (for example
    p1023), you write it as y1023; Shorewall will translate that name to p1023
    when needed.</para>

    <para>Example from /etc/shorewall/rules:</para>

    <programlisting>       #ACTION    SOURCE    DEST       PROTO    DEST
       #                                        PORT(S)
       REJECT     z1:x1023  z1:x1024   tcp      1234</programlisting>
  </section>

  <section id="bridge-router">
    <title>Combination Router/Bridge</title>

    <para>A system running Shorewall doesn't have to be exclusively a bridge
    or a router -- it can act as both, which is also know as a brouter. Here's
    an example:<graphic fileref="images/bridge2.png" /></para>

    <para>This is basically the same setup as shown in the <ulink
    url="shorewall_setup_guide.htm">Shorewall Setup Guide</ulink> with the
    exception that the DMZ is bridged rather than using Proxy ARP. Changes in
    the configuration shown in the Setup Guide are as follows:</para>

    <orderedlist>
      <listitem>
        <para>The <filename>/etc/shorewall/proxyarp</filename> file is empty
        in this configuration.</para>
      </listitem>

      <listitem>
        <para>The <filename>/etc/shorewall/zones</filename> file is
        modified:</para>

        <programlisting>#ZONE                   TYPE          OPTIONS
fw                      firewall
pub                     ipv4          #zone containing all public addresses
net:pub                 bport4
dmz:pub                 bport4
loc                     ipv4</programlisting>
      </listitem>

      <listitem>
        <para>The <filename>/etc/shorewall/interfaces</filename> file is as
        follows:<programlisting>#ZONE    INTERFACE      BROADCAST     OPTIONS
pub      br0            detect        routefilter,bridge
net      br0:eth0 
dmz      br0:eth2
loc      eth1           detect</programlisting></para>
      </listitem>

      <listitem>
        <para>The DMZ systems need a route to the 192.168.201.0/24 network via
        192.0.2.176 to enable them to communicate with the local
        network.</para>
      </listitem>

      <listitem>
        <para>This configuration does not support separate fw-&gt;dmz and
        fw-&gt;net policies/rules; similarly, it does not support separate
        loc-&gt;dmz and loc-&gt;net rules. This will make it a bit trickier to
        configure the rules. I suggest something like the following:</para>

        <para><filename>/etc/shorewall/params</filename>:</para>

        <programlisting>SERVERS=192.0.2.177,192.0.2.178   #IP Addresses of hosts in the DMZ
DMZ=pub:$SERVERS                  #Use in place of 'dmz' in rule DEST
NET=pub:!$SERVERS                 #Use in place of 'net' in rule DEST</programlisting>

        <para><filename>/etc/shorewall/policy</filename>:</para>

        <programlisting>#SOURCE         DEST            POLICY          LEVEL
loc             <emphasis role="bold">pub</emphasis>             ACCEPT
loc             $FW             REJECT          info
loc             all             REJECT          info

$FW             <emphasis role="bold">pub</emphasis>             REJECT          info
$FW             loc             REJECT          info
$FW             all             REJECT          info

dmz             net             REJECT          info
dmz             $FW             REJECT          info
dmz             loc             REJECT          info
dmz             all             REJECT          info

net             dmz             DROP            info
net             $FW             DROP            info
net             loc             DROP            info
net             all             DROP            info

# THE FOLLOWING POLICY MUST BE LAST
all             all             REJECT          info</programlisting>

        <para><filename>/etc/shorewall/rules</filename>:</para>

        <programlisting>#ACTION           SOURCE           DEST             PROTO            DEST             SOURCE
#
                                                                     PORT(S)          PORT(S)
ACCEPT            all              all              icmp             8
ACCEPT            loc              $DMZ             tcp              25,53,80,443,...
ACCEPT            loc              $DMZ             udp              53
ACCEPT            loc              $NET
ACCEPT            $FW              $DMZ             udp              53
ACCEPT            $FW              $DMZ             tcp              53       </programlisting>
      </listitem>
    </orderedlist>
  </section>

  <section id="veth">
    <title>Using Back-to-back veth Devices to Interface with a Bridge</title>

    <para>Beginning with Shorewall 4.4.26, Shorewall has limited support for
    using back-to-back veth devices to interface with a bridge. This approach
    has the advantage that traffic between any pair of zones can be filtered.
    The disadvantage is the complexity of the approach.</para>

    <para>This configuration is shown in the following diagram.</para>

    <graphic align="center" fileref="images/veth1.png" />

    <para>In this configuration, veth0 is assigned the internal IP address;
    br0 does not have an IP address.</para>

    <para>Traffic from the <emphasis role="bold">net</emphasis> and <emphasis
    role="bold">fw</emphasis> zones to the <emphasis
    role="bold">zone<emphasis>i</emphasis></emphasis> zones goes thru
    veth0-&gt;veth1-&gt;ethN-&gt;. Traffic from the <emphasis
    role="bold">zone<emphasis>i</emphasis></emphasis> zones to the <emphasis
    role="bold">fw</emphasis> and <emphasis role="bold">net</emphasis> zones
    takes the reverse path: ethN-&gt;veth1-&gt;veth0. As a consequence,
    traffic between <emphasis role="bold">net</emphasis>,<emphasis
    role="bold">fw</emphasis> and <emphasis
    role="bold">zone<emphasis>i</emphasis></emphasis> goes through Netfilter
    twice: once in the routed firewall (eth0,veth0) and once in the bridged
    firewall (eth1,eth2,eth3,veth1).</para>

    <para>The back-to-back veth devices (veth0 and veth1) are created using
    this command:</para>

    <programlisting>ip link add type veth</programlisting>

    <para>If you have veth devices and want to assign specific names to the
    created devices, use this format:</para>

    <programlisting>ip link add name FOO type veth peer name BAR</programlisting>

    <para>Here's an /etc/network/interfaces stanza that configures veth0,
    veth1 and the bridge:</para>

    <programlisting>auto veth0
iface veth0 inet static
      address 10.10.10.1
      netmask 255.255.255.0
      network 10.10.10.0
      broadcast 10.10.10.255
      
      pre-up /sbin/ip link add name veth0 type veth peer name veth1
      pre-up /sbin/ip link set eth1  up
      pre-up /sbin/ip link set eth2  up

      pre-up /sbin/ip link set eth3  up
      pre-up /sbin/ip link set veth1 up
      pre-up /usr/sbin/brctl addbr br0
      pre-up /usr/sbin/brctl addif br0  eth1
      pre-up /usr/sbin/brctl addif br0  eth2
      pre-up /usr/sbin/brctl addif br0  eth3
      pre-up /usr/sbin/brctl addif br0  veth1
        
      pre-down /usr/sbin/brctl delif br0 eth1
      pre-down /sbin/ip link set eth2 down
      pre-down /usr/sbin/brctl delif br0 eth2
      pre-down /sbin/ip link set eth2 down
      pre-down /usr/sbin/brctl delif br0 eth3
      pre-down /sbin/ip link set eth3 down
      pre-down /usr/sbin/brctl delif br0 veth1
      pre-down /sbin/ip link set veth1 down
        
      post-down /usr/sbin/brctl delbr br0
      post-down /sbin/ip link del veth0</programlisting>

    <para>In <ulink url="manpages/shorewall.net.html">shorewall.conf</ulink>
    (5), we need this:</para>

    <programlisting>ZONE_BITS=3</programlisting>

    <para>This does two things:</para>

    <orderedlist>
      <listitem>
        <para>It enables <firstterm>automatic packet
        marking</firstterm>.</para>
      </listitem>

      <listitem>
        <para>It allows up to 8 <replaceable>marked</replaceable> zones
        (2**3). Zones are marked unless they have <option>nomark</option> in
        the OPTIONS column of their entry in <ulink
        url="manpages/shorewall-zones.html">shorewall-zones </ulink>(5).
        Packets originating in a marked zone have a mark assigned
        automatically by Shorewall.</para>
      </listitem>
    </orderedlist>

    <para>For this configuration, we need several additional zones as shown
    here:</para>

    <programlisting>#ZONE   TYPE    OPTIONS            IN                    OUT
#                                  OPTIONS               OPTIONS
fw      firewall
net     ipv4
zone1   bport
zone2   bport
zone3   bport
<emphasis role="bold">loc     ipv4     nomark
col     ipv4     nomark</emphasis></programlisting>

    <note>
      <para><emphasis role="bold">col</emphasis> is <emphasis
      role="bold">loc</emphasis> spelled backward.</para>
    </note>

    <programlisting>#ZONE     INTERFACES        BROADCAST       OPTIONS
net       eth0              ...
-         br0               ...
zone1     br0:eth1          ...
zone2     br0:eth2          ...
zone3     br0:eth3          ...
loc       veth0             ...
col       br0:veth1         ...</programlisting>

    <para>Several things to note here</para>

    <orderedlist>
      <listitem>
        <para>We have defined two unmarked zones: <emphasis
        role="bold">loc</emphasis> and <emphasis role="bold">col</emphasis>.
        This allows traffic from the <emphasis
        role="bold">zone</emphasis><emphasis><emphasis
        role="bold">i</emphasis></emphasis> zones to the fw and net zones to
        retain the mark of their originating bport zones. It also allows
        traffic from the <emphasis role="bold">fw</emphasis> and <emphasis
        role="bold">net</emphasis> zones to the <emphasis
        role="bold">zonei</emphasis> zones to retain the <emphasis
        role="bold">fw</emphasis> and <emphasis role="bold">net</emphasis>
        marks respectively.</para>
      </listitem>

      <listitem>
        <para>That means that traffic entering the bridge on veth1 will have a
        different mark value, depending on whether it originated in the
        <emphasis role="bold">net</emphasis> zone or in the <emphasis
        role="bold">fw</emphasis> zone.</para>
      </listitem>

      <listitem>
        <para>Similarly, traffic arriving on the veth0 interface will have a
        mark that indicates which of the <emphasis
        role="bold">zonei</emphasis> zones each packet originated on.</para>
      </listitem>
    </orderedlist>

    <para>The basic idea here is that we want to filter traffic to the
    <emphasis role="bold">zonei</emphasis> zones as it leaves veth1 and we
    want to filter traffic from those zones as it leaves veth0. So we use this
    type of polices:</para>

    <programlisting>#SOURCE   DEST    POLICY
fw        loc     ACCEPT
net       loc     ACCEPT
net       all     DROP:info
zone1     col     ACCEPT
zone2     col     ACCEPT
zone3     col     ACCEPT
all       all     REJECT:info</programlisting>

    <para>Rules allowing traffic from the net to zone2 look like this:</para>

    <programlisting>#ACTION     SOURCE       DEST         PROTO  DEST    SOURCE     ORIGINAL    RATE    USER/   MARK
#                                            PORT(S) PORT(S)    DEST        LIMIT   GROUP
ACCEPT      col          zone2        tcp    22      -          -           -       -       <emphasis
        role="bold">net</emphasis></programlisting>

    <para>or more compactly:</para>

    <programlisting>#ACTION     SOURCE       DEST         PROTO  DEST
#                                            PORT(S)
ACCEPT      col          <emphasis role="bold">zone2</emphasis>        tcp    22      ; mark=<emphasis
        role="bold">net</emphasis></programlisting>

    <para>Similarly, rules allowing traffic from the firewall to zone3:</para>

    <programlisting>#ACTION     SOURCE       DEST         PROTO  DEST
#                                            PORT(S)
ACCEPT      col          <emphasis role="bold">zone3</emphasis>        tcp    22      ; mark=<emphasis
        role="bold">fw</emphasis></programlisting>

    <para>The important point here is that, when ZONE_BITS is non-zero, you
    are allowed to place zone names in the MARK column. Shorewall will
    automatically replae the name with the zone's mark value.</para>

    <para>Suppose that you want to forward tcp port 80 to 192.168.4.45 in
    zone3:</para>

    <programlisting>#ACTION     SOURCE       DEST               PROTO  DEST    SOURCE     ORIGINAL    RATE    USER/   MARK
#                                                  PORT(S) PORT(S)    DEST        LIMIT   GROUP
DNAT-       net          loc:172.168.4.45   tcp    80
ACCEPT      col          zone3:172.168.4.45 tcp    80      -          -           -       -       <emphasis
        role="bold">net</emphasis></programlisting>

    <para>Rules allowing traffic from the <emphasis
    role="bold">zonei</emphasis> zones to the <emphasis
    role="bold">net</emphasis> zone look like this: </para>

    <programlisting>#ACTION     SOURCE       DEST               PROTO  DEST    SOURCE     ORIGINAL    RATE    USER/   MARK
#                                                  PORT(S) PORT(S)    DEST        LIMIT   GROUP
ACCEPT      loc          net                tcp    21      -          -           -       -       <emphasis
        role="bold">zone1</emphasis></programlisting>

    <para>And to the firewall:</para>

    <programlisting>#ACTION     SOURCE       DEST               PROTO  DEST    SOURCE     ORIGINAL    RATE    USER/   MARK
#                                                  PORT(S) PORT(S)    DEST        LIMIT   GROUP
ACCEPT      zone2        col                tcp          -          -           -       -       <emphasis
        role="bold">zone2</emphasis></programlisting>
  </section>

  <section id="Limitations">
    <title>Limitations</title>

    <para>Bridging doesn't work with some wireless cards — see <ulink
    url="http://bridge.sf.net">http://bridge.sf.net</ulink>.</para>
  </section>
</article>