2021 Call for Code Awards: Live from New York, with SNL’s Colin Jost! Learn more

Archived | Working with inetd and xinetd, the Internet super serve

Archived content

Archive date: 2019-06-25

This content is no longer being updated or maintained. The content is provided “as is.” Given the rapid evolution of technology, some content, steps, or illustrations may have changed.

If you want to be pedantic, UNIX® is a kernel, or the low-level software that arbiters access to a machine’s resources, such as the file system, memory, and the processor. More colloquially, though, UNIX refers to the entire universe of software running atop the operating system. In fact, it’s common to say, “It’s a UNIX machine,” to express the system’s fundamental capabilities: a UNIX machine typically offers a shell interface, simultaneous access, strong security, and a wide variety of networked services.

Indeed, UNIX (the kernel, et al.) is often chosen specifically for its networking applications. FTP, POP, SMTP, and HTTP were all implemented initially on UNIX machines and continue to drive usage. UNIX systems also run services, often referred to as daemons, to synchronize with a central clock (the Network Time Protocol), exchange news postings (the Net News Transfer Protocol), resolve hostnames into IP addresses (DNS), and more. A partial but robust list of oft-used services can be found in /etc/services on most UNIX machines. The file resembles Listing 1.

Listing 1. Some common entries found in /etc/services, the UNIX catalog of network services

ftp             21/tcp
fsp             21/udp          fspd
ssh             22/tcp
ssh             22/udp
telnet          23/tcp
smtp            25/tcp          mail

Each entry in /etc/services lists the name of the service; the port number and protocol that the service uses (either TCP or UDP); and no, one, or more aliases for the service name. Each system daemon examines /etc/services to find the proper port and protocol to use to offer its service.

For example, the daemon to process incoming e-mail looks up “smtp” (the proper name) or “mail” (one of the aliases) and listens for incoming TCP connections on port 25. Similarly, the remote login daemon searches for “ssh” in the file and listens for incoming TCP connections on port 22.

Briefly, TCP establishes a persistent connection between two machines to transfer data. Moreover, a TCP connection is reliable, meaning that the two machines cooperate to guarantee the delivery of a piece of data. By comparison, UDP is unreliable, meaning a datum may or may not arrive at its destination. The sending machine transmits the data and moves on. You can think of a port number as a unique address. It directs traffic to a specific destination on the remote machine. If a machine’s hostname is the equivalent of a city block, the port number is an individual street address.

If a machine is central to your organization or if you simply operate a sole server, the system may run 5, 10, or even more daemons. For instance, a server for a small company might run services to synchronize time with a world clock, serve Web pages, traffic e-mail, permit remote shell access, print pages, transfer files, connect to a database, monitor system stability, serve domain names, and share files via the Network File System (NFS). Such a configuration is not uncommon, largely because a daemon does not impose great overhead. Daemons are usually designed to sit idle and wait for requests. When a demand for service appears, the daemon wakes, reacts to and processes the request, and then returns to slumber.

Nonetheless, a large contingent of dormant processes can affect system performance. To be sure, when you expect a service to be in great demand, such as sustained Web visits, a perennial daemon makes sense. Otherwise, the daemon may best be reconfigured to execute as needed.

But how can a system offer an always-on service yet launch the service as needed? The solution is a proxy service that anticipates a variety of incoming requests and launches the appropriate service on demand for subsequent processing. On UNIX and Linux® systems, the proxy is called inetd.

Given a list of services, inetd watches those services’ ports and protocols for requests. When activity occurs, inetd maps the incoming request to standard input (stdin), standout output (stdout), and standard error (stderr) and launches the proper daemon. The service processes the data and terminates. inetd keeps resource consumption to a minimum and makes daemons easier to write. Figure 1 shows the difference between a system running multiple daemons without inetd and one running inetd as a proxy.

Figure 1. Systems running multiple daemons with and without inetd

Systems running multiple daemons with and without inetd

At top, each service runs as a separate, perennial process, or daemon. Each daemon listens on a specific port for incoming requests and processes each demand. At bottom, inetd listens to a variety of ports and initiates a service upon receiving a request. The service handles the demand and exits. Some services are exceptions. For example, the SMTP server, which traffics e-mail, typically runs independently.

Given its role, inetd is often referred to as a “super server.” In recent years, inetd has been replaced with a variant named xinetd. Both pieces of software serve the same purpose, but the latter is more secure and offers many features to restrict and throttle access when a system’s load rises. Configuration of inetd and xinetd is similar but not identical, and a system can run either inetd or xinetd but not both. Because the latter is more secure, it’s preferred and is used throughout the rest of this article.

Installing xinetd on your system

Like much of the other software discussed in this column, xinetd is open source and readily builds on UNIX and variants such as OpenBSD and Linux. As of the end of October 2009, the latest version of xinetd is 2.3.14, available from the xinetd home page (see Related topics). After you download the xinetd source code, unpack the tarball, run the configuration script (see Listing 2), and build the software. Before you install xinetd, be sure to back up your inetd configuration, if any, then disable and/or delete inetd. The steps to disable inetd depend on your UNIX variant; see your system’s inetd man page for specifics. You will likely need superuser access to make such a change.

Listing 2. Install xinetd

wget http://www.xinetd.org/xinetd-2.3.14.tar.gz
tar xgz xinetd-2.3.14.tar.gz
cd xinetd-2.3.14
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking target system type... i686-pc-linux-gnu
cd libs/src/portable ; make CC='gcc' CFLAGS='-g -O2  -I../../include' install
make[1]: Entering directory `/home/strike/tmp/xinetd-2.3.14/libs/src/portable'
gcc -g -O2  -I../../include   -c -o difftime.o difftime.c
# Disable and/or remove inetd
sudo make install

Again, the steps to enable xinetd so that it launches with each system reboot are specific to your system.

Optionally, if your version of UNIX has a package manager, you may be able to install xinetd directly from a pre-built binary package. For example, on Ubuntu Linux, you can disable inetd and install and enable xinetd with a single command:

sudo apt-get install xinetd

No matter how you install and enable xinetd, if you ran inetd previously, you must convert your inetd configuration file, inetd.conf, to an xinetd-compatible file. You can perform the transform manually, or you can use a conversion script provided with xinetd to make the changes for you:

xconv.pl < /etc/inetd.conf > /etc/xinetd.conf
mv /etc/inetd.conf /etc/inetd.conf.sav

Xconv.pl is a Perl script provided with xinetd. The latter step — to move the inetd configuration file out of its standard location — is merely a precaution.

You can configure xinetd completely in /etc/xinetd.conf. However, by convention, it’s typical to provide defaults in the file and include individual configuration files — one file per service — found in a special directory named /etc/xinetd.d. For example, this is the xinetd configuration installed from scratch on Ubuntu:

    log_type = SYSLOG daemon info

includedir /etc/xinetd.d

defaults provides values for all services that xinetd controls. These global defaults can be overridden by an individual service. Here, a default value for log_type specifies where each daemon should emit log entries, if any are enabled. The option SYSLOG sends the output to syslog, the central system log. info asks for informational messages only. Other values include emerg, alert, crit, err, warning, notice, and debug. The first value, emerg, generates the least amount of output from xinetd; the final value, debug, provides the most. If you have difficulties launching a particular service from xinetd, enable the more verbose log options to help determine the cause of the failure.

The files found in /etc/xinetd.d adhere to the same format at xinetd.conf. There is an operation with no, one, or more operands and a section of variables and values within braces ({}). For example, Listing 3 is /etc/xinetd.d/imap, an entry you might use for an IMAP service. (IMAP is a mailbox protocol for reading and managing e-mail. It has a significant advantage over POP: IMAP mailboxes can be kept in sync across any number of systems.)

Listing 3. /etc/xinetd.d/imap

service imap
    socket_type    = stream
    protocol       = tcp
    wait           = no
    user           = root
    only_from      = localhost
    banner         = /usr/local/etc/deny_banner
    server         = /usr/local/sbin/imapd

This is a common service configuration file. Let’s break it down:

  • The first line specifies this is a service and names the service.
  • socket_type describes how the connection works and is usually either stream for TCP connections or dgram for UDP services.
  • wait controls whether xinetd handles one connection at a time (wait=yes) or multiple connections at a time (wait=no).
  • user dictates what the daemon should run as. More often than not, the user is root, the superuser, but some services prefer or must be run as a separate user created specifically for the service.
  • only_from demonstrates how you can limit which systems can initiate requests for a service. Here, only those systems on the 198.72.5 subnet and the localhost can use the IMAP service. The rightmost zero acts as a wildcard; any system with the IP address prefix 198.72.5 is permitted. You can use several notations to specify systems; see the xinetd.conf man page for details. (Type man 5 xinetd.conf.)
  • If access is prohibited, the contents of the file /usr/local/etc/deny_banner are sent to the client.
  • Finally, server names the executable to run if access is granted.

The configuration for a service can be quite expressive. You can provide the service during specific times of day (see the access_times option) or only if demand for the machine measured by the load average is below a threshold. You can also redirect an incoming service request to a wholly different server (see redirect).

For the paranoid, xinetd also supports an option called chroot. chroot, if you’ve never heard the term, alters the root directory for a process. Once you change to a new root (hence, chroot), files outside the root and its subdirectories are effectively nonexistent. In other words, if you use chroot to change /tmp/fake_root, all file system resources outside of /tmp/fake_root are inaccessible to the process. chroot is an ideal technique to segregate the resources your service has access to from the rest of the system. For example, you might run an FTP service under chroot so that no one can gain access to any file save those in the new root. (This is actually a best practice for FTP.)

Running a service under xinetd

To demonstrate xinetd and how easy it is to turn a vanilla application into a daemon, let’s write a Ruby script to return an index of text files it has access to. The script is shown in Listing 4.

Listing 4. A Ruby script to catalog a list of text files

#! /usr/bin/env ruby

txtfiles = File.join( "/tmp/xinetd/", "**", "*.txt")
Dir.glob( txtfiles ).each do |filename|
  puts "#{filename}"

You must follow a few guidelines to enable a new service:

  • Choose an unused port above 1024 for your service. (Ports 1-1024 are reserved for the superuser’s use.)
  • As the superuser, edit the service catalog /etc/services, and add the name, port, and protocol of your service. For instance, you might add the entry find 11000/tcp for the Ruby script running on port 11000 via TCP.
  • Create an entry in /etc/xinetd.d for your service. The entry might resemble this one for the Ruby script:

    service find
        socket_type     = stream
        protocol        = tcp
        user            = martin
        wait            = no
        server          = /tmp/xinetd/find.rb
        log_type        = SYSLOG daemon debug

    The snippet should look familiar, albeit with small differences. The script runs as the user martin, because it requires no special privileges to function. In general, always provide the least privileges possible — not just here, but whenever you grant access to any system resource. wait=no must be set for TCP protocol services. server points to the script or executable to run, while log_type specifies additional logging to help iron out any wrinkles in the service.

  • Restart xinetd, or send its process a signal to force a reset. To restart xinetd, look for a control script in /etc/init.d or wherever your system keeps its startup scripts. Restart by running something akin to:

    sudo /etc/init.d/xinetd restart

    Another option is to signal the xinetd daemon to reset. The signal SIGHUP forces xinetd to re-read its configuration and potentially close connections based on new parameters. The command to use is:

    sudo pkill -SIGHUP xinetd

    If your system does not have pkill, which finds a process ID given a process name, use ps aux | grep xinetd to find the process number, and follow that with sudo kill -SIGHUP _pid, where pid is the process ID.

To test the new service, make a directory named /tmp/xinetd, create the Ruby script, and save it in /tmp/xinetd/find.rb. Make the file executable with chmod +x /tmp/xinetd/find.rb. Next, create some directories and text files:

mkdir a b c
touch a/d.txt b/e.txt

You can now test your new service. When an inbound connection arrives on port 11000, xinetd launches the Ruby script. Any script output sent to standard output is emitted to standard out on the originating machine. This script does not require input, but if it did, standard input on the originating machine would be passed to the script. Telnet provides an easy way to connect to any service:

telnet localhost 11000
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

Success! The port opened, control was passed to the script, and it generated the expected output.

Many reasons to run xinetd

xinetd offers many advantages. It conserves resources, running daemons only when needed. It provides an additional layer of security and can “box” a service into a directory with “change root.” Best of all, it can turn virtually any script or program into a service. One caveat: if your service becomes especially popular, consider rewriting it in an efficient language such as C. The faster you can process a request, the better.