Linux as an Internet Server
Arthur Donkers
Some time ago, our office conceived the idea of using
Linux as our
Internet server. The choice seemed particularly appropriate,
since Linux
was designed by people on the Net for the Net. This
article tells you
how to set Linux up to act as your Internet server (see
the sidebar
"Installing Linux" for basic installation
information). The software
involved is free, but you do have to invest time in
finding it,
installing it, and configuring it.
Building a Proper Kernel
The kernel from the basic installation is generic and
therefore not
suited to this particular use. Building a kernel for
a system to be used
as an Internet server requires special attention to
security and to
network devices. Other aspects of the kernel can be
customized to suit
your site's needs.
Security
A basic security question is whether to disable the
IPFORWARDING in the
kernel. When this option is set, it will allow IP packets
to flow
through the server onto your internal network, posing
a significant
security threat. However, you will need to be able to
transmit data from
the local net onto the Internet and, under certain strict
conditions,
also vice versa.
Two solutions are available for this purpose. The first
one is based on
the IPFIREWALL code built into the kernel. This piece
of software lets
you define which IP packets may pass through your system.
You can
specify the acceptable packets based on the protocol
(ICMP, UDP,
TCP/IP), the sender, and the service requested. For
each "rule" you can
specify whether the packet should be blocked or forwarded.
How does this work? The kernel keeps an internal table
where all such
information is stored. Each packet that arrives at one
of the network
interfaces is checked against the contents of this table,
and
appropriate action is taken (if you're familiar with
FreeBSD, you'll
already be aware of this functionality). You can specify
the rules by
using a little-known program called ipfw (see the sidebar
"About ipfw").
A set of rules may look like this:
# This will add an accept rule to the blocking firewall
ipfw add blocking accept tcp from 192.12.34.56/24 to 193.34.56.78/24 23
You can check these rules with the same ipfw command.
The output for the
above rules may look like this:
# list the blocking rules
ipfw list blocking
You must respecify these rules each time your system
is booted. To make
sure that they are added each time you reboot your system,
include the
associated commands in an rc.Firewall file and make
sure that file gets
called by one of the startup scripts, preferably rc.inet1
or rc.inet2.
The second alternative is based on application proxies.
These are
special network-aware daemons that will take care of
forwarding and
blocking the network packets. All of these daemons are
independent
processes and therefore run mostly in user space. You
don't need to
configure the kernel to be able to use these proxies.
Application proxies normally listen in on two or more
network
interfaces. Whenever a packet arrives on one of these
interfaces, it is
checked against the contents of an internal table. If
a rule in this
table matches, a packet may be blocked or sent out on
another interface.
This is very similar to kernel-based firewalling, with
the exception
that all this is done at the user level instead of at
the kernel level.
There are different proxy daemons for different network
services. For
example, a telnet session to another system is a simple
connection, with
one endpoint on your local system and one endpoint on
your remote
system. Data is transmitted in both directions on this
connection. An
ftp session is different: when you make an ftp connection
to a server,
you in effect establish a control connection to that
server. The ftp
commands are transmitted over this control connection.
As soon as data
needs to be exchanged, a data connection is established.
These data
connections are created dynamically, and your proxy
daemon must be able
to deal with these dynamic connections.
A well-known implementation of application proxies is
SOCKS, which is
available in source on the Internet. It provides you
a number of proxies
for telnet, ftp, http, and other services. This package
compiles on many
platforms, including Linux (see the sidebar, "SOCKS"
for more
information).
Network Devices
There are two particular concerns related to the kernel
configuration of
network devices: specifying an Internet address and
enabling the
internet support services. If you have an ethernet card
in your system,
you need to tell the kernel which brand and model it
is. Normally, the
kernel will then be able to detect its I/O address,
the INT number, and
(if applicable) the DMA channel.
If you don't have an ethernet card in your system, the
best approach is
to enable the dummy network device, which functions
as a virtual network
device. You can assign an IP number to this device,
thus ensuring that
your system will have an IP address whether or not you
are connected to
the Internet.
The second critical factor is to determine how to connect
to the
Internet. If you use a PPP or SLIP connection (either
dial-up or
direct), you have to enable this in the kernel. For
SLIP you may enable
the Van Jacobsen compression by answering "Yes"
to the CSLIP
configuration. Be sure to select the appropriate protocol
-- using the
wrong one will definitely prevent you from connecting.
Configuring the System
With the kernel rebuilt, you can go on to configure
the system, again
paying special attention to security. The first issue
to be addressed is
the password system. A "normal" Slackware
distribution stores passwords
in the /etc/passwd file. For security purposes, you'll
need to install a
shadow password system. However, ßimplementing
a shadow password system
does have certain operational implications. All programs
which normally
use the /etc/passwd file need to be recompiled for a
shadow password
system. On the network side this means that at least
the telnet daemon
and ftp daemon need to be recompiled. The source for
both these programs
is available and both already have shadow password support
built in.
A second concern is file protection on the different
parts of the
system. Slackware is very generous with read privileges
and many files
are readable by world. You will need to set the protection
on your files
to allow minimal accessiblity in order to prevent unauthorized
use.
Configuring the Local Network
If the Linux machine is connected to a local network,
it will have some
sort of Ethernet card, and the TCP/IP software will
need to be
configured for this device. If you have more than one
card in your
system, you need to determine which of your cards is
connected to the
local network, then specify the card to the TCP/IP software.
You can
repeat the procedure for all of your cards.
To make sure your system is correctly configured each
time you boot, add
the configuration commands to the rc.inet1 file in the
/etc/rc.d
directory. These commands look like this (where eth0
is the specified
ethernet card):
# Edit for your setup.
IPADDR="192.34.56.78"
NETMASK="255.255.255.0"
NETWORK="192.34.56.0"
BROADCAST="192.34.56.255"
# config the interface
/sbin/ifconfig eth0 ${IPADDR} netmask ${NETMASK} broadcast ${BROADCAST}
The next file you will need is /etc/hosts, which contains
a minimal
mapping of IP addresses to hostnames and vice versa.
A simple version of
this file may look like this:
#
# hosts,
#
# A simple hostname to IP address mapping
# and vice versa
#
127.0.0.1 localhost
192.34.56.78 linux.reseau.nl linux
The system uses two other configuration files to determine
how to
resolve hostnames. The first one, /etc/host.conf, tells
the system in
what order it should look for a hostname/IP address
pair. The standard
way is to look first in the /etc/hosts file, then query
the name server.
This file looks like this:
order hosts, bind
multi on
"multi on" means that it will accept more
than one answer for a query.
The second file, /etc/resolv.conf, tells the system
where it can find a
nameserver if the /etc/host file does not contain the
requested
information. In the example here
domain reseau.nl
nameserver 199.98.76.54
the IP address of the nameserver points to a machine
outside our local
domain. This is the nameserver designated by our Internet
Service
Provider. It will respond to our queries for unknown
hosts.
If you also have an internal nameserver for your domain,
you might
consider running a split name server, which will respond
to queries for
hosts in the local domain as well as to queries for
hosts on the
Internet.
Setting Up PPP/SLIP
The PPP protocol has some advantages over SLIP. The
PPP protocol allows
you to use authorization on a low level, and PPP packets
can be routed.
For purposes of this discussion, I assume a dial-up
PPP connection.
To get the maximum throughput, you'll need to configure
the serial port
on the system at its maximum speed. Normally, Linux
defines 38,400 bps
as the maximum configurable speed for a serial port,
although the
hardware is capable of a 115,200 bps. A special program,
called
setserial, allows you to configure the higher speeds;
it replaces the
38,400 bps entry with either a 57,600 or a 115,200 bps
entry. So when
you set the speed of the port to 38,400, in effect you're
configuring it
to run at either 57,600 or 115,200 bps. You can use
a startup file to
configure this when booting. An example is shown below:
#
# /etc/rc.serial
# Initializes the serial ports on your system
#
SETSERIAL=/etc/setserial
echo -n "Configuring serial ports...."
# These are the standard COM1 through COM4 devices
#
${SETSERIAL} /dev/cua0 uart 16550A port 0x3F8 irq 4 spd_hi ${STD_FLAGS}
${SETSERIAL} /dev/cua1 uart 16550A port 0x2F8 irq 3 spd_vhi ${STD_FLAGS}
${SETSERIAL} /dev/ttyS0 uart 16550A port 0x3F8 irq 4 spd_hi ${STD_FLAGS}
${SETSERIAL} /dev/ttyS1 uart 16550A port 0x2F8 irq 3 spd_vhi ${STD_FLAGS}
The configuration shown here assumes you will only dial
out on this
modem. If the modem will also serve dial-ins, you will
be running a
getty program on that port, and you will have to make
sure that this
getty obeys the UUCP locking style of the port. The
dialout ports on a
Linux system are called /dev/cua?, just as on SunOS.
You can use a
serial communications program such as kermit, minicom,
or cu to test
whether you are able to talk to the modem on the port.
To configure the PPP software, you can use the pppd
package, first
recompiling it for your kernel to make sure you're using
the correct
ioctl calls (these have changed in a few kernel releases,
so recompiling
the program guarantees that you've got the correct code).
You can find
the sources of the pppd program at the standard Linux
ftp sites, such as
sunsite.unc.edu and tsx-11.mit.edu. The documentation
for the pppd
package provides very clear configuration insturctions.
I will touch
briefly here on the most important features.
pppd is configured through files located in the /etc/ppp
directory. The
first file, options, describes the general options for
the pppd program.
Using this file, you can specify whether pppd should
use PPP's built-in
authentication, how to handle character translation,
and so forth. Your
service provider determines whether or not you can use
the PPP
authentication; if you do have the choice, it's a good
idea to use it,
as it provides an extra level of security to your connection.
The
settings used at our site are shown below.
lock
modem
crtscts
asyncmap 0
This tells pppd to lock the serial port according to
the UUCP style, use
the full set of modem signals, use hardware flow control,
and not escape
any character in the datastream (8 bit clean). This
file is read when
pppd is started.
Two more files are involved in the configuration of
pppd: ip-up and
ip-down. These files are called as shell scripts when
pppd has
established or dropped the IP connection with the service
provider. On
our system, these two files are empty, but you can use
them to
reconfigure the nameserver, or to flush the mail queue
when the
connection is made.
Executing the pppconnect script builds the connection
and starts the
pppd program. The following pppconnect script example
also contains some
extra settings for pppd:
#!/bin/sh
DEFAULTDEVICE=/dev/cua0
if [ "x$1" = "x" ]
then
DEVICE=$DEFAULTDEVICE
else
DEVICE="/dev/$1"
fi
/etc/ppp/pppd connect "/etc/chat -f /etc/ppp/pppchat" $DEVICE 38400\
noipdefault ipcp-accept-local ipcp-accept-remote passive defaultroute\
194.98.76.111:
The script will make a connection through serial port
/dev/cua0. The
noipdefault, ipcp-accept-local, and ipcp-accept-remote
options handle
the dynamic IP address allocation used by the provider.
These options
will enable pppd to accept both the remote IP address
and the address
allocated for our site, and pppd will use these two
addresses to
configure the ppp interface on the system. The defaultroute
option tells
pppd to use the ppp interface as the default route,
i.e. the route to be
used for all packets for non-local systems.
The last piece in the connection to the Internet is
the chat script that
pppd uses to dial the provider and make a connection.
The chat script
includes expect-send pairs which specify the string
to be sent to the
modem and the response the modem should send back. If
at any stage
during the execution an unexpected response comes from
the modem, or no
respons at all, the chat script is aborted and pppd
terminates. Our
site's chat script looks like this:
ABORT "NO CARRIER"
ABORT BUSY
ABORT "NO DIALTONE"
ABORT ERROR
"" ATQ0
OK ATM1
OK ATDTW0201234567
TIMEOUT 120
CONNECT ""
ogin: User
TIMEOUT 45
word: Imnotgoingtotellyou!
TIMEOUT 45
Since modem settings are stored as default, it's not
necessary to
reprogram the modem at startup.
After establishing the connection, you can use ifconfig
to check the
settings of the different network interfaces. This may
look a bit like
this :
ppp0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-F8-00-00-00-00-00-00-00-00
inet addr:194.98.78.114 P-t-P:194.98.78.1 Mask:255.255.255.0
UP POINTOPOINT RUNNING MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0
TX packets:0 errors:0 dropped:0 overruns:0
As you can see, pppd has automatically assigned the
dynamic IP addresses
to the interface -- in this case 194.98.78.114 as our
local address and
194.98.78.1 as the address of the remote machine. A
default route
through this machine is also added to our routing table.
To terminate the connection, send the HUP signal to
pppd.
Configuring Services
With the system installed and configured, you can go
on to configure
services that will exploit the Internet connection.
The examples I
provide here are for mail (smtp/.pop) and news.
mail
Given a dial-up connection, incoming mail must be stored
somewhere. Most
service providers place incoming mail in the mailbox
of your dial-in
account, just as if you were a normal user. You can
then retrieve it by
using POP (Post Office Protocol), which was written
specially to
retrieve mail from a mailbox across a network. For this
you'll need a
popclient, which is not a standard part of the Slackware
distribution
and will have to be compiled. The popclient software
may be included on
your CD-ROM, but it's also available on various servers
on the Internet.
We used a version from sunsite.unc.edu, and modified
it so that it could
be run from a shell script, which allows us to specify
the username and
password of the remote mailbox. A call like this
popclient -u User -p Imnotgoingtotellyou! mailserver.remote.nl mailbox
retrieves mail from host mailserver.remote.nl and puts
it in a file
called mailbox, which can be read via your mailreader.
To retrieve mail
automatically once the connection is established, add
this command to
the ip-up script in the /etc/ppp directory.
For outgoing mail, you'll need to configure sendmail
so that it will
queue the mail, but not attempt to deliver it. We accomplished
this by
not running the sendmail daemon on our system. Normally,
the sendmail
daemon runs with a -q parameter designating in minutes
the interval at
which the mailqueue should be rescanned. When sendmail
rescans the
queue, it tries to deliver all mail again, and it will
continue to try
until the mail either gets delivered or is older than
a predefined
number of days. In the latter case a message is sent
to the sender and
the mail is removed from the queue. If the queue doesn't
get scanned,
the mail doesn't get delivered. At the time when a dialup
connection is
made, a call to sendmail like this:
/usr/lib/sendmail -q
forces an immediate queue scan and starts the mail on
its way to its
destination.
The configuration of sendmail for our purposes can be
very simple. A
standalone system like this will use the service provider
as a
smarthost, which means that all mail not destined for
a user on the
local system, is sent to the smarthost for further delivery.
The version
of sendmail we use, 8.6.12, comes with a number of predefined
configurations that can be found in the cf/cf directory
of the source
distribution. The following fragment from our sendmail.mc
file show you
how we have defined this smarthost:
OSTYPE(linux)
DOMAIN(reseau.nl)
MASQUERADE_AS(reseau.nl)
FEATURE(allmasquerade)
FEATURE(notsticky)
MAILER(local)
MAILER(smtp)
FEATURE(always_add_domain)
FEATURE(use_cw_file)
define('confUSERDB_SPEC', ''/usr/local/lib/users.db'')
define('SMART_HOST',smtp:mail.isp.nl)
DDreseau.nl
# hosts for which we accept and forward mail (must be in .reseau.nl)
CF reseau.nl
FF/etc/sendmail.cw
All mail that is not local is delivered to mail.isp.nl.
This
configuration causes all mail to look as though it originates
from the
reseau.nl domain, for which the service provider plays
MX host. Thus,
all mail destined for our domain is delivered to the
service provider.
news
Setting up news is simple: we use a newsreader (trn)
that is NNTP aware.
This means that all news is retrieved from the news
server news.isp.nl
when it is read. Posting of news is also done on the
news.isp.nl
machine. Slackware comes with a few newsreaders, including
trn and inn,
both in a NNTP flavor and a local flavor. You can set
the name of the
newsserver in a file called /etc/nntpserver. This file
contains the name
of the newsserver and nothing else. If you want to override
this
system-wide setting, you can define an environment variable
called
NNTPSERVER which contain the name of the server you
want to connect to.
Conclusion
Using Linux and publicly available software you can
build a complete
Internet system, but you should be very cautious about
the security of
such a system. This article does not address all the
security issues
related to such a setup, so you must be very careful
in applying this
information. As every system administrator knows, a
secure UNIX system
is achieved only through a number of iterations: the
same goes for an
Internet system.
Happy Linuxing!
About the Author
Arthur Donkers graduated from the Delft University
of Technology with a
degree in Electrical Engineering, with a major in Computer
Architecture.
He has since worked for a number of major software houses
in the
Netherlands. His primary field of interest is data communications.
especially the integration of multi-vendor networksystems.
For the last
four years he worked as an independant consultant for
his own company,
Le Reseau ("The Network").
|