An Unofficial Xinetd Tutorial

Submitted by curator on Thu, 2004/07/15 - 04:50.

Contents:

  • What xinetd does
  • Installation
  • Configuration file basics
  • A Simple Configuration with little access control
  • A More Complicated Configuration with Access Control
  • Day to day use of xinetd (or updating the xinetd.conf)
  • Port redirection
  • Additional info for Mac OS X (Server)
  • Parting words

What xinetd does

xinetd is a secure replacement for inetd, and a more efficient replacement for inetd and tcp_wrappers. It sports a number of features that make it a good choice for securing a server. These include access control (based on source address, destination address, and time), extensive logging, and the ability to bind services to specific interfaces. This tutorial will attempt to give an administrator the necessary tools to install, configure, and maintain xinetd.

Being a "secure replacement for inetd", xinetd attempts to do everything that inetd does, only securely. This means that, like inetd, it is a super-server. Both xinetd and inetd read in their configuration files which are basically a list of IP services to listen to. The super-servers "listen" on the ports defined by those listed in configuration files for connection attemps on those ports. When it receives a connection on a port it thinks it has a service for, it attempts to start the requisite server. There are exceptions to this scheme, mostly for single-threaded servers, where the super-servers simply start the server, which then takes care of service requests until the server dies.

Where inetd and xinetd begin to differ is xinetd's support for RPC services; it isn't great. The author of xinetd suggests that an admin running an rpc service do so from inetd. xinetd and inetd can cohabitate quite peacefully. Another thing that differs is the configuration files; the two are mutually incompatible. xinetd's conf file contains more information than inetd does in order to handle the additional security parameters.

Installation

First you need to download the latest source from xinetd.org to some convenient directory (ie., /usr/local/src). Once downloaded, expand the archive and change to its directory. (If running Mac OS X(S), there is a section later in this tutorial that has additional to assist you in this process.)

It is possible to compile xinetd with libwrap support by adding the --with-libwrap flag to ./configure. This allows xinetd to use the hosts.{allow | deny} mechanism. To do so, you'll need to have tcp_wrappers installed, and the requisite libraries in place. The decision to do so is up to the individual admin. This option exists mostly to help those more comfortable with the wrapper mechanism to more easily configure xinetd. We suggest that you do not compile the software with libwrap support unless you have the need; it is best and most flexible to do without it.

Further options are available (such as install paths, ipv6 support, etc) and you should read the install docs to determince which of these settings is correct for you.

Once you've run ./configure with the options you need, run "make" followed by "make install" as root. Assuming xinetd makes and installs with no errors, the next thing to do is configure it. If it doesn't, you may wish to subscribe to the xinetd maillist by sending a message to with a body of "subscribe xinetd".

Configuration file basics

xinetd ships with a perl script (installed in the same directory as the xinetd binary) that conveniently converts an inetd.conf into a xinetd.conf. It may be invoked as "/usr/sbin/xconv.pl < /etc/inetd.conf > /tmp/xinetd.conf", where "/usr/sbin" is your path to the xinetd executable.

xconv.pl will try to make a xinetd.conf from your original inetd.conf as best it can, but most admins will want (read: need) to modify the xinetd.conf it generates. For instance, many BSD's (including Mac OS X [Server]) require that each service have a "groups = yes" setting.

The defaults section

xconv.pl by default makes a defaults section that looks something like this:

defaults

{

#The maximum number of requests a particular service may handle

# at once.

instances = 25

# The type of logging. This logs to a file that is specified.

# Another option is: SYSLOG syslog_facility [syslog_level]

log_type = FILE /var/log/servicelog

# What to log when the connection succeeds.

# PID logs the pid of the server processing the request.

# HOST logs the remote host's ip address.

# USERID logs the remote user (using RFC 1413)

# EXIT logs the exit status of the server.

# DURATION logs the duration of the session.

log_on_success = HOST PID

# What to log when the connection fails. Same options as above

log_on_failure = HOST RECORD

# The maximum number of connections a specific IP address can

# have to a specific service.

per_source = 5

}

Here we can begin to see some of the basic characteristics of a conf file. Sections have the general form:

sectiontypeorname

{

<attribute> <assign_op> <value<value> ...

<anotherattribute> <assign_op> <value<value> ...

...

}

Lines beginning with "#" are comments. Whitespace lines are ignored. There can be only one defaults section in a xinetd.conf file. In the defaults section the assign_op is only a "=".

The defaults section, as its name implies, specifies default settings for the services specified elsewhere in the file. The defaults section can contain a number of attributes: log_type, log_on_success, log_on_failure, only_from, no_access, passenv, instances, disabled, and enabled. Of these, only log_type and instances do not display a "cumulative effect". The cumulative effect is the ability to specify an attribute multiple times within the section.

The first attribute we see here is instances (instances = 25). It specifies the maximum number of requests any service may handle at one once. This setting says that for any service that doesn't specify it's own instances attribute, that service will be limited to 25 connections. The next attribute is log_type (FILE /var/log/servicelog), which specifies the log type (either FILE or SYSLOG) and where specifically to log to. For the FILE log type, this means the full path to the log file, and for the SYSLOG log type it syslog facility and optionally the syslog level.

The next two attributes, log_on_success and log_on_failure, deal with what is to be logged when a server is started and exited. The log_on_success attribute accepts five different values: PID (log of the pid xinetd uses to spawn the server), HOST (logs the remote host's IP address), USERID (logs the userid of the remote user as returned by remote identd service), EXIT (logs the exit status of the server when it exits), and DURATION ( logs the duration of the server session). Here, only the host's address and the server's pid are logged by default (log_on_success = HOST PID). The log_on_failure attribute comes into play when either the server could not be started due to lack of resources, or access was denied via the rules in the conf file. It has four valid values: HOST (again, the remote host's IP address), USERID (same as log_on_success), ATTEMPT (simple acknowledge that a failed attempt was made), and RECORD (grabs as much info about the remote end as is possible). In this default xinetd.conf, the remote machine's address as well as any other information it can garner are logged (log_on_failure = HOST RECORD).

The last attribute shown in the default configuration is the per_source attribute. This specifies the maximum number of connections for any one remote address to a service. It can either be an integer, or the special value "UNLIMITED" which is at is says, an unlimited number of connections. Here it defaults to a maximum of 5 connections per server per IP address (per_source = 5).

As you can see, there are a number of attributes not accounted for in the default configuration. I'll briefly discuss the missing attributes here, as most also apply to the individual service sections we'll get into later. To explicitly allow and deny addresses and networks, xinetd provides two attributes called only_from, and no_access. There are a number of ways to specify an ip address or range of addresses, including dotted decimal quads, CIDR notation, and factorized quads.

The disabled and enabled attributes are meant to be lists of service names (see the next section) that are enabled and disabled. If enabled is specified, then any services not listed as values are considered. The same is true with the disabled attribute, with the unlisted services being considered enabled. Should a service be listed as a value for both enabled and disabled, the disabled attribute overrides. These two attributes are only available in the defaults section.

The remaining attribute available in the defaults section is passenv. The values for passenv are items in a list of environment variables from xinetd's environment to send to the server when it gets instantiated.

With this brief intro to the defaults section complete, we'll move on to the service sections. But never fear, we'll return to the defaults section and its attributes later with the sample configurations.

Services sections

The services section define the individual services to be started by xinetd and how they are to be started. Their general form is

service <servicename>

{

<attribute> <assign_op> <value> <value> ...

<anotherattribute> <assign_op> <value> <value> ...

...

}

Like the defaults section, the services sections have a number of attributes that can be specified: type, flags, socket_type, protocol, wait, user, group, instances, nice, server, server_args, only_from, no_access, access_times, log_type, log_on_success, log_on_failure, rpc_version, rpc_number, env, passenv, port, redirect, bind, interface, banner, banner_success, banner_fail, per_source, cps, max_load, and groups. That may seem like a lot, but realize that you'll need about 7 of them to setup a basic service.

xconv.pl makes services sections that look like this:

service ftp

{

flags = REUSE NAMEINARGS

socket_type = stream

protocol = tcp

wait = no

user = root

server = /usr/libexec/ftpd

server_args = ftpd -l

}

service telnet

{

flags = REUSE NAMEINARGS

socket_type = stream

protocol = tcp

wait = no

user = root

server = /usr/libexec/telnetd

server_args = telnetd

}

xconv.pl will only translate those services in the inetd.conf that are uncommented, and those it does translate are set to their most basic and compatible mode.

The first thing you'll probably notice here are that the services sections are split into individual service configurations. The servicename is a unique name for a service you wish to configure in the following section. This servicename is what is used to look up the service information in /etc/services (or equivalent).

The flags attribute can generally be left as is. The REUSE value is generally a good thing and should be left unless you have a specific reason to remove it. NAMEINARGS specifies that the first value in the server_args attribute will be used as the first argument when starting the service specified. This is most useful when using tcpd; you would specify tcpd in the server attribute, and give it the service ("ftpd -l") in the server_args attribute. The flags attribute is optional. The default configurations should work fine in most cases.

The attributes socket_type, protocol, wait, and user attributes are all synonymous with their inetd counter parts. In all cases I've seen, these can be left alone. Of these, protocol is optional.

We've already talked about server and server_args a bit. The server attribute is simply the full path to the server's executable, very much a required field. Server_args is a list arguments to be passed to the above executable. Though the xconv.pl application lists the server's executable name in this attribute, it is not necessary, nor particularly desirable (as stated by the xinetd man pages). However, there doesn't seem to be any specific problems with leaving the attribute as xconv.pl sets it. If you wish to delete the name from the attributes, remember to remove the NAMEINARGS flag from the flags attribute as well. The server_args attribute must included in a service definition, even if it is left blank.

A minimally configured version of the example ftp service would look as follows:

service ftp

{

socket_type = stream

wait = no

user = root

server = /usr/libexec/ftpd

server_args = -l

}

If you happen to be using rpc services, protocol, rpc_version, and rpc_number (if it's not listed in /etc/rpc or your equivalent) attributes are also mandatory.

For the most part these are the attributes that are required to properly configure a service under xinetd. There are, however, two exceptions: if you're running a BSD, or if the service you're configuring isn't listed in /etc/services (or equivalent). Most BSD's seem to require the addition of the groups (groups = yes) attribute to the service configuration. If you happen to be configuring a service that isn't in /etc/services., you need to add the port attribute to the service configuration (ie, port = 22, for sshd). There are some additional variations when dealing with xinetd's internal's services, but we'll discuss those later.

This is, of course, not the end of the story; we want to not only have functioning services, we want to control access to these services. To this end, xinetd provides us with a number of pertinent service attributes: instances, nice, only_from, no_access, access_times, per_source, cps, and max_load.

Instances accepts an integer as it's value, and as noted in the previous defaults section, specifies the maximum number of simultaneous connections to the particular service. As with any of these values, setting this attribute in the service definition should override whatever is in the defaults section. Nice is related to the unix nice command. It takes an integer that specifies the services process priority. The max_load attribute accepts a floating point value, and specifies the load at which the server will stop accepting connections, based on a one-minute cpu load average. Due to it's OS dependency, this only works on Linux and Solaris right now. Then there's the cps attribute, which also takes an integer and is used to rate limit (in connections per second) a service. The last of these quantitative limiters is the per_source attribute. It takes an integer and set the limit on the maximum number of connections a single host may have to the specified service.

The attributes only_from and no_access are very much related too each other, in as much as they take the same values, and are of supplimentary function. The accept a list of ip addresses, network names (via /etc/networks or equivalent), host/domain names (via reverse lookup), or networks (in CIDR notation). If both only_from and no_access are specified for a service, the best fit match is used (ie, a host is a better match than a network, is better than a network with a larger subnet). The no_access attribute takes precedence over only_from in case of a complete duplication. If you include either attribute, but leave either blank, they disallow all addresses. The last access control attribute is access_times. This accepts time intervals in HH:MM-HH:MM 24-hour notation. Access is granted during these intervals.

The remaining attributes have to do with logging (and have already been discussed in the defaults section), and some nuances of service configuration. Some are covered in a later section, but for more information on these handfull of attributes, I would recommend reading the man pages.

A Simple Configuration with little access control

# This is a modified and cleaned up version of a xinetd.conf

# originally created by xconv.pl.

# The defaults section sets some information for all services

defaults

{

#The maximum number of requests a particular service may handle

# at once.

instances = 25

# The type of logging. This logs to a file that is specified.

# Another option is: SYSLOG syslog_facility [syslog_level]

log_type = FILE /var/log/servicelog

# What to log when the connection succeeds.

# PID logs the pid of the server processing the request.

# HOST logs the remote host's ip address.

# USERID logs the remote user (using RFC 1413)

# EXIT logs the exit status of the server.

# DURATION logs the duration of the session.

log_on_success = HOST PID

# What to log when the connection fails. Same options as above

log_on_failure = HOST RECORD

# The maximum number of connections a specific IP address can

# have to a specific service.

per_source = 25

}

service ftp

{

socket_type = stream

wait = no

user = root

server = /usr/libexec/ftpd

server_args = -l

}

service nntp

{

socket_type = stream

wait = no

user = usenet

server = /usr/libexec/nntpd

server_args =

}

service telnet

{

socket_type = stream

wait = no

user = root

server = /usr/libexec/telnetd

server_args =

}

A More Complicated Configuration with Access Control

# This is a modified and cleaned up version of a xinetd.conf

# originally created by xconv.pl.

# The defaults section sets some information for all services

defaults

{

#The maximum number of requests a particular service may handle

# at once.

instances = 25

# The type of logging. This logs to a file that is specified.

# Another option is: SYSLOG syslog_facility [syslog_level]

log_type = FILE /var/log/servicelog

# What to log when the connection succeeds.

# PID logs the pid of the server processing the request.

# HOST logs the remote host's ip address.

# USERID logs the remote user (using RFC 1413)

# EXIT logs the exit status of the server.

# DURATION logs the duration of the session.

log_on_success = HOST PID

# What to log when the connection fails. Same options as above

log_on_failure = HOST RECORD

# The maximum number of connections a specific IP address can

# have to a specific service.

per_source = 25

# Disabled nntp

disabled = nntp

#Whatever you do, don't let the evil bastards in

no_access = .evilbastards.com

}

service ftp

{

socket_type = stream

wait = no

user = root

server = /usr/libexec/ftpd

server_args = -l

#Allow access from the local network (ie, 192.168.0.0/24)

only_from = 192.168.0.0/24

#And from two remote locations

only_from = 10.1.1.2 roadwarrior.sampleconfig.com

#But not from the evil HR director's subnet

no_access = 192.168.0.128/27

log_on_success = PID HOST EXIT DURATION

log_on_failure = ATTEMPT HOST RECORD