mirror of
https://gitlab.com/shorewall/code.git
synced 2024-11-27 10:03:41 +01:00
025e97c8bb
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@8670 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
1108 lines
46 KiB
XML
1108 lines
46 KiB
XML
<?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>Strong Firewall in a Routed Xen Dom0</title>
|
|
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Tom</firstname>
|
|
|
|
<surname>Eastep</surname>
|
|
</author>
|
|
</authorgroup>
|
|
|
|
<pubdate><?dbtimestamp format="Y/m/d"?></pubdate>
|
|
|
|
<copyright>
|
|
<year>2006</year>
|
|
|
|
<year>2007</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>This article applies to Shorewall 4.0 and later. If you are running
|
|
a version of Shorewall earlier than Shorewall 4.0.0 then please see the
|
|
documentation for that release.</para>
|
|
</caution>
|
|
|
|
<section id="Before">
|
|
<title>Before Xen</title>
|
|
|
|
<para>Prior to adopting Xen, I had a home office crowded with 5 systems,
|
|
three monitors a scanner and a printer. The systems were:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Firewall</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Public Server in a DMZ (mail)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Private Server (wookie)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>My personal Linux Desktop (ursa)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>My work system (docked laptop running Windows XP).</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>The result was a very crowded and noisy room.</para>
|
|
</section>
|
|
|
|
<section id="After">
|
|
<title>After Xen</title>
|
|
|
|
<para>Xen has allowed me to reduce the noise and clutter considerably. I
|
|
now have three systems with two monitors. I've also replaced the
|
|
individual printer and scanner with a Multifunction
|
|
FAX/Scanner/Printer.</para>
|
|
|
|
<para>The systems now include:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Combination Firewall/Public Server/Private Server/Wireless
|
|
Gateway using Xen (created by building out my Linux desktop system --
|
|
Now replaced by a Hewlett-Packard Pavilion a1510y).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>My work system.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>My Linux desktop (wookie, which is actually the old public
|
|
server box)</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>The Linux systems run either <trademark>OpenSuSE </trademark>10.3 or
|
|
<trademark>Ubuntu</trademark> "Gutsy Gibbon".</para>
|
|
|
|
<para>Here is a high-level diagram of our network.</para>
|
|
|
|
<graphic align="center" fileref="images/Xen5.png" />
|
|
|
|
<para>As shown in this diagram, the Xen system has three physical network
|
|
interfaces. These are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><filename class="devicefile">eth0</filename> -- connected to our
|
|
DSL "Modem".</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="devicefile">eth1</filename> -- connected to the
|
|
switch in my office.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="devicefile">eth2</filename> -- connected to a
|
|
Wireless Access Point (WAP) that interfaces to our wireless
|
|
network.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>There are three Xen domains.</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>Dom0 (DNS name <emphasis
|
|
role="bold">gateway.shorewall.net</emphasis>) is used as our main
|
|
firewall and wireless gateway as well as a local file server. It hosts
|
|
<ulink url="Shorewall_Squid_Usage.html">Squid</ulink> running as a
|
|
transparent HTTP proxy and a DHCP server that manages IP address
|
|
assignment for both the LAN and the Wireless network.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>A DomU (Domain name <emphasis role="bold">lists</emphasis>, DNS
|
|
name <emphasis role="bold">lists.shorewall.net</emphasis>) that is
|
|
used as a public Web/FTP/Mail/DNS server.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>A DomU (Domain name <emphasis role="bold">test</emphasis>, DNS
|
|
name <emphasis role="bold">test.shorewall.net</emphasis>) that I use
|
|
for Shorewall testing.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Shorewall runs in Dom0.</para>
|
|
|
|
<caution>
|
|
<para>As the developer of Shorewall, I have enough experience to be very
|
|
comfortable with Linux networking and Shorewall/iptables. I arrived at
|
|
this configuration after a fair amount of trial and error
|
|
experimentation (see <ulink url="XenMyWay.html">Xen and the art of
|
|
Consolidation</ulink>). If you are a Linux networking novice, I
|
|
recommend that you do not attempt a configuration like this one for your
|
|
first Shorewall installation. You are very likely to frustrate both
|
|
yourself and the Shorewall support team. Rather I suggest that you start
|
|
with something simple like a <ulink url="standalone.htm">standalone
|
|
installation</ulink> in a DomU; once you are comfortable with that then
|
|
you will be ready to try something more substantial.</para>
|
|
|
|
<para>As Paul Gear says: <emphasis>Shorewall might make iptables easy,
|
|
but it doesn't make understanding fundamental networking principles,
|
|
traffic shaping, or multi-ISP routing any easier</emphasis>.</para>
|
|
|
|
<para>The same goes for Xen networking.</para>
|
|
</caution>
|
|
|
|
<section id="Domains">
|
|
<title>Domain Configuration</title>
|
|
|
|
<para>Below are the relevant configuration files for the two domains. I
|
|
use a partition on my hard drives for the DomU storage device.</para>
|
|
|
|
<para>There is not much documentation about how to configure Xen for
|
|
routed operation. I've tried to mark the relevant parts with <emphasis
|
|
role="bold">bold font</emphasis>.<important>
|
|
<para>The files from <filename
|
|
class="directory">/etc/xen/auto</filename> shown below correspond to
|
|
my configuration under Xen 3.0. I'm now running Xen 3.1 which does
|
|
not use configuration files for the domains but rather keeps the
|
|
configuration in a database managed by xend. See <link
|
|
linkend="Xen3.1">below</link>.</para>
|
|
</important></para>
|
|
|
|
<blockquote>
|
|
<para><filename>/boot/grub/menu.lst</filename> — here is the entry
|
|
that boots Xen in Dom0.</para>
|
|
|
|
<blockquote>
|
|
<programlisting>title Kernel-2.6.18.8-0.1-xen
|
|
root (hd0,5)
|
|
kernel /boot/xen.gz
|
|
module /boot/vmlinuz-2.6.18.8-0.1-xen root=/dev/sda6 vga=0x31a resume=/dev/sda5 splash=silent showopts
|
|
module /boot/initrd-2.6.18.8-0.1-xen</programlisting>
|
|
</blockquote>
|
|
|
|
<para><filename>/etc/modprobe.conf.local</filename> (This may need to
|
|
go in <filename>/etc/modprobe.conf</filename> or
|
|
<filename>/etc/modprobe.d/options</filename> on your system)</para>
|
|
|
|
<para><blockquote>
|
|
<programlisting><emphasis role="bold">options netloop nloopbacks=0</emphasis> #Stop netloop from creating 8 useless vifs</programlisting>
|
|
</blockquote></para>
|
|
|
|
<para><filename>/etc/xen/auto/01-lists</filename> — configuration file
|
|
for the lists domain. Placed in <filename
|
|
class="directory">/etc/xen/auto/</filename> so it is started
|
|
automatically by Xen's <emphasis>xendomains</emphasis> service.</para>
|
|
|
|
<blockquote>
|
|
<programlisting>disk = [ 'phy:/dev/sda9,hda,w', 'phy:/dev/hda,hdb,r' ]
|
|
memory = 512
|
|
vcpus = 1
|
|
builder = 'linux'
|
|
name = 'server'
|
|
vif = [ 'mac=00:16:3e:b1:d7:90, <emphasis role="bold">ip=206.124.146.177, vifname=eth3</emphasis>' ]
|
|
localtime = 0
|
|
on_poweroff = 'destroy'
|
|
on_reboot = 'restart'
|
|
on_crash = 'restart'
|
|
extra = ' TERM=xterm'
|
|
bootloader = '/usr/lib/xen/boot/domUloader.py'
|
|
bootentry = 'hda2:/boot/vmlinuz-xen,/boot/initrd-xen'</programlisting>
|
|
|
|
<para>Note that the vifname is set to 'eth3' for the virtual
|
|
interface to this DomU. This will cause the Dom0 interface to the
|
|
server to have a fixed name (<filename
|
|
class="devicefile">eth3</filename>) which makes it a lot easier to
|
|
deal with in Shorewall and elsewhere.</para>
|
|
|
|
<para>Specifying an IP address (ip=206.124.146.177) causes the
|
|
vif-route script to create a host route to that IP address on
|
|
<filename class="devicefile">eth3</filename>.</para>
|
|
|
|
<blockquote>
|
|
<programlisting>gateway:~ # <command>ip route ls dev eth3</command>
|
|
206.124.146.177 scope link src 206.124.146.176
|
|
gateway:~ #</programlisting>
|
|
</blockquote>
|
|
|
|
<para>Note that the source for the route is 206.124.146.176. That is
|
|
the primary IP address of Dom0's <filename
|
|
class="devicefile">eth0</filename>. Xen configures <filename
|
|
class="devicefile">eth3</filename> to have that same IP
|
|
address.</para>
|
|
</blockquote>
|
|
|
|
<para><filename>/etc/xen/auto/02-test</filename> — configuration file
|
|
for the test domain.</para>
|
|
|
|
<blockquote>
|
|
<programlisting>disk = [ 'phy:/dev/hdb4,hda,w', 'phy:/dev/hda,hdb,r' ]
|
|
memory = 512
|
|
vcpus = 1
|
|
builder = 'linux'
|
|
name = 'test'
|
|
vif = [ 'mac=00:16:3e:83:ad:28, <emphasis role="bold">ip=192.168.1.7</emphasis>, <emphasis
|
|
role="bold">vifname=eth4</emphasis>' ]
|
|
localtime = 0
|
|
on_poweroff = 'destroy'
|
|
on_reboot = 'restart'
|
|
on_crash = 'restart'
|
|
extra = ' TERM=xterm'
|
|
bootloader = '/usr/lib/xen/boot/domUloader.py'
|
|
bootentry = 'hda2:/boot/vmlinuz-xen,/boot/initrd-xen'
|
|
</programlisting>
|
|
</blockquote>
|
|
|
|
<para>Excerpt from
|
|
<filename>/etc/xen/xend-config.sxp</filename>:<blockquote>
|
|
<programlisting>…
|
|
|
|
# It is possible to use the network-bridge script in more complicated
|
|
# scenarios, such as having two outgoing interfaces, with two bridges, and
|
|
# two fake interfaces per guest domain. To do things like this, write
|
|
# yourself a wrapper script, and call network-bridge from it, as appropriate.
|
|
#
|
|
<emphasis role="bold">#</emphasis>(network-script network-bridge)
|
|
|
|
…
|
|
|
|
# If you are using only one bridge, the vif-bridge script will discover that,
|
|
# so there is no need to specify it explicitly.
|
|
#
|
|
<emphasis role="bold">#</emphasis>(vif-script vif-bridge)
|
|
|
|
## Use the following if network traffic is routed, as an alternative to the
|
|
# settings for bridged networking given above.
|
|
<emphasis role="bold">(network-script network-route)
|
|
(vif-script vif-route)</emphasis>
|
|
</programlisting>
|
|
|
|
<important>
|
|
<para>As of this writing, the vif-route script does not set up
|
|
Proxy ARP correctly. So the domU can communicate with the dom0
|
|
but not with hosts beyond the dom0.</para>
|
|
|
|
<para>If you configure Shorewall as described below, Shorewall
|
|
will correct the Proxy ARP configuration so that it will
|
|
work.</para>
|
|
</important>
|
|
</blockquote></para>
|
|
</blockquote>
|
|
|
|
<para id="Xen3.1">Instructions for editing entries in the Xen 3.1 xend
|
|
database may be found at <ulink
|
|
url="http://www.novell.com/documentation/vmserver/config_options/index.html?page=/documentation/vmserver/config_options/data/b8uh3zr.html">http://www.novell.com/documentation/vmserver/config_options/index.html?page=/documentation/vmserver/config_options/data/b8uh3zr.html</ulink>,
|
|
The following are excerpts from the XML representations of the two user
|
|
domains (produced by "xm list -l …").</para>
|
|
|
|
<para>lists domain:<blockquote>
|
|
<para><programlisting>…
|
|
(features )
|
|
<emphasis role="bold"> (on_xend_start start)
|
|
(on_xend_stop shutdown)</emphasis>
|
|
(start_time 1194710550.49)
|
|
…
|
|
(console_mfn 397179)
|
|
(device
|
|
(vif
|
|
<emphasis role="bold"> (mac 00:16:3e:b1:d7:90)
|
|
(script vif-route)
|
|
(ip 206.124.146.177)
|
|
(vifname eth3)</emphasis>
|
|
(type netfront)
|
|
(devid 0)
|
|
(uuid 55676385-7b69-09fd-4027-751b692ead75)
|
|
)
|
|
)
|
|
(device
|
|
(vbd
|
|
…</programlisting></para>
|
|
</blockquote></para>
|
|
|
|
<para>test domain:<blockquote>
|
|
<para><programlisting>…
|
|
(console_mfn 418003)
|
|
(device
|
|
(vif
|
|
(uuid 64a1dd48-fa8b-7561-e90b-cd589cbeb7fa)
|
|
<emphasis role="bold"> (script vif-route)
|
|
(ip 192.168.1.7)
|
|
(mac 00:16:3e:83:ad:28)
|
|
(vifname eth4)
|
|
</emphasis> (devid 0)
|
|
(type netfront)
|
|
(backend 0)
|
|
)
|
|
)
|
|
(device
|
|
(vbd
|
|
…</programlisting></para>
|
|
</blockquote></para>
|
|
|
|
<para>With the three Xen domains up and running, the system looks as
|
|
shown in the following diagram.</para>
|
|
|
|
<graphic align="center" fileref="images/Xen4a.png" />
|
|
|
|
<para>The zones correspond to the Shorewall zones in the Dom0
|
|
configuration.</para>
|
|
|
|
<para>Readers who are paying attention will notice that eth4 has the
|
|
same public IP address (206.124.146.176) as eth0 (and eth3), yet the
|
|
<emphasis role="bold">test</emphasis> system connected to that interface
|
|
has an RFC 1918 address (192.168.1.7). That configuration is established
|
|
by Xen which clones the primary IP address of eth0 on all of the routed
|
|
virtual interfaces that it creates. <emphasis
|
|
role="bold">test</emphasis> is configured with it's default route via
|
|
192.168.1.254 which is the IP address of the firewall's br0. That works
|
|
because of the way that the Linux network stack treats local IPv4
|
|
addresses; by default, it will respond to ARP "who-has" broadcasts for
|
|
any local address and not just for the addresses on the interface that
|
|
received the broadcast (but of course the MAC address returned in the
|
|
"here-is" response is that of the interface that received the
|
|
broadcast). So when <emphasis role="bold">test</emphasis> broadcasts
|
|
"who-has 192.168.1.254", the firewall responds with "here-is
|
|
192.168.1.254 00:16:3e:83:ad:28" (00:16:3e:83:ad:28 is the MAC of
|
|
virtual interface eth4).</para>
|
|
|
|
<caution>
|
|
<para>Under some circumstances, UDP and/or TCP communication from a
|
|
DomU won't work for no obvious reason. That happened with the
|
|
<emphasis role="bold">lists</emphasis> domain in my setup. Looking at
|
|
the IP traffic with <command>tcpdump -nvvi eth1</command> in Dom0
|
|
showed that UDP packets from the <emphasis
|
|
role="bold">lists</emphasis> DomU had incorrect checksums. That
|
|
problem was corrected by arranging for the following command to be
|
|
executed in the <emphasis role="bold">lists</emphasis> and <emphasis
|
|
role="bold">test</emphasis> domains when the <filename
|
|
class="devicefile">eth0</filename> device was brought up:</para>
|
|
|
|
<para><command>ethtool -K eth0 tx off</command></para>
|
|
|
|
<para>Under <trademark>OpenSuSE</trademark> 10.2, I placed the
|
|
following in
|
|
<filename><filename>/etc/sysconfig/network/ifcfg-eth-id-00:16:3e:b1:d7:90</filename></filename>
|
|
(the config file for eth0):</para>
|
|
|
|
<programlisting>ETHTOOL_OPTIONS='-K iface tx off'</programlisting>
|
|
|
|
<para>Under other distributions, the technique will vary. For example,
|
|
under <trademark>Debian</trademark> or <trademark>Ubuntu</trademark>,
|
|
you can just add a 'post-up' entry to
|
|
<filename>/etc/network/interfaces</filename> as shown here:</para>
|
|
|
|
<programlisting> iface eth0 inet static
|
|
address 206.124.146.177
|
|
netmask 255.255.255.0
|
|
<emphasis role="bold">post-up ethtool -K eth0 tx off</emphasis></programlisting>
|
|
</caution>
|
|
|
|
<caution>
|
|
<para>Update. Under OpenSuSE 10.2, communication from a domU works
|
|
okay without running ethtool <emphasis role="bold">but traffic shaping
|
|
in dom0 doesn't work!</emphasis> So it's a good idea to run it just to
|
|
be safe.</para>
|
|
</caution>
|
|
</section>
|
|
|
|
<section id="Firewall">
|
|
<title>Dom0 Shorewall Configuration</title>
|
|
|
|
<para>In Dom0, I run a conventional three-interface firewall with Proxy
|
|
ARP DMZ -- it is very similar to the firewall described in the <ulink
|
|
url="shorewall_setup_guide.htm">Shorewall Setup Guide</ulink> with the
|
|
exception that I've added a fourth interface for our wireless network.
|
|
The firewall runs a routed <ulink url="OPENVPN.html">OpenVPN
|
|
server</ulink> to provide road warrior access for our three laptops and a
|
|
bridged OpenVPN server for the wireless network in our home. Here is the
|
|
firewall's view of the network:</para>
|
|
|
|
<graphic align="center" fileref="images/network4a.png" />
|
|
|
|
<para>The three laptops can be directly attached to the LAN as shown
|
|
above or they can be attached wirelessly -- their IP addresses are the
|
|
same in either case; when they are directly attached, the IP address is
|
|
assigned by the DHCP server running in Dom0 and when they are attached
|
|
wirelessly, the IP address is assigned by OpenVPN.</para>
|
|
|
|
<para>The Shorewall configuration files are shown below. All routing and
|
|
secondary IP addresses are handled in the OpenSuSE network
|
|
configuration.</para>
|
|
|
|
<blockquote>
|
|
<para>/etc/shorewall/shorewall.conf</para>
|
|
|
|
<programlisting>STARTUP_ENABLED=Yes
|
|
VERBOSITY=0
|
|
SHOREWALL_COMPILER=perl
|
|
LOGFILE=/var/log/firewall
|
|
LOGFORMAT="Shorewall:%s:%s:"
|
|
LOGTAGONLY=No
|
|
LOGRATE=
|
|
LOGBURST=
|
|
LOGALLNEW=
|
|
BLACKLIST_LOGLEVEL=
|
|
MACLIST_LOG_LEVEL=$LOG
|
|
TCP_FLAGS_LOG_LEVEL=$LOG
|
|
RFC1918_LOG_LEVEL=
|
|
SMURF_LOG_LEVEL=$LOG
|
|
LOG_MARTIANS=No
|
|
IPTABLES=
|
|
SHOREWALL_SHELL=/bin/ash
|
|
SUBSYSLOCK=/var/lock/subsys/shorewall
|
|
MODULESDIR=
|
|
CONFIG_PATH=/etc/shorewall:/usr/share/shorewall
|
|
RESTOREFILE=
|
|
IPSECFILE=zones
|
|
LOCKFILE=
|
|
DROP_DEFAULT="Drop"
|
|
REJECT_DEFAULT="Reject"
|
|
ACCEPT_DEFAULT="none"
|
|
QUEUE_DEFAULT="none"
|
|
IP_FORWARDING=Yes
|
|
ADD_IP_ALIASES=No
|
|
ADD_SNAT_ALIASES=No
|
|
RETAIN_ALIASES=No
|
|
TC_ENABLED=internal
|
|
TC_EXPERT=No
|
|
CLEAR_TC=Yes
|
|
MARK_IN_FORWARD_CHAIN=Yes
|
|
CLAMPMSS=Yes
|
|
ROUTE_FILTER=No
|
|
DETECT_DNAT_IPADDRS=Yes
|
|
MUTEX_TIMEOUT=60
|
|
ADMINISABSENTMINDED=Yes
|
|
BLACKLISTNEWONLY=Yes
|
|
DELAYBLACKLISTLOAD=No
|
|
MODULE_SUFFIX=
|
|
DISABLE_IPV6=Yes
|
|
BRIDGING=No
|
|
DYNAMIC_ZONES=No
|
|
PKTTYPE=No
|
|
RFC1918_STRICT=Yes
|
|
MACLIST_TABLE=mangle
|
|
MACLIST_TTL=60
|
|
SAVE_IPSETS=No
|
|
MAPOLDACTIONS=No
|
|
FASTACCEPT=Yes
|
|
IMPLICIT_CONTINUE=Yes
|
|
HIGH_ROUTE_MARKS=Yes
|
|
USE_ACTIONS=Yes
|
|
OPTIMIZE=1
|
|
EXPORTPARAMS=No
|
|
EXPAND_POLICIES=Yes
|
|
KEEP_RT_TABLES=No
|
|
DELETE_THEN_ADD=No
|
|
BLACKLIST_DISPOSITION=DROP
|
|
MACLIST_DISPOSITION=DROP
|
|
TCP_FLAGS_DISPOSITION=DROP</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/zones</filename>:</para>
|
|
|
|
<programlisting>#ZONE TYPE OPTIONS IN OUT
|
|
# OPTIONS OPTIONS
|
|
fw firewall #The firewall itself.
|
|
net ipv4 #Internet
|
|
loc ipv4 #Local wired Zone
|
|
dmz ipv4 #DMZ
|
|
vpn ipv4 #Open VPN clients
|
|
wifi ipv4 #Local Wireless Zone
|
|
#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE
|
|
</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/policy</filename>:</para>
|
|
|
|
<programlisting>#SOURCE DEST POLICY LOG LIMIT:BURST
|
|
# LEVEL
|
|
$FW $FW ACCEPT
|
|
$FW net ACCEPT
|
|
loc net ACCEPT
|
|
$FW vpn ACCEPT
|
|
vpn net ACCEPT
|
|
vpn loc ACCEPT
|
|
loc vpn ACCEPT
|
|
$FW loc ACCEPT
|
|
loc $FW ACCEPT
|
|
wifi all REJECT $LOG
|
|
net $FW DROP $LOG 1/sec:2
|
|
net loc DROP $LOG 2/sec:4
|
|
net dmz DROP $LOG 8/sec:30
|
|
net vpn DROP $LOG
|
|
all all REJECT $LOG
|
|
#LAST LINE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>Note that the firewall<->local network interface
|
|
is wide open so from a security point of view, the firewall system is
|
|
part of the local zone.</filename></para>
|
|
|
|
<para><filename>/etc/shorewall/params (edited)</filename>:</para>
|
|
|
|
<programlisting>MIRRORS=<comma-separated list of Shorewall mirrors>
|
|
|
|
NTPSERVERS=<comma-separated list of NTP servers I sync with>
|
|
|
|
POPSERVERS=<comma-separated list of server IP addresses>
|
|
|
|
LOG=info
|
|
|
|
INT_IF=br0
|
|
DMZ_IF=eth3
|
|
EXT_IF=eth0
|
|
WIFI_IF=eth2
|
|
TEST_IF=eth4
|
|
|
|
OMAK=<IP address at our second home>
|
|
|
|
#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/init</filename>:</para>
|
|
|
|
<programlisting>echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/interfaces</filename> (don't specify
|
|
the BROADCAST addresses if you are using Shorewall-perl):</para>
|
|
|
|
<programlisting>#ZONE INTERFACE BROADCAST OPTIONS
|
|
net ${EXT_IF} detect dhcp,logmartians=1,blacklist
|
|
dmz $DMZ_IF detect logmartians=1
|
|
loc $INT_IF detect dhcp,logmartians=1,routeback,bridge
|
|
loc $TEST_IF detect optional
|
|
loc $TEST1_IF detect optional
|
|
wifi $WIFI_IF detect dhcp,maclist,mss=1400
|
|
vpn tun+ -
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/nat</filename>:</para>
|
|
|
|
<programlisting>#EXTERNAL INTERFACE INTERNAL ALL LOCAL
|
|
# INTERFACES
|
|
COMMENT One-to-one NAT
|
|
206.124.146.178 $EXT_IF:0 192.168.1.3 No No
|
|
206.124.146.180 $EXT_IF:2 192.168.1.6 No No
|
|
#LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/masq (Note the cute trick here and in
|
|
the <filename>following proxyarp</filename> file that allows me to
|
|
access the DSL "Modem" using its default IP address
|
|
(192.168.1.1))</filename>. The leading "+" is required to place the
|
|
rule before the SNAT rules generated by entries in
|
|
<filename>/etc/shorewall/nat</filename> above.</para>
|
|
|
|
<programlisting>#INTERFACE SOURCE ADDRESS PROTO PORT(S) IPSEC
|
|
COMMENT Handle DSL 'Modem'
|
|
|
|
+$EXT_IF:192.168.1.1 0.0.0.0/0 192.168.1.254
|
|
|
|
COMMENT Masquerade VPN clients and Wifi
|
|
|
|
$EXT_IF 192.168.2.0/24
|
|
$EXT_IF 192.168.3.0/24
|
|
|
|
$EXT_IF:192.168.98.1 192.168.99.1 192.168.1.99
|
|
$EXT_IF:192.168.99.1 192.168.98.1 192.168.1.98
|
|
|
|
COMMENT Masquerade Local Network
|
|
|
|
$EXT_IF $INT_IF 206.124.146.179
|
|
#LAST LINE -- ADD YOUR ENTRIES ABOVE THIS LINE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/proxyarp</filename>:</para>
|
|
|
|
<programlisting>#ADDRESS INTERFACE EXTERNAL HAVEROUTE PERSISTENT
|
|
192.168.1.1 $EXT_IF $INT_IF yes
|
|
206.124.146.177 $DMZ_IF $EXT_IF yes
|
|
192.168.1.7 $TEST_IF $INT_IF yes
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/tunnels</filename>:</para>
|
|
|
|
<programlisting>#TYPE ZONE GATEWAY GATEWAY
|
|
# ZONE
|
|
openvpnserver:udp net 0.0.0.0/0 #Routed server for RoadWarrior access
|
|
openvpnserver:udp wifi 192.168.3.0/24 #Home wireless network server
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/blacklist</filename>:</para>
|
|
|
|
<programlisting>#ADDRESS/SUBNET PROTOCOL PORT
|
|
- udp 1024:1033,1434
|
|
- tcp 57,1433,1434,2401,2745,3127,3306,3410,4899,5554,6101,8081,9898
|
|
#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/actions</filename>:</para>
|
|
|
|
<programlisting>#ACTION
|
|
Mirrors # Accept traffic from Shorewall Mirrors
|
|
#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/action.Mirrors</filename>:</para>
|
|
|
|
<programlisting>#TARGET SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE
|
|
# PORT PORT(S) DEST LIMIT
|
|
ACCEPT $MIRRORS
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/rules</filename>:</para>
|
|
|
|
<programlisting>SECTION NEW
|
|
###############################################################################################################################################################################
|
|
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/
|
|
# PORT PORT(S) DEST LIMIT GROUP
|
|
###############################################################################################################################################################################
|
|
REJECT:$LOG loc net tcp 25
|
|
REJECT:$LOG loc net udp 1025:1031
|
|
#
|
|
# Stop NETBIOS crap
|
|
#
|
|
REJECT loc net tcp 137,445
|
|
REJECT loc net udp 137:139
|
|
#
|
|
# Stop my idiotic work laptop from sending to the net with an HP source/dest IP address
|
|
#
|
|
DROP loc:!192.168.0.0/22 net
|
|
###############################################################################################################################################################################
|
|
# Local Network to Firewall
|
|
#
|
|
REDIRECT- loc 3128 tcp 80 - !192.168.1.1,192.168.0.7,206.124.146.177,155.98.64.80
|
|
###############################################################################################################################################################################
|
|
# Road Warriors to Firewall
|
|
#
|
|
ACCEPT vpn fw tcp ssh,time,631,8080
|
|
ACCEPT vpn fw udp 161,ntp,631
|
|
Ping/ACCEPT vpn fw
|
|
###############################################################################################################################################################################
|
|
# Road Warriors to DMZ
|
|
#
|
|
ACCEPT vpn dmz udp domain
|
|
ACCEPT vpn dmz tcp www,smtp,smtps,domain,ssh,imap,https,imaps,ftp,10023,pop3 -
|
|
Ping/ACCEPT vpn dmz
|
|
###############################################################################################################################################################################
|
|
# Local network to DMZ
|
|
#
|
|
ACCEPT loc dmz udp domain
|
|
ACCEPT loc dmz tcp ssh,smtps,www,ftp,imaps,domain,https -
|
|
ACCEPT loc dmz tcp smtp
|
|
Trcrt/ACCEPT loc dmz
|
|
###############################################################################################################################################################################
|
|
# Internet to ALL -- drop NewNotSyn packets
|
|
#
|
|
dropNotSyn net fw tcp
|
|
#dropNotSyn net loc tcp
|
|
dropNotSyn net dmz tcp
|
|
###############################################################################################################################################################################
|
|
# Internet to DMZ
|
|
#
|
|
ACCEPT net dmz udp domain
|
|
LOG:$LOG net:64.126.128.0/18 dmz tcp smtp
|
|
ACCEPT net dmz tcp smtps,www,ftp,imaps,domain,https -
|
|
ACCEPT net dmz tcp smtp - 206.124.146.177,206.124.146.178
|
|
ACCEPT net dmz udp 33434:33454
|
|
Mirrors net dmz tcp rsync
|
|
Limit:$LOG:SSHA,3,60\
|
|
net dmz tcp 22
|
|
Trcrt/ACCEPT net dmz
|
|
##############################################################################################################################################################################
|
|
#
|
|
# Net to Local
|
|
#
|
|
# When I'm "on the road", the following two rules allow me VPN access back home using PPTP.
|
|
#
|
|
DNAT net loc:192.168.1.4 tcp 1729
|
|
DNAT net loc:192.168.1.4 gre
|
|
#
|
|
# Roadwarrior access to Ursa
|
|
#
|
|
ACCEPT net:$OMAK loc tcp 22
|
|
Limit:$LOG:SSHA,3,60\
|
|
net loc tcp 22
|
|
|
|
#
|
|
# ICQ
|
|
#
|
|
ACCEPT net loc:192.168.1.3 tcp 113,4000:4100
|
|
#
|
|
# Bittorrent
|
|
#
|
|
ACCEPT net loc:192.168.1.3 tcp 6881:6889,6969
|
|
ACCEPT net loc:192.168.1.3 udp 6881:6889,6969
|
|
#
|
|
# Real Audio
|
|
#
|
|
ACCEPT net loc:192.168.1.3 udp 6970:7170
|
|
#
|
|
# Overnet
|
|
#
|
|
#ACCEPT net loc:192.168.1.3 tcp 4662
|
|
#ACCEPT net loc:192.168.1.3 udp 12112
|
|
#
|
|
# OpenVPN
|
|
#
|
|
ACCEPT net loc:192.168.1.3 udp 1194
|
|
ACCEPT net loc:192.168.1.6 udp 1194
|
|
# Skype
|
|
#
|
|
ACCEPT net loc:192.168.1.6 tcp 1194
|
|
#
|
|
# Traceroute
|
|
#
|
|
Trcrt/ACCEPT net loc:192.168.1.3
|
|
#
|
|
# Silently Handle common probes
|
|
#
|
|
REJECT net loc tcp www,ftp,https
|
|
DROP net loc icmp 8
|
|
###############################################################################################################################################################################
|
|
# DMZ to Internet
|
|
#
|
|
ACCEPT dmz net udp domain,ntp
|
|
ACCEPT dmz net tcp echo,ftp,ssh,smtp,whois,domain,www,81,https,cvspserver,2702,2703,8080
|
|
ACCEPT dmz net:$POPSERVERS tcp pop3
|
|
Ping/ACCEPT dmz net
|
|
#
|
|
# Some FTP clients seem prone to sending the PORT command split over two packets. This prevents the FTP connection tracking
|
|
# code from processing the command and setting up the proper expectation. The following rule allows active FTP to work in these cases
|
|
# but logs the connection so I can keep an eye on this potential security hole.
|
|
#
|
|
ACCEPT:$LOG dmz net tcp 1024: 20
|
|
###############################################################################################################################################################################
|
|
# Local to DMZ
|
|
#
|
|
ACCEPT loc dmz udp domain,xdmcp
|
|
ACCEPT loc dmz tcp www,smtp,smtps,domain,ssh,imap,rsync,https,imaps,ftp,10023,pop3,3128
|
|
Trcrt/ACCEPT loc dmz
|
|
###############################################################################################################################################################################
|
|
# DMZ to Local
|
|
#
|
|
ACCEPT dmz loc:192.168.1.5 udp 123
|
|
ACCEPT dmz loc:192.168.1.5 tcp 21
|
|
Ping/ACCEPT dmz loc
|
|
|
|
###############################################################################################################################################################################
|
|
# DMZ to Firewall -- ntp & snmp, Silently reject Auth
|
|
#
|
|
#ACCEPT net loc:192.168.1.3 udp 12112
|
|
#
|
|
# OpenVPN
|
|
#
|
|
ACCEPT net loc:192.168.1.3 udp 1194
|
|
ACCEPT net loc:192.168.1.6 udp 1194
|
|
# Skype
|
|
#
|
|
ACCEPT net loc:192.168.1.6 tcp 1194
|
|
#
|
|
# Traceroute
|
|
#
|
|
Trcrt/ACCEPT net loc:192.168.1.3
|
|
#
|
|
# Silently Handle common probes
|
|
#
|
|
REJECT net loc tcp www,ftp,https
|
|
DROP net loc icmp 8
|
|
###############################################################################################################################################################################
|
|
# DMZ to Internet
|
|
#
|
|
ACCEPT dmz net udp domain,ntp
|
|
ACCEPT dmz net tcp echo,ftp,ssh,smtp,whois,domain,www,81,https,cvspserver,2702,2703,8080
|
|
ACCEPT dmz net:$POPSERVERS tcp pop3
|
|
Ping/ACCEPT dmz net
|
|
#
|
|
# Some FTP clients seem prone to sending the PORT command split over two packets. This prevents the FTP connection tracking
|
|
# code from processing the command and setting up the proper expectation. The following rule allows active FTP to work in these cases
|
|
# but logs the connection so I can keep an eye on this potential security hole.
|
|
#
|
|
ACCEPT:$LOG dmz net tcp 1024: 20
|
|
###############################################################################################################################################################################
|
|
# Local to DMZ
|
|
#
|
|
ACCEPT loc dmz udp domain,xdmcp
|
|
ACCEPT loc dmz tcp www,smtp,smtps,domain,ssh,imap,rsync,https,imaps,ftp,10023,pop3,3128
|
|
Trcrt/ACCEPT loc dmz
|
|
###############################################################################################################################################################################
|
|
# DMZ to Local
|
|
#
|
|
ACCEPT dmz loc:192.168.1.5 udp 123
|
|
ACCEPT dmz loc:192.168.1.5 tcp 21
|
|
Ping/ACCEPT dmz loc
|
|
|
|
###############################################################################################################################################################################
|
|
# DMZ to Firewall -- ntp & snmp, Silently reject Auth
|
|
#
|
|
ACCEPT loc dmz udp domain,xdmcp
|
|
ACCEPT loc dmz tcp www,smtp,smtps,domain,ssh,imap,rsync,https,imaps,ftp,10023,pop3,3128
|
|
Trcrt/ACCEPT loc dmz
|
|
###############################################################################################################################################################################
|
|
# DMZ to Local
|
|
#
|
|
ACCEPT dmz loc:192.168.1.5 udp 123
|
|
ACCEPT dmz loc:192.168.1.5 tcp 21
|
|
Ping/ACCEPT dmz loc
|
|
|
|
###############################################################################################################################################################################
|
|
# DMZ to Firewall -- ntp & snmp, Silently reject Auth
|
|
#
|
|
ACCEPT dmz fw tcp 161,ssh
|
|
ACCEPT dmz fw udp 161,ntp
|
|
REJECT dmz fw tcp auth
|
|
Ping/ACCEPT dmz fw
|
|
###############################################################################################################################################################################
|
|
# Internet to Firewall
|
|
#
|
|
REJECT net fw tcp www,ftp,https
|
|
DROP net fw icmp 8
|
|
ACCEPT net fw udp 33434:33454
|
|
ACCEPT net:$OMAK fw udp ntp
|
|
ACCEPT net fw tcp auth
|
|
ACCEPT net:$OMAK fw tcp 22
|
|
Limit:$LOG:SSHA,3,60\
|
|
net fw tcp 22
|
|
Trcrt/ACCEPT net fw
|
|
#
|
|
# Bittorrent
|
|
#
|
|
ACCEPT net fw tcp 6881:6889,6969
|
|
ACCEPT net fw udp 6881:6889,6969
|
|
###############################################################################################################################################################################
|
|
# Firewall to DMZ
|
|
#
|
|
ACCEPT fw dmz tcp domain,www,ftp,ssh,smtp,https,993,465
|
|
ACCEPT fw dmz udp domain
|
|
REJECT fw dmz udp 137:139
|
|
Ping/ACCEPT fw dmz
|
|
##############################################################################################################################################################################
|
|
# Avoid logging Freenode.net probes
|
|
#
|
|
DROP net:82.96.96.3 all
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/tcdevices</filename></para>
|
|
|
|
<programlisting>#INTERFACE IN-BANDWITH OUT-BANDWIDTH
|
|
$EXT_IF 1300kbit 384kbit
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE
|
|
</programlisting>
|
|
|
|
<para><filename>/etc/shorewall/tcclasses</filename><programlisting>#INTERFACE MARK RATE CEIL PRIORITY OPTIONS
|
|
$EXT_IF 10 5*full/10 full 1 tcp-ack,tos-minimize-delay
|
|
$EXT_IF 20 3*full/10 9*full/10 2 default
|
|
$EXT_IF 30 2*full/10 6*full/10 3
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting></para>
|
|
|
|
<para><filename>/etc/shorewall/tcrules</filename><programlisting>#MARK SOURCE DEST PROTO PORT(S) CLIENT USER TEST
|
|
# PORT(S)
|
|
1:110 192.168.0.0/22 $EXT_IF #Our internal nets get priority
|
|
#over the server
|
|
1:130 206.124.146.177 $EXT_IF tcp - 873 #Throttle rsync traffic to the
|
|
#Shorewall Mirrors.
|
|
#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE</programlisting></para>
|
|
</blockquote>
|
|
|
|
<para>The <filename class="devicefile">tap0</filename> device used by
|
|
the bridged OpenVPN server is created and bridged to <filename
|
|
class="devicefile">eth1</filename> using a SUSE-specific SysV init
|
|
script:</para>
|
|
|
|
<blockquote>
|
|
<programlisting>#!/bin/sh
|
|
#
|
|
# The Shoreline Firewall (Shorewall) Packet Filtering Firewall - V3.0
|
|
#
|
|
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
#
|
|
# (c) 1999,2000,2001,2002,2003,2004,2005 - Tom Eastep (teastep@shorewall.net)
|
|
#
|
|
# On most distributions, this file should be called /etc/init.d/shorewall.
|
|
#
|
|
# Complete documentation is available at http://shorewall.net
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of Version 2 of the GNU General Public License
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
# If an error occurs while starting or restarting the firewall, the
|
|
# firewall is automatically stopped.
|
|
#
|
|
# Commands are:
|
|
#
|
|
# bridge start Starts the bridge
|
|
# bridge restart Restarts the bridge
|
|
# bridge reload Restarts the bridge
|
|
# bridge stop Stops the bridge
|
|
# bridge status Displays bridge status
|
|
#
|
|
|
|
# chkconfig: 2345 4 99
|
|
# description: Packet filtering firewall
|
|
|
|
### BEGIN INIT INFO
|
|
# Provides: bridge
|
|
# Required-Start: boot.udev
|
|
# Required-Stop:
|
|
# Default-Start: 2 3 5
|
|
# Default-Stop: 0 1 6
|
|
# Description: starts and stops the bridge
|
|
### END INIT INFO
|
|
|
|
################################################################################
|
|
# Interfaces to be bridged -- may be listed by device name or by MAC
|
|
#
|
|
INTERFACES="eth1"
|
|
|
|
#
|
|
# Tap Devices
|
|
#
|
|
TAPS="tap0"
|
|
|
|
################################################################################
|
|
# Give Usage Information #
|
|
################################################################################
|
|
usage() {
|
|
echo "Usage: $0 start|stop|reload|restart|status"
|
|
exit 1
|
|
}
|
|
#################################################################################
|
|
# Find the interface with the passed MAC address
|
|
#################################################################################
|
|
find_interface_by_mac() {
|
|
local mac
|
|
mac=$1
|
|
local first
|
|
local second
|
|
local rest
|
|
local dev
|
|
|
|
/sbin/ip link ls | while read first second rest; do
|
|
case $first in
|
|
*:)
|
|
dev=$second
|
|
;;
|
|
*)
|
|
if [ "$second" = $mac ]; then
|
|
echo ${dev%:}
|
|
return
|
|
fi
|
|
esac
|
|
done
|
|
}
|
|
################################################################################
|
|
# Convert MAC addresses to interface names
|
|
################################################################################
|
|
get_interfaces() {
|
|
local interfaces
|
|
interfaces=
|
|
local interface
|
|
|
|
for interface in $INTERFACES; do
|
|
case $interface in
|
|
*:*:*)
|
|
interface=$(find_interface_by_mac $interface)
|
|
[ -n "$interface" ] || echo "WARNING: Can't find an interface with MAC address $mac"
|
|
;;
|
|
esac
|
|
interfaces="$interfaces $interface"
|
|
done
|
|
|
|
INTERFACES="$interfaces"
|
|
}
|
|
################################################################################
|
|
# Start the Bridge
|
|
################################################################################
|
|
do_start()
|
|
{
|
|
local interface
|
|
|
|
get_interfaces
|
|
|
|
for interface in $TAPS; do
|
|
/usr/sbin/openvpn --mktun --dev $interface
|
|
done
|
|
|
|
/sbin/brctl addbr br0
|
|
|
|
for interface in $INTERFACES $TAPS; do
|
|
/sbin/ip link set $interface up
|
|
/sbin/brctl addif br0 $interface
|
|
done
|
|
}
|
|
################################################################################
|
|
# Stop the Bridge
|
|
################################################################################
|
|
do_stop()
|
|
{
|
|
local interface
|
|
|
|
get_interfaces
|
|
|
|
for interface in $INTERFACES $TAPS; do
|
|
/sbin/brctl delif br0 $interface
|
|
/sbin/ip link set $interface down
|
|
done
|
|
|
|
/sbin/ip link set br0 down
|
|
|
|
/sbin/brctl delbr br0
|
|
|
|
for interface in $TAPS; do
|
|
/usr/sbin/openvpn --rmtun --dev $interface
|
|
done
|
|
}
|
|
################################################################################
|
|
# E X E C U T I O N B E G I N S H E R E #
|
|
################################################################################
|
|
command="$1"
|
|
|
|
case "$command" in
|
|
start)
|
|
do_start
|
|
;;
|
|
stop)
|
|
do_stop
|
|
;;
|
|
restart|reload)
|
|
do_stop
|
|
do_start
|
|
;;
|
|
status)
|
|
/sbin/brctl show
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|
|
</programlisting>
|
|
</blockquote>
|
|
</section>
|
|
</section>
|
|
</article>
|