Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Absolute BSD - The Ultimate Guide To FreeBSD (2002).pdf
Скачиваний:
25
Добавлен:
17.08.2013
Размер:
8.15 Mб
Скачать

have specifically listed. This is a perfectly acceptable default deny stance.

We'll refer to default deny and default accept throughout the following sections.

TCP Wrappers

Remember from Chapter 5 that network connections are made to various programs that listen for connection requests. TCP Wrappers intercepts these requests before they reach the daemon, checks the IP address that is making the request against a configuration file, and decides accordingly whether to accept, reject, or alter the request. Despite the TCP Wrappers name, it works with UDP network connections as well as TCP connections. TCP Wrappers is a long−time UNIX standard that has been incorporated into FreeBSD. Individual programs might or might not work with TCP Wrappers, though; just about everything in the base FreeBSD install does, but some third−party software won't.

Wrappers are most often used to protect inetd, the program that starts the smaller daemons. (We will discuss inetd in Chapter 12.) To start inetd with wrappers support, use the −Ww flag with inetd_flags="−Ww" in /etc/rc.conf, for example (see Chapter 9). The examples here will not work unless inetd is started correctly. While our examples will discuss protecting inetd programs with TCP Wrappers, you can protect any program in exactly the same way.

Configuring Wrappers

TCP Wrappers checks each incoming connection request against the rules in /etc/hosts.allow, in order. The first matching rule is applied, and processing stops immediately. This makes rule order very important.

Each rule is on a separate line, and is made up of three parts separated by colons: a daemon name, a client list, and a list of options. Here's a simple sample line:

...............................................................................................

ftpd : all : deny

...............................................................................................

The daemon name in this example is "ftpd", and the client list is "all", meaning all hosts. Finally, the option is "deny", meaning "deny all connections." Nobody can connect to the FTP server on this host, unless an earlier rule explicitly grants access.

In our early examples, we will refer to only two options: accept and deny. They allow and reject connections, respectively. There are many more options, but we'll discuss them later.

Daemon Name

The daemon name is the program's name as it appears on the command line. For example, inetd starts the ftpd program when it receives an incoming FTP request. The Apache Web server starts a program called httpd, so if your version of Apache supports wrappers, you would want to use "httpd" in /etc/hosts.allow. One special daemon name, ALL, matches all daemons that support wrappers.

158

If you have multiple IP addresses on one network card, you can specify different wrapper rules for each IP address that a daemon listens on as part of the daemon name, something like this:

...............................................................................................

ftpd@192.168.8.7 : ALL : deny

ftpd@192.168.8.8 : ALL : accept

...............................................................................................

In this example, we have two daemon names: ftpd@192.168.8.7 and ftpd@192.168.8.8. Each has a separate TCP Wrappers rule.

The Client List

The client list is a list of specific IP addresses, network address blocks, host−names, domain names, and keywords, separated by spaces. Hostnames and IP addresses are simple; just list them:

...............................................................................................

ALL: netmanager.AbsoluteBSD.com 192.168.4.3 : allow

...............................................................................................

Specify network numbers in the client list with a slash between the IP address and the netmask, as discussed in Chapter 5. For example, if some script kiddies are attacking you from a bunch of different addresses that all begin with 216.136.204, you could block them like this:

...............................................................................................

ALL: 216.136.204.0/255.255.255.0 : deny

...............................................................................................

You can also use domain names in client patterns, by prefacing them with a dot:

...............................................................................................

ALL : .mycompany.com : allow

...............................................................................................

You can reverse any of these, of course, to deny connections from just a single location:

...............................................................................................

telnetd : .competitor.com : deny

...............................................................................................

If you have a long list of clients, you can even list them in a file and put the full path to the file in the client space in /etc/hosts.allow. I've been on networks with large numbers of widely scattered hosts, such as an ISP or corporate network environment with network management workstations scattered across the world. Each workstation shared the same TCP Wrappers rule as every other workstation, and appeared on half a dozen lines in /etc/hosts.allow. By maintaining a single file with a list of these workstations, I could centralize all changes; edit one file, and all the rules that call the file are updated.

Client Keywords

In addition to specifically listing client addresses and names, you can also use several special client keywords to add groups of clients to your list:

159

ALL This keyword matches every possible host.

LOCAL This matches every machine whose hostname does not include a dot. Generally, this means machines in the local domain.

UNKNOWN This keyword matches machines with unidentifiable hostnames, IP addresses, or usernames. As a general rule of thumb, if a machine is making an IP connection, its IP address is known. Tracing hostnames requires DNS, however, and tracking usernames requires the identd protocol. Be very careful using this option, because transitory DNS problems can make even local host−names unresolvable, and most hosts don't run identd by default. You don't want a machine to become unreachable just because your nameserver was misconfigured—especially if that machine is your nameserver!

KNOWN This keyword matches any host with a determinable hostname and IP address. Again, if your DNS fails, every host on the Internet will suddenly appear to have lost its hostname. If you say that all identifiable hosts can connect and your server's DNS fails, nobody will be allowed to connect.

PARANOID This matches any host whose name does not match its IP address. You might get a connection from a host with an IP address of 192.168.84.3 that claims to be called mail.AbsoluteBSD.com. TCP Wrappers will then turn around and check the IP address of mail.AbsoluteBSD.com. If TCP Wrappers gets a different IP address than the source IP, the host will match this rule.

Most of the client keywords listed here require a working DNS server (see Chapter 12). If you use these keywords, you must be aware of the vital link between DNS and the rest of your programs. If your DNS server fails, daemons that use wrappers and these keywords won't be able to recognize any hosts. This means that everything will match your UNKNOWN rules. Also, broken DNS on the client end can deny remote users access to your servers, as your DNS servers won't be able to get the proper information from the client's DNS servers.

Other keywords are available, but they are not as useful or secure. For example, it's possible to allow connections based on the username on the remote machine making the request. You don't really want to permit a request based on the user−name at the client end, though. Any yahoo can slap together a FreeBSD or Linux box and give himself whatever username he desires. If I set up TCP Wrappers to only allow someone with a username of "mwlucas" to connect to my home system, someone who wanted in could easily add an account of that name to his FreeBSD system. Also, this relies on the same identd protocol that we mentioned earlier, and very few hosts run identd. You will find a few other obscure keywords of similar usefulness in the man page hosts_access(5).

The ALL and ALL EXCEPT Keywords

The ALL and ALL EXCEPT keywords can be used both for daemon names and for client lists.

The ALL keyword matches absolutely everything. For example, the default /etc/hosts.allow starts with a rule that permits all connections, from all locations, to any daemon:

...............................................................................................

ALL : ALL: accept

...............................................................................................

160

This matches all programs, from all clients. You can limit this by giving a specific name to either the client list or the daemon list:

...............................................................................................

ALL : 192.168.1.87 : deny

...............................................................................................

In this example, we are rejecting all connections from the host 192.168.1.87.

Categorically blocking access to all hosts isn't that great an idea, but remember that TCP Wrappers follows rules in order and quits when it reaches the first matching rule. The ALL keyword lets you set a default deny or default accept stance quite easily. Let's consider the following ruleset:

...............................................................................................

ALL : 192.168.8.3 192.168.8.4 : accept

ftpd : ALL : accept

ALL : ALL : deny

...............................................................................................

Here, we're allowing the workstations 192.168.8.3 and 192.168.8.4 to access anything they want. These are the sysadmin's desktop machines. Then we allow anyone to connect to the FTP service on this machine. Finally, we drop all other connections. This is a useful default deny stance.

Use the ALL EXCEPT keyword to compress the preceding ruleset even further. ALL EXCEPT lets you list hosts by exclusion; what isn't listed matches. Let's consider the same rules written using ALL EXCEPT:

...............................................................................................

ALL

: 192.168.8.3 192.168.8.4 : accept

ALL

EXCEPT ftpd : ALL : deny

...............................................................................................

Some people will find the rules more clear when written with ALL, others with ALL EXCEPT. The important thing to remember is that the first matching rule ends the check, so you need to be careful slinging ALL around. Generally speaking, the first rule that has any combination of ALL and ALL EXCEPT in both the daemon and client lists will stop the check; every connection will match it.

Allow Options

The allow option tells TCP Wrappers to accept the connection. The default hosts.allow file starts with this rule:

...............................................................................................

ALL : ALL : allow

...............................................................................................

This rule applies to all daemons and all clients, and it matches and allows all possible connections. While this rule can't be the first on the list if you want to protect your services, it's a good final rule if all you're doing is protecting particular server programs against particular network addresses.

161

If you're experimenting with TCP wrappers, it's a good idea to allow any connections from the local host, or you're liable to discover a number of programs that break when they can't talk to the local machine. Do so as follows:

...............................................................................................

ALL : localhost : allow

...............................................................................................

Options for Responses

Now that you have a good grasp of the daemon and client lists, let's take a look at some of the more interesting options for responses. The concept of these options is very simple: You have an incoming connection that matches a rule, so now what do you do with it? Responses can be very simple, or very complicated and subtle.

Note If you're using a lot of options, TCP Wrappers rules can get very long. Fortunately, the hosts.allow file uses the backslash (\) followed by a return as a line−continuation character, which helps keep the rules readable.

The most basic options are accept and deny. If a connection attempt matches the rule, the request is either passed on to the waiting daemon or rejected. You can use additional options, however, separated by colons.

Severity

Once you have decided to accept or reject the connection attempt, you can also log connection attempts. Suppose you want to block all incoming requests from a competitor; it might be nice to know if they were actually trying to connect. Logs will tell you that.[1] Similarly, you might want to know how many rejected connection attempts you're getting from people with DNS problems (especially if you're using the PARANOID client keyword).

The severity option sends a message to the system log, syslogd(8). You can configure syslogd to direct these messages to an arbitrary file (see Chapter 19), based on the syslogd facility and level you choose:

...............................................................................................

telnetd: ALL: severity auth.info : allow

...............................................................................................

This example will log all telnet connections.

Twist

The twist option allows you to run arbitrary shell commands and scripts when someone attempts to connect to a wrapped TCP daemon, and returns the output to the user. Twist only works with TCP connections.[2] Twist takes a shell command as an argument and acts as a deny−plus−do−this rule. You must know some basic shell scripting to use twist; very complicated twists are entirely possible,

162

but we'll stick with the simple ones. We're not demonstrating shell scripts, after all! If you're in doubt, you can always just use /bin/echo "reason" to let the remote client know why its connection has been rejected. (Note the straight double quotes around the reason, they're important!)

Twist is useful for a final rule, if you're using default deny. (If you have a restrictive security stance, end your security policy with such a catch−all deny rule.) You can use twist to return an answer to the person attempting to connect as follows:

...............................................................................................

ALL : ALL : twist /bin/echo "You cannot use this service."

...............................................................................................

Or if you want to just deny a particular service to a particular host, you can use a more specific daemon and client listings with twist. The following example is a little too long to fit on one line, so I've split it using the backslash character:

...............................................................................................

sendmail : .spammer.com : twist /bin/echo \

"You cannot use this service"

...............................................................................................

If you're feeling friendly, you can tell people why you're rejecting their connection attempt. The following twist rejects all connections from people whose host−names do not match their IP addresses, and tells them why:

...............................................................................................

ALL : PARANOID : twist /bin/echo \

"Your DNS is broken. When you fix it, come back."

...............................................................................................

Twist will hold the network connection open until the shell command finishes. If your command takes a long time to finish, you could find that you're holding open more connections than you planned. This can reduce system performance dramatically. Twists should be simple and finish rapidly.

Note It's tempting to put a rude message in twist output, especially when you think that nobody could have a legitimate reason for trying to access a server. But spitting back "Bite me, script kiddie!" will annoy legitimate users, and it just might peeve script kiddies enough that they try harder to get in.

Spawn

Like twist, the spawn option denies the connection and runs a specified shell command. Unlike twist, spawn does not return the results to the client. Use spawn when you want your FreeBSD system to take an action upon a connection request, but you don't want the client to know about it. Spawned commands run in the background, and their results are not returned to the client. The following example will allow the connection, but will log the client's IP address to a file:

...............................................................................................

ALL : PARANOID : spawn (/bin/echo %a >> /var/log/misconfigured) \

: allow

...............................................................................................

163

If you're familiar with shell scripts, you are probably scratching your head at that %a symbol in the preceding command. TCP Wrappers supports a variety of variables for use in twist and spawn commands, which are expanded before the command is run, so that you can easily customize your responses to connection requests. This particular variable, %a, stands for client address. It expands into the client's IP address in the actual shell command before the command is run. Other variables are shown in Table 8−1.

Table 8−1: Variables that can be used in twist and spawn commands

Variable Description

%a Client address

%A Server IP address

%c All available client information

%d Daemon name

%h Client hostname (if available), or IP address

%H Server hostname (if available), or IP address

%n Client hostname; if no hostname is found, this gives UNKNOWN. If the hostname's name and IP address don't match, this equals PARANOID

%N Server hostname; if no hostname is found, returns either UNKNOWN or PARANOID

You can use these variables anywhere you would use the information they represent in a shell script. For example, to log all available client information to a file whenever anyone connects to a wrapped program, you could use this spawn:

...............................................................................................

ALL : PARANOID : spawn (/bin/echo %c >>/var/log/clients) \

: allow

...............................................................................................

You may have noticed that this script is the same as the earlier example, with the minor changes of the variable used and the log filename. You can do the same sort of thing with any information you want to log.

Spaces and backslashes in hostnames can give the command shell problems because they're illegal characters. While neither should appear under normal circumstances, someone might try to, say, use a hostname with a space in it just to confuse security software. To be on the safe side, TCP Wrappers replaces any character that might confuse the command shell with an underscore (_). Check for this sort of thing in your logs; they might indicate possible intrusion attempts, or just someone who likes underscores in hostnames.

164