mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-04 21:41:15 +01:00
ef0253905a
Signed-off-by: Tom Eastep <teastep@shorewall.net>
341 lines
15 KiB
XML
341 lines
15 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="ProxyARP">
|
|
<!--$Id$-->
|
|
|
|
<articleinfo>
|
|
<title>Proxy ARP</title>
|
|
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Tom</firstname>
|
|
|
|
<surname>Eastep</surname>
|
|
</author>
|
|
</authorgroup>
|
|
|
|
<pubdate><?dbtimestamp format="Y/m/d"?></pubdate>
|
|
|
|
<copyright>
|
|
<year>2001-2006</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>
|
|
|
|
<section>
|
|
<title>Overview</title>
|
|
|
|
<para>Proxy ARP (RFC 1027) is a way to make a machine physically located
|
|
on one network appear to be logically part of a different physical network
|
|
connected to the same router/firewall. Typically it allows us to hide a
|
|
machine with a public IP address on a private network behind a router, and
|
|
still have the machine appear to be on the public network "in front of"
|
|
the router. The router "proxys" ARP requests and all network traffic to
|
|
and from the hidden machine to make this fiction possible.</para>
|
|
|
|
<para>Consider a router with two interface cards, one connected to a
|
|
public network PUBNET and one connected to a private network PRIVNET. We
|
|
want to hide a server machine on the PRIVNET network but have it
|
|
accessible from the PUBNET network. The IP address of the server machine
|
|
lies in the PUBNET network, even though we are placing the machine on the
|
|
PRIVNET network behind the router.</para>
|
|
|
|
<para>By enabling proxy ARP on the router, any machine on the PUBNET
|
|
network that issues an ARP "who has" request for the server's MAC address
|
|
will get a proxy ARP reply from the router containing the router's MAC
|
|
address. This tells machines on the PUBNET network that they should be
|
|
sending packets destined for the server via the router. The router
|
|
forwards the packets from the machines on the PUBNET network to the server
|
|
on the PRIVNET network.</para>
|
|
|
|
<para>Similarly, when the server on the PRIVNET network issues a "who has"
|
|
request for any machines on the PUBNET network, the router provides its
|
|
own MAC address via proxy ARP. This tells the server to send packets for
|
|
machines on the PUBNET network via the router. The router forwards the
|
|
packets from the server on the PRIVNET network to the machines on the
|
|
PUBNET network.</para>
|
|
|
|
<para>The proxy ARP provided by the router allows the server on the
|
|
PRIVNETnetwork to appear to be on the PUBNET network. It lets the router
|
|
pass ARP requests and other network packets in both directions between the
|
|
server machine and the PUBNET network, making the server machine appear to
|
|
be connected to the PUBNET network even though it is on the PRIVNET
|
|
network hidden behind the router.</para>
|
|
|
|
<para>Before you try to use this technique, I strongly recommend that you
|
|
read the <ulink url="shorewall_setup_guide.htm">Shorewall Setup
|
|
Guide</ulink>.</para>
|
|
</section>
|
|
|
|
<section id="Example">
|
|
<title>Example</title>
|
|
|
|
<para>The following figure represents a Proxy ARP environment.</para>
|
|
|
|
<graphic align="center" fileref="images/proxyarp.png"/>
|
|
|
|
<para>Proxy ARP can be used to make the systems with addresses
|
|
130.252.100.18 and 130.252.100.19 appear to be on the upper
|
|
(130.252.100.*) subnet. Assuming that the upper firewall interface is eth0
|
|
and the lower interface is eth1, this is accomplished using the following
|
|
entries in <filename>/etc/shorewall/proxyarp</filename>:</para>
|
|
|
|
<programlisting>#ADDRESS INTERFACE EXTERNAL HAVEROUTE PERSISTENT
|
|
130.252.100.18 eth1 eth0 no yes
|
|
130.252.100.19 eth1 eth0 no yes </programlisting>
|
|
|
|
<para><emphasis role="bold">Be sure that the internal systems
|
|
(130.242.100.18 and 130.252.100.19 in the above example) are not included
|
|
in any specification in <filename>/etc/shorewall/masq</filename>
|
|
(/etc/shorewall/snat on Shorewall 5.0.14 or later) or
|
|
<filename>/etc/shorewall/nat</filename>.</emphasis></para>
|
|
|
|
<note>
|
|
<para>I've used an RFC1918 IP address for eth1 - that IP address is
|
|
largely irrelevant (see below).</para>
|
|
</note>
|
|
|
|
<para>The lower systems (130.252.100.18 and 130.252.100.19) <emphasis
|
|
role="bold">should have their subnet mask and default gateway configured
|
|
exactly the same way that the Firewall system's eth0 is configured. In
|
|
other words, they should be configured just like they would be if they
|
|
were parallel to the firewall rather than behind it.</emphasis></para>
|
|
|
|
<warning>
|
|
<para>Do not add the Proxy ARP'ed address(es) (130.252.100.18 and
|
|
130.252.100.19 in the above example) to the external interface (eth0 in
|
|
this example) of the firewall.</para>
|
|
</warning>
|
|
|
|
<note>
|
|
<para>It should be stressed that entries in the proxyarp file do not
|
|
automatically enable traffic between the external network and the
|
|
internal host(s) — such traffic is still subject to your policies and
|
|
rules.</para>
|
|
</note>
|
|
|
|
<para>While the address given to the firewall interface is largely
|
|
irrelevant, one approach you can take is to make that address the same as
|
|
the address of your external interface!</para>
|
|
|
|
<graphic align="center" fileref="images/proxyarp1.png"/>
|
|
|
|
<para>In the diagram above, <filename class="devicefile">eth1</filename>
|
|
has been given the address 130.252.100.17, the same as
|
|
<filename>eth0</filename>. Note though that the VLSM is 32 so there is no
|
|
network associated with this address. This is the approach <ulink
|
|
url="XenMyWay.html">that I take with my DMZ</ulink>.</para>
|
|
|
|
<para>To permit Internet hosts to connect to the local systems, you use
|
|
ACCEPT rules. For example, if you run a web server on 130.252.100.19 which
|
|
you have configured to be in the <emphasis role="bold">loc</emphasis> zone
|
|
then you would need this entry in /etc/shorewall/rules:</para>
|
|
|
|
<programlisting>#ACTION SOURCE DEST PROTO DPORT
|
|
ACCEPT net loc:130.252.100.19 tcp 80</programlisting>
|
|
|
|
<warning>
|
|
<para>Your distribution's network configuration GUI may not be capable
|
|
of configuring a device in this way. It may complain about the duplicate
|
|
address or it may configure the address incorrectly. Here is what the
|
|
above configuration should look like when viewed using
|
|
<command>ip</command> (the line "inet 130.252.100.17/32 scope global
|
|
eth1" is the most important):</para>
|
|
|
|
<programlisting>gateway:~# <command>ip addr ls eth1</command>
|
|
3: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
|
|
link/ether 00:a0:cc:d1:db:12 brd ff:ff:ff:ff:ff:ff
|
|
<emphasis role="bold">inet 130.252.100.17/32 scope global eth1</emphasis>
|
|
gateway:~#</programlisting>
|
|
|
|
<para>Note in particular that there is no broadcast address. Here is an
|
|
<filename>ifcfg-eth-id-00:a0:cc:d1:db:12</filename> file from SUSE that
|
|
produces this result (Note: SUSE ties the configuration file to the card
|
|
by embedding the card's MAC address in the file name):</para>
|
|
|
|
<programlisting>BOOTPROTO='static'
|
|
BROADCAST='130.252.100.17'
|
|
IPADDR='130.252.100.17'
|
|
MTU=''
|
|
NETMASK='255.255.255.255'
|
|
NETWORK='130.252.100.17'
|
|
REMOTE_IPADDR=''
|
|
STARTMODE='onboot'
|
|
UNIQUE='8otl.IPwRm6bNMRD'
|
|
_nm_name='bus-pci-0000:00:04.0'</programlisting>
|
|
|
|
<para>Here is an excerpt from a Debian /etc/network/interfaces file that
|
|
does the same thing:</para>
|
|
|
|
<programlisting>...
|
|
auto eth1
|
|
iface eth1 inet static
|
|
address 130.252.100.17
|
|
netmask 255.255.255.255
|
|
broadcast 0.0.0.0
|
|
...</programlisting>
|
|
</warning>
|
|
</section>
|
|
|
|
<section id="ARP">
|
|
<title>ARP cache</title>
|
|
|
|
<para>A word of warning is in order here. ISPs typically configure their
|
|
routers with a long ARP cache timeout. If you move a system from parallel
|
|
to your firewall to behind your firewall with Proxy ARP, it will probably
|
|
be <emphasis role="bold">HOURS</emphasis> before that system can
|
|
communicate with the Internet.</para>
|
|
|
|
<para>If you sniff traffic on the firewall's external interface, you can
|
|
see incoming traffic for the internal system(s) but the traffic is never
|
|
sent out the internal interface.</para>
|
|
|
|
<para>You can determine if your ISP's gateway ARP cache is stale using
|
|
ping and tcpdump. Suppose that we suspect that the gateway router has a
|
|
stale ARP cache entry for 130.252.100.19. On the firewall, run tcpdump as
|
|
follows:</para>
|
|
|
|
<programlisting>tcpdump -nei eth0 icmp</programlisting>
|
|
|
|
<para>Now from 130.252.100.19, ping the ISP's gateway (which we will
|
|
assume is 130.252.100.254):</para>
|
|
|
|
<programlisting>ping 130.252.100.254</programlisting>
|
|
|
|
<para>We can now observe the tcpdump output:</para>
|
|
|
|
<programlisting>13:35:12.159321 <emphasis role="bold">0:4:e2:20:20:33</emphasis> 0:0:77:95:dd:19 ip 98: 130.252.100.19 > 130.252.100.254: icmp: echo request (DF)
|
|
13:35:12.207615 0:0:77:95:dd:19 <emphasis role="bold">0:c0:a8:50:b2:57 </emphasis>ip 98: 130.252.100.254 > 130.252.100.19 : icmp: echo reply</programlisting>
|
|
|
|
<para>Notice that the source MAC address in the echo request is different
|
|
from the destination MAC address in the echo reply!! In this case
|
|
0:4:e2:20:20:33 was the MAC of the firewall's eth0 NIC while
|
|
0:c0:a8:50:b2:57 was the MAC address of the system on the lower left. In
|
|
other words, the gateway's ARP cache still associates 130.252.100.19 with
|
|
the NIC in that system rather than with the firewall's eth0.</para>
|
|
|
|
<para>If you have this problem, there are a couple of things that you can
|
|
try:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>A reading of <citetitle>TCP/IP Illustrated, Vol 1</citetitle> by
|
|
Stevens reveals<footnote>
|
|
<para>Courtesy of Bradey Honsinger</para>
|
|
</footnote> that a <quote>gratuitous</quote> ARP packet should cause
|
|
the ISP's router to refresh their ARP cache (section 4.7). A
|
|
gratuitous ARP is simply a host requesting the MAC address for its own
|
|
IP; in addition to ensuring that the IP address isn't a
|
|
duplicate...</para>
|
|
|
|
<blockquote>
|
|
<para>if the host sending the gratuitous ARP has just changed its
|
|
hardware address..., this packet causes any other host...that has an
|
|
entry in its cache for the old hardware address to update its ARP
|
|
cache entry accordingly.</para>
|
|
</blockquote>
|
|
|
|
<para>Which is, of course, exactly what you want to do when you switch
|
|
a host from being exposed to the Internet to behind Shorewall using
|
|
proxy ARP (or one-to-one NAT for that matter). Happily enough, recent
|
|
versions of Redhat's iputils package include <quote>arping</quote>,
|
|
whose <quote>-U</quote> flag does just that:</para>
|
|
|
|
<programlisting>arping -U -I <<emphasis>net if</emphasis>> <<emphasis>newly proxied IP</emphasis>>
|
|
arping -U -I eth0 66.58.99.83 # for example</programlisting>
|
|
|
|
<para>Stevens goes on to mention that not all systems respond
|
|
correctly to gratuitous ARPs, but googling for <quote>arping
|
|
-U</quote> seems to support the idea that it works most of the
|
|
time.</para>
|
|
|
|
<para>To use arping with Proxy ARP in the above example, you would
|
|
have to:</para>
|
|
|
|
<programlisting>shorewall clear
|
|
ip addr add 130.252.100.18 dev eth0
|
|
ip addr add 130.252.100.19 dev eth0
|
|
arping -U -c 10 -I eth0 130.252.100.18
|
|
arping -U -c 10 -I eth0 130.252.100.19
|
|
ip addr del 130.252.100.18 dev eth0
|
|
ip addr del 130.252.100.19 dev eth0
|
|
shorewall start</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>You can call your ISP and ask them to purge the stale ARP cache
|
|
entry but many either can't or won't purge individual entries.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<warning>
|
|
<para>There are two distinct versions of <command>arping</command>
|
|
available:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para><command>arping</command> by Thomas Habets (Debian package
|
|
<emphasis>arping</emphasis>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><command>arping</command> as part of the iputils package by
|
|
Alexey Kuznetsov (Debian package
|
|
<emphasis>iputils-arping</emphasis>).</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>You want the second one by Alexey Kuznetsov.</para>
|
|
</warning>
|
|
</section>
|
|
|
|
<section>
|
|
<title>IPv6 - Proxy NDP</title>
|
|
|
|
<para>The IPv6 analog of Proxy ARP is Proxy NDP (Neighbor Discovery
|
|
Protocol). Beginning with Shorewall 4.4.16, Shorewall6 supports Proxy NDP
|
|
in a manner similar to Proxy ARP support in Shorewall:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>The configuration file is /etc/shorewall6/proxyndp (see <ulink
|
|
url="manpages6/shorewall6-proxyndp.html">shorewall6-proxyndp
|
|
</ulink>(5)).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The ADDRESS column of that file contains an IPv6 address.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>It should be noted that IPv6 implements a "strong host model"
|
|
whereas Linux IPv4 implements a "weak host model". In the strong model, IP
|
|
addresses are associated with interfaces; in the weak model, they are
|
|
associated with the host. This is relevant with respect to Proxy NDP in
|
|
that a multi-homed Linux IPv6 host will only respond to neighbor
|
|
discoverey requests for IPv6 addresses configured on the interface
|
|
receiving the request. So if eth0 has address 2001:470:b:227::44/128 and
|
|
eth1 has address 2001:470:b:227::1/64 then in order for eth1 to respond to
|
|
neighbor discoverey requests for 2001:470:b:227::44, the following entry
|
|
in /etc/shorewall6/proxyndp is required:</para>
|
|
|
|
<programlisting>#ADDRESS INTERFACE EXTERNAL HAVEROUTE PERSISTENT
|
|
2001:470:b:227::44 - eth1 Yes</programlisting>
|
|
|
|
<para>A practical application is shown in the Linux <ulink
|
|
url="Vserver.html#NDP">Vserver article</ulink>.</para>
|
|
</section>
|
|
</article>
|