Many Linux systems run a super-server, or a software server that handles the initial stages of connection requests on behalf of other software servers. Super servers typically handle connections for small (or seldom-used) servers, such as Telnet, FTP, POP, IMAP, SWAT, SANE, and VNC, just to name a few. Each of those servers can be run standalone without the benefit of a super server, but running a super server typically results in reduced memory load when the servers it proxies for aren’t being accessed, albeit with some overhead and lag during connection attempts. (Some servers cannot be managed by a super server.)
One big advantage of using a super-server is the extra layer of security it provides. A modern super-server, such as xinetd, includes built-in access control features that can limit access to subjugated servers. Unfortunately, most out-of-the-box configurations don’t utilize the many access control features of xinetd, so this month, let’s look at how to enhance the security of your network services using xinetd as a watchful mediator.
xinetd Basics
One of xinetd ’s advantages over the older inetd is that xinetd supports an includedir directive in its main configuration file, /etc/xinetd.conf. When this line is present, all of the files in the specified directory (except for those whose names end in a tilde or that include a dot) are read and parsed as supplementary configuration files. Every major distribution that uses xinetdas its super-server includes an includedir directive in its main xinetd.conf file; the directive typically points to /etc/xinetd.d.
By dividing the configuration of xinetd into a collection of files, each server package can include or generate its own xinetd configuration file, such as /etc/xinetd.d/cups-lpd for the LPDserver component of the Common Unix Printing System (CUPS) server. When the CUPS package is installed, xinetd is automatically configured to use the new server — or it can be, if the cups-lpd file activates the server. Frequently, packages leave the server inactive for security reasons.
To activate a newly-installed server, edit its xinetd configuration file. You’ll see an entry that looks something like this:
service printer { socket_type = stream protocol = tcp wait = no user = lp server = /usr/lib/cups/daemon/cups-lpd disable = yes }
To enable the server, you must change the line disable=yes to read disable=no. You must then reload or restart xinetd,, typically by typing /etc/init.d/xinetd reload or /etc/init.d/xinetd restart. (The exact path to the xinetd startup script varies from one system to another, though.) After making this change, the new server should be available. If it isn’t, check your system log file (typically /var/log/messages) for error messages.
IP-Based Controls
One of the most basic types of xinetd access controls restrict connections by IP address. Inxinetd, these controls are implemented by the only_from and no_access directives, which look like this:
only_from = 192.168.78.0 no_access = 192.168.78.24 bad.example.com
These lines should be added to a server’s /etc/xinetd.d/ control file, anywhere between the opening brace ({) and the closing brace (}). In the example above access is granted to all computers in the 192.168.78.0/24 network, except for 192.168.78.24 and bad.example.com. If you use both the only_from and no_access directives, the one with the more specific machine description takes precedence. You can list multiple entries in either directive by separating the entries with spaces.
Computers may be specified in any of several ways:
*Machine IP address. The safest way is usually to specify a machine’s IP address, such as the192.168.78.24 in the preceding example.
*Network IP address. Multiple computers’ IP addresses may be specified in several ways. One is to close the address with one or more “0” entries, as in 192.168.78.0 in the preceding example, for 192.168.78.0/24. You can also specify the netmask explicitly, as in192.168.78.0/24.
*Machine name. You can specify a hostname, as in bad.example.com in the preceding example. When you do so, xinetd looks up the hostname when it starts up or reloads its configuration. Thus, if the hostname changes while xinetd is running, the super server won’t catch this change.
*Network name. You can specify a network by using a name that appears in the /etc/networksfile.
As a general rule, if a server should remain inaccessible to some or most computers on the Internet, using IP-based restrictions is a good starting point. The only_from directive alone is often appropriate. Using no_access alone is handy if you just want to restrict a few systems you know to be troublemakers. Using both directives together lets you grant access to entire networks while restricting access from certain machines. For instance, you might want to block access to a server from a router if that router shouldn’t be using the server, as a precaution in case the router is compromised from the outside.
Of course, if you omit both directives, no restrictions are implemented.
Network Interface Controls
Sometimes you may want to limit access to particular servers based on the network interface. For instance, on a router or firewall, you might want to give access to a server from the internal network but not from the external network. This technique can even be useful on a non-router system: you can give access to a server to the loopback interface, thus ensuring that only clients running on the server computer itself may access the server program. This technique can be handy for tools such as the Samba Web Administration Tool (SWAT), which provides web-based administration for Samba. You can use SWAT from the local machine, but not run the risks of having it compromised because it’s on a network.
Network interface controls are implemented at a lower level than IP-based controls. This makes the network interface controls more fool-proof, as they can’t be tricked by IP address spoofing, for instance.
To implement these controls, use the bind or interface directive, which are synonymous:
bind = 192.168.78.27
This directive binds the server to the interface that uses the 192.168.78.27 IP address. If a request comes in for the server from another interface, xinetd ignores it.
You can use this feature to have xinetd respond differently to different interfaces. Create two or more service definitions, each of which includes a bind directive for a particular interface. You can then tweak access control, logging, and other options for each interface.
For instance, you might set up temporal controls (described next) for a true network interface, but omit those same controls from the loopback interface. If you omit the bind and interfaceoptions, xinetd listens to all available network interfaces.
Temporal Controls
Sometimes a server should only be available at certain times. For instance, you might want to make a login server accessible to local users during business hours, but not late at night when the office should be empty. To accommodate such requirements, xinetd provides theaccess_times option, which takes a range of times on a 24-hour clock, separated by a dash (-):
access_times = 7:00-18:00
This example enables the server from 7:00 AM to 6:00 PM. Note that these times are theinitial access times. Somebody could access the server at 5:58 PM and remain logged in for hours. xinetd won’t terminate an already established connection. If you don’t use anaccess_time option, xinetd imposes no temporal restrictions.
Client Number Controls
When a particular software service becomes too popular, the load on the host computer can become so great as to make the service — and perhaps other services, too — useless to all users. Some servers provide configuration options to limit the number of simultaneous users to avoid such problems, and xinetd provides similar facilities for the servers it manages, whether or not they provide their own connection number controls. In fact, xinetd provides three throttling options: instances, per_source, and cps.
instances = 50 per_source = 20 cps = 5 2
The instances option limits the total number of simultaneous connections xinetd will accept for a server. The default value is UNLIMITED, which imposes no limit. Setting a numeric value causes xinetd to refuse connection attempts if the specified number of connections are already active.
The per_source option is similar to instances, but it applies only to a single client computer. For instance, the preceding combination of instances and per_source limits the total number of connections to 50, of which up to 20 may be from a single IP address.
The cps option limits the rate of incoming connections per second. It takes two arguments: the number of connections it accepts per second and the number of seconds to wait before accepting new connections if the limit is exceeded. In cps=5 2, xinetd accepts up to five incoming connections per second; if more than that number arrive, the super-server refuses new connections for two seconds. This option can be helpful in limiting damage from denial-of-service (DoS) attacks and in controlling bursts of activity (such as a small web site being “Slashdotted”). The default is cps=50 10.
Reasonable values for all of these options depend on the server being managed, the capabilities of the underlying host computer, the speed of the computer’s network connection, and your own tolerances for sluggish operation. You might set low values for big, sluggish servers running on slow hardware, and set higher values for small quick servers running on fast hardware. If you’re unsure what values to set, try monitoring normal activity. If your system’s performance isn’t too sluggish with the highest loads you see, try setting limits above the peak values you see.
CPU Load Controls
Another approach to managing the impact of incoming connections is to have xinetd monitor system load and accept or refuse connections based on activity. The main method of imposing such limits is to use the max_load option, which takes a one-minute CPU load value as a value:
max_load = 3.5
This example tells xinetd to refuse connections if the computer’s one-minute CPU load average exceeds 3.5. (The Linux uptime command displays 1-, 5-, and 15-minute load averages, if you want to check these manually.)
A load average of 1.0 means that programs are requesting CPU time to keep the CPU fully loaded at all times. Values below 1.0 mean that the CPU is sitting idle some of the time, while values above 1.0 indicate that programs are demanding more CPU time than is available, forcing Linux to ration CPU time. Reasonable load averages depend on the computer’s speed and purpose. A very fast computer might perform well with load averages substantially above 1.0, but an old computer might perform poorly even with a load average of 1.0. (Bringing the load average below 1.0 won’t improve the performance of any programs that remain running; this state usually means that programs are spending a lot of time waiting for input. Sluggish performance with lower CPU load averages typically mean there’s a bottleneck somewhere other than the CPU, such as the video card or hard disk.)
Setting the max_load option lets you block incoming connections if your computer is too busy. This limit has the advantage of taking into consideration all of the activity on the computer, even including standalone servers and local programs. Most other xinetd restrictions apply only to a specific server that it manages.
Several other system load options are supported by xinetd. These take the form rlimit_ thing, where thing is the thing being limited. These are rlimit_cpu, rlimit_data, rlimit_stack, rlimit_rss, andrlimit_as, which impose limits on CPU time, data size, stack size, resident set size (RSS), and address space (AS) size, respectively.
The rlimit_cpu option limits the amount of CPU time, in seconds, that a server launched byxinetd may consume. The remaining options are all measures of memory use, of whichrlimit_as is the most useful on Linux. These memory options all take a number of bytes as a value, although you can append a K or M to specify the memory use in kilobytes or megabytes, respectively. Once a server exceeds the specified limit, xinetd terminates it. These options are particularly handy if a server might be abused in such a way that it’s likely to consume inordinate system resources, or if it’s got a known bug that can cause its resource consumption to spiral out of control.
Putting It All Together
Wrapping up, consider Listing One, which shows a modified CUPS LPD server entry that implements several of the options just described.
{
socket_type = stream
protocol = tcp
wait = no
user = lp
server = /usr/lib/cups/daemon/cups-lpd
disable = no
bind = 192.168.78.27
only_from = 192.168.78.0
no_access = 192.168.78.24 bad.example.com
access_times = 7:00-18:00
instances = 50
per_source = 20
max_load = 3.5
rlimit_cpu = 20
}
The order of options within the braces of a service definition is unimportant. Listing One ’s configuration is much like the default configuration, but it adds many options: it binds the server to a single network interface, accepts connections from just one set of IP addresses (with a couple of systems excluded), accepts connections only from 7:00 AM to 6:00 PM, enables just 50 instances to be active (20 from any one IP address), refuses connections if the CPU load is above 3.5, and limits the server to consume 20 seconds of CPU time.
A configuration such as the one in Listing One can improve overall security by limiting who can connect to the server, when a client may connect, and what sort of resources requests can consume.
Although xinetd options aren’t a substitute for other security measures (such as iptablesfirewall rules and good password practices), they can be part of a complete security plan for your system, and are therefore well worth investigating further.
#man xinetd.conf
http://www.linux-mag.com/id/2402/