As we explained, TCP wrappers is a good choice for a single-homed/stand-alone server on a secure network where you want to limit host/network access to just a couple of services. Many application server administrators use the TCP wrappers /etc/hosts.allow and /etc/hosts.deny files to control daemon access from one easy-to-view area, then use iptables for more advanced state-based, filter, and packet-level service control (of course, you can use iptables for all of this if you prefer.)
Tip |
If you control client access with TCP wrappers, keep as much of your client control data in the /etc/hosts.allow and /etc/hosts.deny files as you can, rather than spreading it across both TCP wrappers and iptables. This will help prevent you from defining conflicting rules across the two mechanisms and potentially save your hours of chasing down ghosts when troubleshooting service-related issues. |
Table 11-2 shows common services and daemons, with notes that are critical when configuring your services in /etc/hosts.allow and /etc/hosts.deny. The first column shows the service name, while the daemon name is the actual binary daemon name that you use in the /etc/hosts.allow and /etc/hosts.deny file. Many of these services are controlled by the xinetd master daemon. You can see which services are xinetd-based with this command:
# chkconfig --list| grep -v 0: xinetd based services: chargen-udp: off rsync: off chargen: off ...
The xinetd daemon itself can be viewed with the following command:
# chkconfig --list xinetd xinetd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
Note |
Table 11-2 is really only accurate for newer Red Hat- and Fedora Core-based systems. Older systems or non-Red Hat-based distributions will need to compile their own list of such services. See the "Compiling a Daemon List for non-Red Hat Distributions" sidebar for instructions on how to do this. |
The services in Table 11-2 are common services that most administrators offer on their Internet or intranet servers. Services not compiled with libwrap support need to have network access controlled from either their own configuration files, as with Apache's /etc/httpd/conf/httpd.conf, or through iptables. The latter option is the most secure.
Note |
The terms libwrap and TCP wrappers are often used synonymously. The first is the library, and the second is the name of the package. Likewise, you may hear the terms /etc/hosts.allow or /etc/hosts.deny used interchangeably with the term host_access. Here the first two are the files used, and the latter is what these files are functionally referred to as in the man page for the files. |
Note that NFS atop portmap is a special case. NFS is actually not a single daemon, but several daemons tied together to the network daemon called portmap that offers the Remote Procedure Call or SunRPC service. In this way, NFS can be controlled through /etc/hosts.deny by blocking access to the portmap daemon, which in turn identifies and allows NFS services to run. However, remember that TCP wrappers still allows clients to hit the userspace service (libwrap and a daemon), so it is inherently less secure. If you want a truly hardened and secure NFS implementation on the Internet, use iptables and not TCP wrappers.
Remember that the first step to securing a server, whether you use TCP wrappers or iptables, is to shut down all the services you don't need. Cutting down the number of running services decreases your network security profile, that is, how big of a target your server appears to be. See Chapter 4 for more information.
The behavior of TCP wrappers host_access controls is controlled by the values stored in /etc/hosts.allow and /etc/hosts.deny. In this section, we show you the default versions of these files and offer some tips on configuring them appropriately.
The default /etc/hosts.allow file is quite basic:
# cat /etc/hosts.allow # # hosts.allow This file describes the names of the hosts # which are allowed to use the local INET # services, as decided by the '/usr/sbin/tcpd' # server. #
Same is the default /etc/hosts.deny file:
# cat /etc/hosts.deny # # hosts.deny This file describes the names of the hosts # which are *not* allowed to use the local INET # services, as decided by the '/usr/sbin/tcpd' # server. # # The portmap line is redundant, but it is left to remind you # that the new secure portmap uses hosts.deny and hosts.allow. # In particular you should know that NFS uses portmap!
The basic idea behind TCP wrappers is that the hosts.allow file contains hosts that are allowed to access services on your machine, while hosts.deny contains hosts that are denied entry. Specifically, any service request that does not match a service:host pairing value contained in either file, or which is not denied by a wildcard in the deny file (or is not compiled against libwrap at all), is allowed by default. If a librwrap service:host match is made in the hosts.allow file, then the service is let in. If a librwrap service:host match is made in the hosts.deny file, then the service is not allowed.
Let's see how this is used in the real world. Assume that you want to set up and control resources on a multiservice server in your department. You want to run an extranet web server (internal resources such as webmail on the Internet to only select clients) to only remote office clients in the IP space 172.16.1.*, and also want to have some limited internal e-mail SMTP/POP and SSH/sFTP access on the server. The users of this system need to get their e-mail via POP3 from an internal LAN with IP addresses in the 10.*.*.* range, as well as from dial-up and wireless networks in the 192.168.1.* range. However, only administrators should be able to SSH into the server from the internal administrative LAN (10.1.1.*). You can set these parameters with TCP wrappers. Unfortunately, Apache access is controllable only through iptables or its own daemon config file; we'll deal with this and SMTP later with iptables. Let's just do the SSH/sFTP and POP3 part with TCP wrappers. See the following table:
Service |
Allowed Network(s) |
How to control access |
---|---|---|
SSH/sFTP |
10.1.1* |
TCP wrappers or iptables |
SMTP |
10*.*.*/192.168.1* |
TCP wrappers or iptables |
POP3 |
10*.*.*/192.168.1* |
TCP wrappers or iptables |
HTTP |
172.16.1* |
Only iptables (or httpd.conf) |
We'll show how SSH and POP3 are done with wrappers/hosts_access and do the rest with iptables.
Note |
Under Fedora Core, sendmail/SMTP is fully SMTP-Auth enabled, meaning that to relay mail through your server users provide both username and password before sending mail. However, the default SMPT-Auth does not encrypt the password information or the mail itself. To have encrypted mail sessions, you need to enable additional measures such as TLS(SSL) and POP3S or IMAPS. For more information on enabling SMTP-Auth w/TLS, see www.falkotimme.com/howtos/sendmail_smtp_auth_tls/index.php. |
The line formatting of the /etc/hosts.allow and /etc/hosts.deny files are the same. The only difference is in how they impact daemon client-host requests. Entries in both files are written in three comma-delimited columns, as in
daemon_list : hosts_list [ : spawn ( shell-command) ]
The daemon's name goes in the first column, then the hosts allowed or denied access (designated by host name, IP address(es), or network(s)), and finally an optional shell script or program that runs when a request triggers a daemon:host match.
To serve the needs of the server in our example, you might construct an /etc/hosts.allow file that looks like this:
... # TWW: Added 2004-01-30 (always date and comment) # httpd flows through or is controlled by iptables # sshd only from 10.1.1.x network, and pop3s from all of 10. + admin LAN sshd: 10.1.1. #ssh allowed from local admin LAN ipop3d, sendmail: 192.168.1. , 10. , .example.com #pop3s allowed from here... ...
Notice that the daemon name for the service is listed, not just ssh or pop3. This is key if you expect it to work.
Caution |
All requests that match the daemon and host pairings in the allow file will be allowed into the server. If there is no match in this file, then the request is matched against the /etc/hosts.deny file. If there is no match in this file also, then the service is allowed by default. This illustrates why you need to remember to populate that /etc/hosts.deny file with some type of catch-deny entry, otherwise the entries above are ineffectual. |
This configuration allows our admin SSH sessions from the 10.1.1.* network, and allows SMTP and POP traffic from the 192.168.1.* network, the entire 10.*.*.* network, and any IPs that resolve back to the domain *.example.com. TCP wrappers can use domain names here as it offers an autoreverse-lookup feature that should resolve any IP address that has a reverse IP to name DNS record.
Note |
The daemon_list and client_list are columns separated by colons, and the lists of daemons or hosts within each column are separated by commas. If you want to allow sshd and ipop3d connections from both the 10.*.*.* and 192.168.1.* networks, simply add the following line: sshd, ipop3d : 192.168.1. , 10. |
Once you've configured /etc/hosts.allow for the connections you want to allow, it's time to block the requests you don't want. If you leave /etc/hosts.deny with no entries, all requests not explicitly matched in /etc/hosts.allow will flow through the deny file and be allowed to connect. This makes the whole point moot, so be sure to configure /etc/hosts.deny. You can do this simply, as in this example:
Note that the ALL daemon listing only matches daemons compiled against libwrap and TCP wrappers. Apache/httpd does not check the allow and deny files, so it must be blocked at the outer iptables layer or in the daemon's own configuration file. The ALL:ALL entry in /etc/hosts.deny will block all service requests not explicitly permitted in /etc/hosts.allow, but will not control requests from blacklisted hosts for non-TCP wrappers compatible daemons.
Caution |
Whenever making dangerous entries in /etc/hosts.deny, such as sshd:ALL or ALL:ALL, you must verify that the entries in /etc/hosts.allow are valid. If you make a mistake in /etc/hosts.allow, you could lock down all access to the server! A typo as simple as ssh:... instead of sshd:..., combined with an ALL:ALL entry in the deny file, would bar all logins no matter from whom. |
TCP wrappers is fairly straightforward. Even so, there are some things that might trip you up if you don't pay careful attention while you're working with the hosts_access files. Here are a few tips to keep you on the right path:
When troubleshooting TCP wrappers problems, either flush or turn off iptables-based firewalling entirely. Wrappers and iptables are layers of security, and you can make yourself crazy trying to fix the problem in one layer when it's actually happening in the other service. The /etc/init.d/iptables stop command is your friend.
In the same vein, if you're troubleshooting iptables, check /etc/hosts.deny to be sure that you don't have an unexpected ALL:ALL or a block that's triggering your iptables problem.
Always keep a spare shell or terminal window open while working on your allow and deny files remotely! Changes in TCP wrappers affect only new client connections. If you manage to lock yourself out, you can use the open shell to get back into the file and fix the error. Just don't reboot until you're really sure it's fixed!
If you choose not to use ALL:ALL entries in your deny file, you can use line-item entries with EXCEPTions like this one:
ipop3d, sendmail: ALL EXCEPT 192.168.1.
Just be sure to first verify your denies by inverting the logic, as in
ipop3d, sendmail: ALL EXCEPT !192.168.1.
This flips the deny, letting the request work from every location except the one you specify. With this, you can verify that there are no typos in the daemon name or client listing and that the wrapper is working as expected. When you're satisfied, remove the ! (UNIX negation symbol) and save the file.
Even though they're helpful in line-item entries, you can't use ! and EXCEPT with ALL. The ALL daemon setting is a special case that overrides all other deny rules, and can only be overridden itself by a positive daemon:client match in the allow file.
Some administrators like to add one or two white-list IP addresses to their deny files so that there is always a back door into the system even if they make errors elsewhere in /etc/hosts. Do this with a single entry in /etc/hosts.deny that looks like this:
Even if you don't get a daemon name or IP address right in the allow file, you will always be able to get in from the EXCEPT IP. Just remember that the deny file adopts the most secure entry method. If you use this trick, you'll need to configure all allows in /etc/hosts.allow and let all denials flow through to the deny file.