Cover V05, I01
Article
Sidebar 1
Sidebar 2
Sidebar 3

jan96.tar


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").