\documentclass[twocolumn,twoside]{article}
\usepackage{graphics}
\title{IPv4 Masquerading for the Hypothetical Geek}
\author{Ben Pfaff $<$pfaffben@msu.edu$>$}
\date{24 May 2000}

\setlength{\textwidth}{6.5in}
\setlength{\oddsidemargin}{0pt}
\setlength{\evensidemargin}{0pt}
\setlength{\textheight}{8.5in}
\setlength{\topmargin}{0pt}

\newcommand{\hyply}{\emph{hypothetically}}
\newcommand{\hyp}{\emph{hypothetical}}
\newcommand{\Hyply}{\emph{Hypothetically}}
\newcommand{\Hyp}{\emph{Hypothetical}}

\begin{document}
\maketitle
\tableofcontents

\section{Introduction}

\Hyply, if you're a geek, you have any number of computers just
sitting around, and you have enough random parts to build another half
dozen or so without video or disks.  So, \hyply, the thing to do is to
network them all together, just for hack value, using a combination of
old thinwire Ethernet cards and a 386 with 6 NE2000s acting as a
bridge.

Remember, all this is \hyp.  I would never do this.  I am not a geek.

The only problem is that all these machines will be wanting Internet
access.  What good is a computer without Internet access, after all?
So you call up the \hyp{} local DSL provider and order 18 \hyp{} DSL
lines and companion IP addresses, or 25 to allow room for expansion.

Ahem!  Not even your \hyp{} geek can pay for 25 \hyp{} DSL lines, and
anyway no DSL provider exists out in the \hyp{} boonies where the
\hyp{} geek lives.

So, in reality, your \hyp{} geek is stuck with a 56
kbps\footnote{Current FCC regulations limit speed to 53 kbps.  It's
only your crappy phone lines that limit speed to 20 kbps.} modem on a
single phone line.  How can such a geek make the best of this?  The
\hyp{} geek still wants all the machines to have Internet access.  He
doesn't want to put a modem in all 18 computers, which would \hyply{}
result in the \hyp{} geek slitting his \hyp{} wrists\footnote{Down,
not across.} on a jagged case fragment anyhow.

The real answer to this \hyp{} problem of connectivity is
\textit{masquerading}, also known as \textit{network address
translation} or NAT.  Masquerading makes any number of machines on a
single network look like a single host with a single network address.
More specifically, masquerading for IPv4\footnote{IPv4, or Internet
Protocol version 4, is the version used in real life.  IPv6, the next
version, is used only in pipe dreams\texttt{\^{}W\^{}W}experimental
settings.} has been a feature of the Linux kernel since version
1.2.\textit{x} for some value \textit{x}.

This article covers the basics of IP masquerading under Linux
2.0.\textit{x} and 2.2.\textit{x}.  For more information on IP
masquerading under Linux, please see David Ranch's excellent IP
Masquerading HOWTO, available from your local Linux documentation
site.

\section{Planning}

\begin{figure*}[th]
\centering\resizebox{6in}{!}{\includegraphics{network.ps}}
\caption{Architecture of typical home network.}
\label{network}
\end{figure*}

Figure~\ref{network} on page~\pageref{network} shows the architecture
of a typical home network set up under IP masquerading.  Notice how
all the machines in the network are ultimately connected to the
Internet through the server in the lower right of the diagram.  This
is probably the way that you want to plan for your IP masquerading
setup to work.

You'll need all of the following in order to set up masquerading:

\begin{itemize}
\item A Linux-capable server computer with a network card and an
Internet connection.  A 386 or 486 is fine for basic setups.

\item One or more client computers with network cards.  These can run
just about any operating system.

\item A hub to connect all the computers together.

\item A range of IP addresses (see below).

\item A geek, for debugging purposes.  This can be the most expensive
part of the setup, but some geeks can be bribed with interesting bits
of old hardware or discounts on new hardware.
\end{itemize}

You'll have to come up with the hardware and the geek on your own.
But selecting the IP address range to use is easy.  I recommend that
you use the 16-bit ``Class B''-size address range at
192.168.\textit{x}.\textit{y}, which is reserved specifically for
private networks like the one you're building.  As long as you have
fewer than 65,000 or so computers on your network\footnote{Around
here, that reads ``as long as you're not Ed Glowacki.''}, this should
be plenty.

As a consequence, the examples below assume that all of your computers
have IP addresses of the form 192.168.0.\textit{x}, where \textit{x}
is a number between 1 and 254\footnote{192.168.0.0 and 192.168.0.255
are reserved for the network address and the broadcast address,
respectively.}.  Specifically, it is assumed that your server is at
192.168.0.1.

Now that we're done with the formalities, plug everything together and
proceed to the next section, where we'll set up basic masquerading on
the server and the clients.

\section{Basic server setup}

The toughest setup for masquerading is on the server, and even that
isn't very hard.  Now, let's a look at how to actually do it.

Start by logging into your Linux 2.0.\textit{x} or 2.2.\textit{x}
server as \texttt{root}, the superuser.  Then follow the simple steps
below.  If you're going to use masquerading on a regular basis, you
should integrate these commands into a system startup script in
\texttt{/etc/init.d}, but the first time through it might be more
educational to type them directly at a shell prompt.

\begin{enumerate}
\item Modern Linux kernels disable packet forwarding by default.  This
means that incoming IP packets will never be passed on to other
computers.  However, for masquerading we need to turn on packet
forwarding, using the following command:

\begin{verbatim}
echo 1 > /proc/sys/net/ipv4/ip_forward
\end{verbatim}

\item If you use the most common type of PPP dialup account, where you
get a new IP address every time you dial, you should turn on kernel
support for dynamic IP address hacking, too:

\begin{verbatim}
echo 1 > /proc/sys/net/ipv4/ip_dynaddr
\end{verbatim}

\item (Optional.)  By default, masqueraded connections that are idle
for 15 minutes or longer ``time out'' and expire.  This timeout
duration can be adjusted; e.g., the following command sets the
expiration timer to 2 hours (7200 seconds):

\begin{description}
\item[(2.0)]
\verb|ipfwadm -M -s 7200 10 160|
\item[(2.2)]
\verb|/sbin/ipchains -M -S 7200 10 160|
\end{description}

\item (Optional.)  Some IP-based protocols need extra kernel support
for successful masquerading.  You can load modules to support these
protocols.  For instance, to load the FTP masquerading module:

\begin{verbatim}
modprobe ip_masq_ftp
\end{verbatim}

Besides FTP, masquerading modules exist for CuSeeMe, IRC, Quake,
RealAudio, and VDOLive, among others.  Note that most protocols do not
require specific masquerading support.

\item Set default forwarding policy to ``deny.''  This is very
important; if omitted, then you allow anyone on the Internet to tunnel
through your network, making it appear as if their network activity
were originating from your own network.

\begin{description}
\item[(2.0)]
\verb|/sbin/ipfwadm -F -p deny|
\item[(2.2)]
\verb|/sbin/ipchains -P forward DENY|
\end{description}

\item Turn on masquerading for your local network:

\begin{description}
\item[(2.0)]
\verb|/sbin/ipfwadm -F -a m| \\ 
\verb|-S 192.168.0.0/255.255.255.0| \\ 
\verb|-D 0.0.0.0/0.0.0.0|
\item[(2.2)]
\verb|/sbin/ipchains -A forward| \\ 
\verb|-s 192.168.0.0/255.255.255.0|\\
\verb|-j MASQ|
\end{description}

In the commands above you should replace \verb|192.168.0.0| and
\verb|255.255.255.0| by the actual network address and netmask of your
local network.  If you're using my recommended setup, no changes are
necessary.
\end{enumerate}

That's it!  You should now have a functioning IP masquerading setup.
If not, refer to the following section.

\subsection{Troubleshooting}

This is where you should contact your geek.  But if you want to try to
debug it on your own, consider the following points:

\begin{description}
\item[Does the kernel support masquerading?]  A lot of distributions
now come out-of-the-box with kernel support for masquerading.  But
yours might not.  If you suspect that your kernel lacks IP
masquerading support, refer to the IP Masquerading HOWTO for
information on what options need to be enabled when recompiling the
kernel.

\item[Is the network card set up correctly?]  Can the server can
\texttt{ping} other hosts in the network and that they can
\texttt{ping} the server?  If not, you've got a problem.

\item[Are you online?]  Nothing in these instructions will make your
server automatically auto-dial when a web page is requested.  (That's
explained later.)

\item[Did you do the ritual sacrifice?]  Arachnae, goddess of
networks, appreciates the sacrifice of hardware, the newer the better.
\end{description}

\section{Client setup}

Once you've set up the server, it's time to set up the clients.  This
is pretty easy.  I'll cover how to set up Linux clients and Windows
9\textit{x} clients.  For more exotic systems, follow your nose, or
refer to the IP Masquerading HOWTO.

\subsection{Linux}

Your distribution probably has some GUI method\footnote{``It's
GUI-riffic!''} for setting up networking.  These instructions assume
that you're not using that method.  As a result, the following should
work with just about any Linux kernel.  It probably works, with little
modification, under many other Unix-like kernels, too.  Again, you'll
want to modify your startup scripts to do the following automatically.

\begin{enumerate}
\item Set the machine's IP address, network address, and netmask.  For
instance:

\begin{verbatim}
ifconfig eth0 192.168.0.2
         netmask 255.255.255.0
\end{verbatim}

\item Tell the machine how to get to the local network.  (Some newer
kernels may set this up automatically.)

\begin{verbatim}
route add -net 192.168.0.0 eth0
\end{verbatim}

\item Instruct the machine that everything not on the local network
should go through the server (it already knows how to get packets to
the server, since it's on the local network; if it weren't, you'd have
to tell it how), using it as a gateway:

\begin{verbatim}
route add default gw 192.168.0.1
\end{verbatim}

\item If you don't already have DNS set up, then create
\texttt{/etc/resolv.conf} with the content shown below.  Replace the
values shown by your own domain(s) and local DNS server(s):

\begin{verbatim}
search msu.edu debian.org gnu.org
nameserver 35.8.2.41 35.8.2.42
\end{verbatim}
\end{enumerate}

\subsubsection{Troubleshooting}

If it doesn't work, you're doing something wrong.  Duh.  Your geek
will know what's wrong.  If he's on vacation, think about the
following:

\begin{description}
\item[Can you see the server?]  Try using \verb|ping| to test your
connectivity to the server.

\item[Is ICMP masqueraded?]  ICMP, the protocol used by \verb|ping|,
is only masqueraded by newer kernels.  So if you're trying to ping the
Internet through the server, it might not work.  Try something else,
like a web browser.

\item[\texttt{route} is not idempotent.]  If you run \texttt{route} a
lot, your routes will accumulate.  You can view the routing table with
\verb|route| or \verb|route -n|.  To clear out the routing table, use
\verb|route del|.  For more information, see route(8).
\end{description}

\subsection{Windows 9\textit{x}}

Open ``Control Panel'' under ``Settings'' on the Start menu.  Inside
Control Panel, double-click on ``Network.''  Within the main list box
in the dialogue box that appears, find ``TCP/IP'' associated with your
Ethernet card and double-click on it.  Then make the following
selections from the listed tabs:

\begin{description}
\item[IP Address] Specify the client's IP address and netmask.  For
instance, you might use \texttt{192.168.0.2} and \texttt{255.255.255.0}.

\item[Gateway] Add a single entry, the address of your server.  If
you're following my recommendations, this is \texttt{192.168.0.1}.

\item[DNS Configuration] Select the ``Enable DNS'' setting.  Enter a
host name in ``Host''; the name itself is not particularly important.
Enter your preferred domain name within ``Domain.''  Put your DNS
servers in ``DNS Server Search Order''; for instance,
\texttt{35.8.2.41} and \texttt{35.8.2.42}.  Enter any additional
domains within ``Domain Suffix Search Order.''

\item[Other] Set as desired
\end{description}

You'll probably need to reboot after making these settings.

\subsubsection{Troubleshooting}

What do I look like, a Windows expert?  ``Fiddle with it until it
starts working'' is my advice.

There's probably no point in talking to your geek about it.  He
doesn't know, either.

\section{Advanced server setup}

If you've gone through what's above, you now have a working IP
masquerading setup.  Congratulations.  But there's lots more that you
can set up, with some extra work.  You might be interested in setting
up one or more of the following:

\begin{itemize}
\item Automatic dialing whenever Internet sites are accessed.
\item Web and FTP caching to accelerate surfing.
\item A DHCP server to simplify client setup.
\item A nameserver to speed DNS lookups and allow naming client
computers.
\item An NTP client/server to synchronize machines' clocks.
\end{itemize}

The following sections briefly cover each of these possibilities.

\subsection{Autodialing}

Most of the time, what you really want to happen is for the modem to
dial when you're using the Internet, then hang up when you're done.
This is pretty easy to do using \verb|diald|, and that's what I
recommend that you use.  I'll assume that you can set up \verb|diald|
on your own; it's not that hard.

But sometimes that's not what you want to do.  For instance, you might
want to keep the connection up permanently for a while, or you might
want to prevent the modem from dialing entirely if you're using the
line for other purposes.  To conveniently allow for that, you can set
up a helpful CGI script on your webserver.

A sample CGI script for this purpose is shown in Figure~\ref{cgi} on
page~\pageref{cgi}.  You should install this script into your web
server directory (e.g., \verb|/var/www|) and make it available only to
machines on the local network.

In addition, you need to add a line to \verb|diald|'s configuration
file, of this form:

\begin{verbatim}
fifo /var/run/diald.fifo
\end{verbatim}

The script has to be setuid to a user empowered to write to the FIFO
mentioned above.  Sometimes this has to be \verb|root|, but you might
be lucky enough that \verb|dialout| or similar will work, too, or you
may be able to adjust the ownership or permissions on the FIFO created
by \verb|diald|.

\begin{figure*}
\begin{verbatim}
#! /usr/bin/perl

use CGI;
$q = new CGI;

if ($q->param ('action') eq 'up') {
    fifo_cmd ('unblock');
    fifo_cmd ('up');
    fifo_cmd ($q->param ('keep') ? 'force' : 'unforce');
} elsif ($q->param ('action') eq 'down') {
    fifo_cmd ('unforce');
    fifo_cmd ('down');
    fifo_cmd ($q->param ('keep') ? 'block' : 'unblock');
}

print $q->header(-expires=>'now');
print $q->start_html(-title=>'Modem Control');
print "<h1 align=center>Modem Control</h1>\n";
print $q->start_form ();
print "<table>\n";
print "<p><tr><td>action</td><td nowrap>bring the connection\n";
print $q->popup_menu ('action', ['up','down'], 'up');
print "</td><td>To dial the modem, select <strong>up</strong>, or\n";
print "to disconnect, select <strong>down</strong>.</td></tr><p>\n";
print "<p><tr><td>permanence</td><td nowrap>\n";
print $q->checkbox(-name=>'keep', -label=>'Keep it that way.');
print "</td><td>If you don't check this box, then the normal\n";
print "semantics will be applied to the connection. That is,\n";
print "if you selected <strong>down</strong> above, the modem will dial when\n";
print "there is Internet activity; if you selected <strong>up</strong>,\n";
print "the modem will disconnect after idle time.\n";
print "Checking this box will disable that behavior: the connection\n";
print "will stay up or down, as appropriate, until you come back to\n";
print "this page and resubmit the form.";
print "</td></tr><p>\n";
print "</table>\n";
print $q->submit ('Submit');
print "</p>\n";
print $q->end_form (), "\n";
print $q->end_html, "\n";

sub fifo_cmd {
    my ($cmd) = @_;
    open FIFO, ">/var/run/diald.fifo";
    print FIFO "$cmd\n";
    close FIFO;
}
\end{verbatim}
\caption{CGI script in Perl to allow for manual control of
\texttt{diald} autodialer.  Also available from
\texttt{http://www.msu.edu/user/pfaffben/masq/diald.cgi}.}
\label{cgi}
\end{figure*}

\subsection{Web and FTP caching}

Web browsers such as Mozilla keep a cache of sites recently visited by
particular users from particular workstations in order to speed up web
browsing.  A web cache on a server keeps a cache of sites recently
visited by anyone who uses the cache.  This can significantly speed up
web browsing over a limited-bandwidth connection.

To implement web and FTP caching, you just have to install and
configure Squid on your server.  This is a pretty easy process, and
there's not much else to say about it.

I don't recommend using Squid on a machine with less than 32 MB RAM,
and more RAM is better.

\subsection{DHCP}

I'm a programmer, therefore I'm lazy.  I don't want to spend my time
assigning and maintaining IP addresses for 18 different machines.
Especially not for a laptop that often moves between networks.  You
probably don't want to, either.  This is why you'd want to use DHCP
for automatically assigning IP addresses.  With Debian GNU/Linux,
you'll want the \verb|dhcp| package for this purpose; other
distributions may have this DHCP server under a different name.

It's actually pretty easy to set up DHCP, but figuring out how to do
it from the documentation can be gross.  So here's a sample
configuration file for our sample network setup:

\begin{verbatim}
server-identifier server.quux.org;
subnet 192.168.0.0 netmask 255.255.255.0 {
    range 192.168.0.128 192.168.0.254;
    option domain-name-servers 35.8.2.41;
    option domain-name "quux.org";
    option routers 192.168.0.1;
    option subnet-mask 255.255.255.0;
    option broadcast-address 192.168.0.255;
    default-lease-time 3600;
    max-lease-time 86400;
}
\end{verbatim}

By default, the DHCP server will hand out IP addresses on a
first-come, first-serve basis within the range specified in the
\verb|range| directive above.  You can also specify that particular
machines should get fixed IP addresses, like this (be sure not to use
an IP address reserved for dynamic assignment above):

\begin{verbatim}
host gameOSbox {
  hardware ethernet 08:00:07:26:c0:a5;
  fixed-address 192.168.0.5;
}
\end{verbatim}

You can obtain the Ethernet address to specify on \texttt{hardware
ethernet} from the output of \texttt{ifconfig} on the machine in
question.

\subsection{Nameserver}

Up until now, you've had to refer to all of your client computers by
their IP addresses.  If you have more than just a few clients, you'll
want to give them names instead.  You can do this by setting up the
BIND DNS server (``nameserver''), on your server machine.  This also
allows the server to cache DNS entries for the entire network,
speeding up network operations.

Setting up BIND separates the lusers from the BOFHs.  It is not easy.
Fortunately, for your network, you won't need more than a simple
setup, which as usual I've sugar-coated.  My suggested BIND
configuration file (typically \texttt{/etc/named.conf} or
\texttt{/etc/bind/named.conf}) is this:

\begin{verbatim}
options {
    directory "/var/named";
    forwarders {
        35.8.2.41;
        35.8.2.42;
    };
    query-source address * port 53;
};

zone "." {
    type hint;
    file "named.root";
};

zone "localhost" {
    type master;
    file "named.local";
};

zone "127.in-addr.arpa" {
    type master;
    file "named.rev-local";
};

zone "quux.org" {
    type master;
    file "named.domain";
};

zone "0.168.192.in-addr.arpa" {
    type master;
    file "named.rev-domain";
};
\end{verbatim}

You'll want to change the list of \texttt{forwarders} to show your
ISP's nameservers, or you can leave them out entirely (but this will
reduce performance).  Note, in the last declaration of the file, that
the network address for your local network \texttt{quux.org} is given
in \emph{reverse} order.

If you only want to run BIND for its DNS caching abilities, you can
omit the last two \texttt{zone} entries above.  You're done, at this
point.  Start BIND and get outta here.

Otherwise, you're interested in serving out your own domain.  First
choose a domain name.  This doesn't have to be the name of a real
domain and in fact shouldn't be.  (If it is then you won't be able to
access the corresponding real domain at all, by name at least.)  

Start by replacing \verb|quux.org| by this domain name above.  Then
you have to create two files.  The first of these is
\verb|/var/named/named.domain|, and it should look something like
this:

\begin{verbatim}
@ IN SOA ns.quux.org. root.quux.org. (
        1               ; Serial
        10800           ; Refresh
        1800            ; Retry
        3600000         ; Expire
        259200 )        ; Minimum
        IN      NS      server.quux.org.

server  IN      A       192.168.0.1
www     IN      CNAME   server
ftp     IN      CNAME   server
ns      IN      CNAME   server
proxy   IN      CNAME   server
client1 IN      A       192.168.0.2
client2 IN      A       192.168.0.3
client3 IN      A       192.168.0.4
\end{verbatim}

The first line introduces the ``SOA'' or ``start of authority'' record
that gives the name of the nameserver and the email address of the
server administrator (\texttt{root@quux.org}) with `\texttt{@}'
replaced by `\texttt{.}'.  The second line is the file's ``serial
number,'' which should be incremented whenever its contents are
changed.

The body of the file lists associations between hostnames and IP
addresses using ``A'' records. There should be only one A record per
host.  It can also include hostname synonyms.  There may be any number
of these ``CNAME'' or ``canonical name'' records for a given host.

If you are using DHCP then you might wish to give unique names to all
possible DHCP-assigned IP addresses.  You should probably use a script
to do this, unless you like typing in lots of repetitive data.

The second file you need to create is named
\verb|/var/named/named.rev-domain|.  It should look like this:

\begin{verbatim}
@ IN SOA ns.quux.org. root.quux.org. (
        1               ; Serial
        10800           ; Refresh
        1800            ; Retry
        3600000         ; Expire
        259200 )        ; Minimum
        IN      NS      server.quux.org.

1       IN      PTR     server.quux.org.
2       IN      PTR     client1.quux.org.
3       IN      PTR     client2.quux.org.
4       IN      PTR     client3.quux.org.
\end{verbatim}

This file is the inverse of the first one.  The first part is
identical in form and content to that in the first file.  The
remainder of the file specifies how IP addresses can be translated
back into hostnames, with ``PTR'' records that ``point'' from IP
addresses to hostnames.  Every A record should have a corresponding
PTR record, and vice versa.

There's a number of other possible DNS record types, but the above
should be plenty for your masquerading network.  For more information
on setting up DNS and BIND, refer to the BIND documentation.

Once you have BIND set up, you can change the list of DNS servers on
the server and the clients to point to your server.  Notice that if
you're using DHCP for your clients, all you have to do to make this
change is to update your DHCP server configuration and either tell the
clients to refresh from it or just wait for them to time out.  For
things like this, DHCP can be a real time- and headache-saver.

\subsection{NTP Server}

Sometimes it can be important to keep the clocks on all your machines
synchronized.  The easiest way to do this is to install \verb|ntpd|,
an NTP (Network Time Protocol) client and server.

The traditional way to do this is to have the NTP daemon running all
the time.  Unfortunately this doesn't work out too well for systems
that aren't permanently connected to the Internet like yours.

An alternative is to add a call to \verb|ntpdate| to your PPP startup
script.  The \verb|ntpdate| program just retrieves, once, the current
date and time from a remote server and sets the system clock to
correspond.  Of course, you still want to run the NTP server so that
the other machines on the network can read the date from your server.

Local NTP time servers include MSU's nameservers \verb|35.8.2.41| and
\verb|35.8.2.42|, also known as \verb|serv1.cl.msu.edu| and
\verb|serv2.cl.msu.edu|.

\section{Conclusion}

\Hyply, now you know how to set up a masqueraded network under Linux.
Go to it!

\end{document}
