 | Level: Introductory Teodor Zlatanov (tzz@iglou.com), Programmer, Gold Software Systems
01 Nov 2001 Every UNIX administrator is familiar with inetd, the daemon that manages most incoming network connections through a centralized configuration file (inetd.conf). The xinetd daemon is a replacement for inetd that offers many improved or new features, and easier configuration. Ted explains the concepts behind inetd, and gives examples for setting up xinetd at your own site.
The classic inetd daemon has been around for a long time. There are
several ways to replace its functionality, but the most flexible and
easiest way seems to be xinetd. Xinetd does all the things inetd
can do, and a lot more. TCP wrapping, modular configuration,
connection redirection, and load limits on incoming connections are
just a few of the features that make xinetd a nice choice for system
administrators. This article is meant for the beginner to intermediate system
administrator and the explanations and examples will try not to assume
that you are already familiar with inetd. In this article we will look at some simple uses of xinetd, from
installation to implementation of security policies. Before starting
For the purposes of this article, ideally your system should be a recent (2000 or later) mainstream
UNIX (Linux, Solaris, BSD) installation. The examples may work with
earlier versions of Perl and UNIX, and other operating systems, but
their failure to function should be considered an exercise for the
reader to solve. The specific examples given are for Red Hat Linux,
but they should work (with the exception of chkconfig) on other systems as
well.
What's inetd anyway?
To a UNIX system administrator, inetd is as basic as the cp/rm/mv
commands. It's always there, ready to handle incoming connections.
But what is it, really? What does it do? The answer begins with TCP/IP (it also includes UDP, but let's
not worry about that for now). When you make a connection to a host,
you are in fact creating a TCP/IP connection (a socket, usually) --
that's like a telephone call between you and the host. A TCP/IP
connection is uniquely defined by the originating host and the
receiving host, but there's another identifier. If we all connected
to a server, how would it know to distinguish between webserver,
telnet, SSH, FTP, and other connections? Sockets are also defined by
the port used to make the connection. For instance, port 21 is
incoming FTP, 22 is SSH, and 23 is TELNET (you can look in /etc/services on
a UNIX system for most of the rest). Once a connection is made, someone has picked up the phone on the
other end. It can either be an operator or a direct
line. The direct line means you are directly connected to the server,
while the operator is the approach that involves inetd. The operator is really
handling a bunch of incoming direct lines (ports on a host), and
handing them off in person to the program (server) responsible. UDP is a different connection method. Like TCP, it is basically a
conversation with someone, but it's not guaranteed to be reliable.
UDP, to continue the telephone analogy, is like throwing messages on a
conveyor belt, and having the recipient stand on the other end of it.
You can get a lot more messages through on the conveyor belt, but the
recipient may miss a few if there are too many (network traffic is
high) or he takes too long reading the messages (the server is busy). With inetd, you are redirected to a specific server after some checks
are performed. There's just one configuration file, inetd.conf,
managing all the incoming connections. That makes life easier when
adding, deleting, changing, or reviewing services on a system. For
instance, ftp is defined as follows on a Solaris system with TCP wrappers: Listing 1. inetd.conf definition of the FTP service
ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd
|
These are all the necessary parameters for creating an FTP connection.
In brief, we're using TCP/IP (tcp) in stream-oriented (stream) mode,
allowing more than one FTP connection at a time (nowait), running as
root, and invoking FTP (TCP wrappers, which will in
turn invoke the FTP daemon). Is this hard to parse at 1 AM? Absolutely. Is the complexity
necessary? No. Xinetd took the inetd design and modularized it,
meaning that each service can be in its own configuration file.
Xinetd also added features like the TCP wrappers, making configuration
easier. Xinetd preserved the central configuration (operator) approach,
storing all the configuration files in a single place, usually
/etc/xinetd.conf and /etc/xinetd.d/* so that system administration
gets easier. The modular configuration means that you can distribute
a service to several machines by copying it to the xinetd.d directory,
and you can remove it similarly. You can even specify extra include
directories. Finally, the xinetd FAQ (see Resources later in this article)
states that RPC programs don't work too well
with xinetd. No problem, use inetd for RPC and xinetd for everything
else. It's like hiring two operators because one speaks Spanish and
the other speaks everything else.
Introducing xinetd
So what is xinetd? It's just a program, that's all. There's nothing
magical about handling incoming network connections. You could do it
in Perl, Python, or Java. Xinetd was written in C, and it's just as
fast as its predecessor, inetd, if not faster (for instance, the TCP
wrappers don't have to be executed for each incoming connection; they
are loaded into memory at startup). Xinetd is a work in progress. (You may have an outdated version, so make
sure you check the home page for the latest; see Resources.) Because it's a work in progress, security
holes in xinetd are patched quickly, unlike inetd vulnerabilities, which
usually take a lot longer to get patched. Of course, xinetd
comes with the source code, so you can review it and see for yourself
where vulnerabilities might exist. How do you define services with xinetd? You write a service file that
specifies the specific configuration in addition to the generic
parameters specified in /etc/xinetd.conf. So, if /etc/xinetd.conf
says: Listing 2. Example xinetd.conf (standard Red Hat 7.1)
defaults
{
instances = 60
log_type = SYSLOG authpriv
log_on_success = HOST PID
log_on_failure = HOST
cps = 25 30
}
service telnet
{
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
log_on_failure += USERID
disable = yes
}
includedir /etc/xinetd.d
|
Every service file you place in /etc/xinetd.d will inherit those
defaults, and specify its own parameters. The telnet service is
defined at the top level here, instead of in the subdirectory. That's
perfectly fine, and this modularity allows complex configurations. To get xinetd to re-read the configuration file, you don't have to
restart it. Simply send it the USR2 signal. What do those parameters mean? Let's run through the whole list. You
can also see the list with man xinetd.conf from the command line, if
that man page was installed properly, but this summary will try to
explain the parameters in simpler terms, without assuming you already
know all about sockets and services. Some parameters (rpc_version,
rpc_number) were skipped. General parameters
-
id
- The unique name for this service. A service name is already
specified before the braces, but the ID makes it possible to have
several protocols for a service that's logically the same. This is
of limited use to the casual user. The NFS services, for
instance, can run over the UDP or TCP transmission protocols. The
time service, which is internal to xinetd, is provided in a TCP and
a UDP version with Red Hat Linux 7.1 in /etc/xinetd.d/time and
/etc/xinetd.d/time-udp.
-
type
- This should actually be called "specialtype", because it only
applies to special services. It can be a combination of "RPC" for
RPC services (remote procedure calls, introduced by Sun, causes of
many security issues, and best avoided); "INTERNAL" for services
built into xinetd, such as the time service; and "UNLISTED" for
nonstandard services you won't find in the system lists
(/etc/services or /etc/rpc for RPC services).
-
flags
- All the extra flags go here. The list is long and quite
technical; the interesting flags are REUSE (for socket reuse,
such as telnet), NAMEINARGS/NOLIBWRAP (if you want to invoke the TCP
wrappers manually or you want to avoid the wrappers altogether),
NODELAY/KEEPALIVE (for tuning TCP sockets), DISABLE (overrides the
top-level "disable" parameter), and SENSOR (for detecting and
thwarting some types of denial-of-service network attacks).
-
disable
- You always want it set to "no" unless you want the service
to be disabled. The Red Hat Linux chkconfig program will switch the
"disable" parameter on or off for you; it is probably easier to
enable and disable specific services with chkconfig under Red Hat
than to do it manually. Note that chkconfig expects to find the
service file in /etc/xinetd.d/SERVICE. So for the example in
Listing 2 above, chkconfig will not turn telnet on/off when requested.
This could be considered a bug or a feature, depending on your
viewpoint.
-
socket_type
- Usually you want this set to "stream" unless you are
using UDP services, in which case set this to "dgram". There's also
"raw" and "seqpacket", but those are pretty unusual.
-
protocol
- This is the protocol to be used for the connection,
usually "tcp" or "udp", though in theory you can use anything from
/etc/protocols.
-
wait
- If set to "no", xinetd will start a new handler for that
service on every connection. If "yes", xinetd expects the handler
to deal with all subsequent connections until it dies. In most
cases, this is "no".
-
server, server_args
- The program name for the handler, and the
parameters it should get. The handler name should not be in the
arguments, as is the case with inetd.
-
port
- The port of the service. Usually unnecessary, since the port is mapped to the service by the /etc/services file.
-
redirect
- Allows xinetd to send all traffic to the service to
another host. Thus, firewalled hosts can accept secure traffic
through a central xinetd forwarder, yet have no connections to the
outside network. This feature can also be adopted, with some work,
to do service failover between two hosts.
-
banner, banner_success, banner_fail
- A custom block of text from a
file to be printed upon any/a successful/an unsuccessful
connection.
-
enabled
- Supplements the "disabled" parameter and the DISABLE flag
on a global level.
-
include, includedir
- Tells xinetd to include a file or a directory.
Environment parameters
-
user, group, umask, groups
- What UNIX attributes xinetd should
impersonate when starting the service handler. This is mostly for
insecure services.
-
nice
- A UNIX priority level that determines how important this
service is to the system. You can tune it for your system; take a
look at the "nice" man page.
-
env
- Environment variables for the service handler.
-
passenv
- What environment variables from xinetd should be passed
down to the service handler.
Resource management parameters
-
instances
- Number of handlers that can be started at once. This can be
tuned to prevent denial-of-service attacks. Set it to "UNLIMITED"
if you want the default (no limits) behavior.
-
max_load
- I: )
If the system is too loaded, stop accepting connections.
The load numbers are system dependent, and should be tuned only
if you really know what you are doing.
-
rlimit_as, rlmist_cpu, rlimit_data, rlimit_rss, rlimit_stack
- The rlimit parameters specify resource limits (memory, CPU, and
specific memory areas) for service handlers.
Security-specific parameters
-
only_from, no_access
- Supplementary to the TCP wrappers, this is a
way to block hosts making connections to us. Note that the default
is to allow access to everyone, unless the TCP wrappers (whose rules
are usually in /etc/hosts.allow) say otherwise.
-
access_times
- The times of day that a service is available. For
instance, "6:00-23:00" means the service will be available from 6 AM
to 11:01 PM.
-
log_type, log_on_success, log_on_failure
- Various logging options.
The USERID flag in particular can be troublesome, because it slows
things down to interrogate the connecting machine about the user
connecting to us. Avoid USERID if possible.
-
bind
- Allows a service to be specific to an interface, usually in
the interest of security. For instance, the FTP service on the
inside network would be just FTP, while outside FTP connections
would generate intruder alerts. The "id" parameter would be useful
here.
-
per_source
- Specifies the maximum instances of a service from a
source IP. Useful for handling single-source denial-of-service
attacks or buggy programs making too many connections.
-
cps
- Maximum connections per second allowed, and the number of
seconds before the service is enabled again. "30 45" would mean "30
incoming connections per second, and wait 45 seconds if that limit
is exceeded". For counteracting denial-of-service attacks, mostly.
-
deny_time
- How long service will be denied to someone who sets off a
SENSOR flag.
 |
Replacing TCP wrappers
The classic TCP wrappers package is a very useful tool. Through a
centralized file, usually /etc/hosts.allow and /etc/hosts.deny, access
can be allowed or denied to any hosts necessary, per service.
Unfortunately, the TCP wrapper library does not know much about system
loads, resource limits, multiple attacks, and so on. Xinetd
incorporates the TCP wrapper functionality (through the libwrap
library), so you can move to xinetd smoothly and keep using the same
configuration files from before. That's pretty much all there is to the migration. Keep your old
hosts.deny and hosts.allow files, and xinetd will happily follow
them. Keep in mind, however, that xinetd has many options for control
of connections that improve on the TCP wrappers. For instance,
limiting connections per second, or connections when the load is too
high, can be an invaluable aid to server management. Make sure you compile xinetd with the libwrap option, or it will not
know about the TCP wrappers. If xinetd comes from an RPM on Red Hat
Linux, make sure you test that the TCP wrapper files work properly
BEFORE you put the machine out in the open.
Advanced usage: failover
Although there are many ways in which xinetd could be used, the
redirect parameter gives us the most interesting avenues. Failover,
we all know, is pretty hard to do, and hardware failover is expensive.
The approach described here is cheap and effective, through simple
software. It does have a single point of failure -- the redirecting
station, so you should consider whether that's acceptable. If it's not,
well, hardware failover is expensive for a reason. First, decide on a way to pick an "active" machine out of two or more.
Let's assume you do it through a script, set_active.pl (we are going
to do this for the telnet service, but it will work for any other
service that can be switched to an alternate server with no ill
effects). The script will take a machine name, which we will use to
set the new failover, and a service name, which will give us the right
/etc/xinetd.d/SERVICE file to edit. Feel free to customize the script
to edit a different file, or take different parameters. The job could
be done with a one-liner "perl -p -i -e" script, but this way you can
expand a lot more in the future, and error-check your parameters. This is simple enough. Now you just have to decide on a procedure to
invoke this script - either manually, through a cron job, or triggered
by another program. It becomes an architecture decision at this
point. Don't forget to send the USR2 signal to xinetd at this point,
or just restart it if you wish. Automating signals can be done with
"pkill -USR2 xinetd" on Red Hat Linux, and restarting xinetd is just
"/etc/rc.d/init.d/xinetd restart" on Linux or something similar on
most UNIX systems. This sort of failover will NOT work for database connectivity without
a lot of extra work on the database side. You are best advised to use
it for protocols such as rsync, ssh, ftp, and telnet, where the
failover machines don't depend on each other.
Conclusion
Clearly, the plethora of features xinetd offers is a good reason to
use it. Don't forget, however, the other benefits of xinetd: bugs are
fixed as soon as they are reported, the source code is freely
available, and migrating the existing inetd configuration (when you
use the itox helper program that comes with xinetd) is a snap. Why not use xinetd? Backward compatibility would be your best reason,
followed closely by incompatibility with your specific platform.
The xinetd software is most popular on Solaris and Linux servers, so
your particular platform may have issues that are unresolved.
Resources
About the author  | |  | Teodor Zlatanov graduated with an M.S. in computer engineering from Boston University in 1999. He has worked as a programmer since 1992, using Perl, Java, C, and C++. His interests are in open source work on text parsing, 3-tier client-server database architectures, UNIX system administration, CORBA, and project management. Contact Teodor at
tzz@iglou.com. |
Rate this page
|  |