Chapter 6. Controlling Spam

Introduction

Spam mail: you know it when you see it, and everyone has seen the ridiculous advertisements for investment schemes, pornography, herbal cures, and everything else imaginable. Many experts categorize all Unsolicited Commercial Email (UCE) as spam, and certainly UCE clutters electronic mailboxes around the world. However, legitimate advertisers who offer real “opt-out” schemes are not the worst problem.[1] The real problems come from spammers. What distinguishes spammers from legitimate advertisers is that spammers hide their identity and abuse other people’s systems. These traits can be seen by the fact that:

  • Spammers hide the origin of the email so that no one knows they sent it. Legitimate advertisers proudly display their company name in the sender address. Any advertiser who doesn’t probably has a reason to hide who they are and what they are doing and should be considered a spammer.

  • Spammers abuse the services of other people’s systems by using those systems as unauthorized relays.

  • Spammers send information you never asked to receive. You don’t join a spammers’ mailing list, and when spammers provide an opt-out scheme, it does not opt the user out of anything. Instead, the scheme is used to collect email addresses to sell to other spammers.

You must do your part to reduce spam for everyone by ensuring that your system is not misused by remote spammers and that your local users do not contribute to spam.

Spammers use open mail relays to hide their identity. See the recipes in Chapter 3 for examples of how to configure a mail relay host. Test your relay as shown in Chapter 3 every time the configuration is changed to ensure that it can’t be abused.

The first step in addressing local spammers is to create an acceptable use policy (AUP) that forbids spamming and defines the actions you will take to stop it. Make sure that the policy clearly states that email is not private and is subject to logging, scanning, and filtering. Because this is a policy, it must be approved and issued by management, and it must be reviewed and approved by the legal department. Policies are always a hassle because they are not technical solutions and because they involve management. However, it is a necessary step to give you the authority you need to analyze mail. Once the policy is in place, all users must agree to it as a condition of obtaining a user account.

In addition to ensuring that your system doesn’t contribute to the spam problem, there are technical tools that you can use to actively fight spam. sendmail provides a number of tools to combat incoming junk mail:

  • The access database blocks mail from and to specified systems.

  • DNS blackhole lists block mail from suspected spammers and from open mail relays.

  • Mail filtering programs, such as procmail, are accessible from sendmail and are capable of filtering mail based on the content of the mail.

  • sendmail’s header processing can detect malformed or inconsistent headers.

  • sendmail automatically performs sanity checks, such as checking that the sender’s domain can be resolved by DNS.

The access database

The access database provides fine-grained control over mail relaying and mail delivery. Use the access_db feature to add the access database to the sendmail configuration:

FEATURE(`access_db')

By default, the access database is a hash database, and its default pathname is /etc/mail/access.db. Use the optional argument field with the access_db feature to change the default values, as in this example:

FEATURE(`access_db', `btree -T<TMPF> /var/mail/access')

This example changes the database type, specifies the -T<TMPF> option to deal with temporary lookup failures, and changes the database pathname. Only change the defaults when it is truly necessary.

Each line in the access database contains two fields: the key field and the return value. When the access database is used to control junk mail, the key to the database is an address, and the return value specifies the action that sendmail should take with regard to mail to or from the specified address. When the access database was used in Chapter 3, the return value was, logically enough, the keyword RELAY. To control spam, the recipes in this chapter use the access database to determine whether mail should be accepted from or delivered to specified addresses. For that, we need a different set of return values. The keywords that apply to controlling junk mail are listed in Table 6-1.

Table 6-1. access database keywords used for spam control

Keyword

Action

OK

Accepts messages from or to the specified address.

DISCARD

Drops any message from or to the specified address.

REJECT

Issues an error message and drops any mail from or to the specified address.

ERROR:dsn:code text

Rejects the mail with the specified response code and error message.

HATER

Adds the check_mail and check_relay rulesets for mail to the specified recipient.

FRIEND

Skips the check_mail and check_relay rulesets for mail to the specified recipient.

The OK command tells sendmail to accept mail from the source identified by the address in the key field regardless of other conditions. For example, if the hostname specified in the address field cannot be resolved by DNS, sendmail accepts mail from that host even if the accept_unresolvable_domains feature is not enabled. OK accepts mail for local delivery; OK does not grant relaying privileges. The RELAY keyword, described in Chapter 3, is required for that.

The REJECT keyword returns a standard error message to the source and rejects the mail. The DISCARD action drops the mail without sending an error message back to the source. Many anti-spam authorities disagree with silently discarding mail because they feel it does not discourage the spammer. For all the spammer knows, you received the mail, so he just keeps sending more junk. Other anti-spam authorities prefer to silently discard mail because they believe that responding to the mail in any form verifies the address for the spammer, which encourages the spammer to continue his assault. Both approaches protect your users from the spammer. However, using REJECT, which returns an error message to the source of the mail, helps when legitimate mail is accidentally classified as spam because it notifies the source of the mail that their mail was rejected.

The REJECT action sends a default error message. Use the ERROR keyword to reject a message with your own custom error message. For example:

example.com         ERROR:5.7.1:550 Relaying denied to spammers

In this case, the error message returned to the sender is “Relaying denied to spammers.” This error message includes delivery status notification code 5.7.1 and the SMTP error code 550. Use a valid DSN code from RFC 1893 that is compatible with the RFC 821 error code and the message.[2] The format for the error message shown in Table 6-1 is ERROR:dsn:code text. This format is recommended, but not required. It could be specified without the keyword ERROR or the DSN code. However, that old error format has been deprecated. Use the ERROR keyword and the DSN code to ensure compatibility with future sendmail releases.

The FRIEND and HATER keywords only apply if the delay_checks feature is used to control when the check_mail and check_relay rulesets are applied. The FRIEND keyword in the return value allows mail that would normally be discarded by check_mail and check_relay to pass through the system to the recipient specified in the key field. When HATER is used, check_mail and check_relay are only applied to mail addressed to recipients who have the HATER keyword in their access database entries. FRIEND and HATER cannot appear in the same access database because the delay_checks feature must be configured to accept either FRIEND or HATER—it cannot be configured to accept both at the same time. Recipe 6.13 provides an example of how these keywords are used.

Most of the actions in Table 6-1 are described as affecting mail “from or to” an address. This is only true when tags are used or the blacklist_recipients feature is used. When that feature is not used, the actions only affect mail coming from a source address, unless the address field is modified by an optional To:, From:, or Connect: tag. These tags limit the address test to the envelope recipient, envelope sender, and connection address, respectively.[3] For example, an access database entry to reject connections from 10.0.187.215 might contain:

Connect:10.0.187.215      ERROR:5.7.1:550 UCE not accepted

The Connect: tag limits the match to the address of the remote system that connected to the server to deliver the mail. If that address is 10.0.187.215, the mail is rejected and the message “UCE not accepted” is returned to the sender.

The address in the key field of an access database entry can define a user, an individual email address, a source IP address, a network address, or the name of a domain:

  • An individual is defined using either a full email address in the form user @ host.domain or a username in the form username @.

  • A host is identified by its hostname or its IP address.

  • A domain is identified by a domain name.

  • A network is identified by the network portion of an IP address.

In addition to the Connect: example shown in the access database, other address formats can be used to identify mail from 10.0.187.215. Here are a few:

10.0.187                 REJECT
[10.0.187.215]           DISCARD
example.com              ERROR:5.7.1:550 Mail not accepted.

The first two lines in this access database match IP addresses. The first entry rejects mail from any computer whose IP address begins with the network number 10.0.187, which is the network from which the UCE was received. The second line defines a specific computer with the address 10.0.187.215. The square brackets surrounding the individual address indicate that this IP address doesn’t resolve to a hostname.

The last entry defines an entire domain. It rejects mail from any host in the domain example.com. Of course, you wouldn’t do this if you got only one piece of UCE from that domain, but if you consistently received junk mail from the domain, you may decide to block all mail from that domain until they improved their security. The dnsbl feature provides another method for blocking mail from specific hosts and domains.

Blackhole lists with dnsbl and enhdnsbl

Add the dnsbl feature to the sendmail configuration to use a blackhole list to block spam. A blackhole list is a DNS database that identifies spam contributors. The contributors can be the original source of the spam or open mail relays that permit spammers to relay mail. Blackhole list services are implemented through DNS. Every Unix system can issue DNS queries, so this is a very effective way to distribute information. Of course, a program can only make use of the information if it understands it, which sendmail does.

The dnsbl feature accepts two optional arguments. The first argument is the name of the domain that contains the blackhole list. This defaults to the Realtime Blackhole List (RBL) that is maintained by the Mail Abuse Prevention System (MAPS). There are several other groups that maintain lists and make them available to the public. Table 6-2 lists a few of these.

Table 6-2. Blackhole list services

Service name

Web site

Domain name

Spamhaus Block List

www.spamhaus.org

sbl.spamhaus.org

Relay Stop List

relays.visi.com

relays.visi.com

Distributed Server Boycott List

dsbl.org

list.dsbl.org

MAPS RBL

mail-abuse.org

None required. This is the dnsbl default.

To use a blackhole list specified in Table 6-2, point the first argument of the dnsbl feature to the domain listed in the table. For example, the following command would configure sendmail to use the Spamhaus Block List:

FEATURE(`dnsbl', `sbl.spamhaus.org')

The policies enforced by the different blackhole list services vary. Most of these services focus on blocking open relays instead of focusing on spam sources. The reason for this focus is that spam sources are constantly changing and hiding their true identities. They are aided in this, albeit unwittingly, by open relays. The open relay doesn’t really want to help the spammer. Blocking the open relay’s mail quickly gets the attention of the administrator of that relay, who fixes the system, and thus denies the spammer access to resources. This indirect defense against spam impacts many innocent, if naive, network users. For this reason, many consider blackhole lists to be a cure that is as bad as the disease, and they discourage the use of blackhole lists.

There are many systems listed in the public blackhole lists. Any site that relays spam—which could be your site if you don’t properly configure sendmail—is likely to be blackhole listed. This is one of the reasons that it is essential to configure relaying properly. A mistake in configuring relaying could get your site added to the blackhole list. If a site stops relaying spam, it should be removed from the list after about a month. Of course, this policy varies from list to list, as does the efficiency by which sites are added to and removed from the lists. If your site gets added to a blackhole list, fix the problem and apply to have your site removed from the list by following the instructions on the list’s web site. Visit the web site of each listing service to find out more about the list before you start using it.

The simplest way to block spam is to let someone else do it. However, while using a public blackhole list is simple, it isn’t perfect. You can’t choose which sites are added to the list, which means the list might block email from a friendly site just because the administrator at that site forgot to turn off relaying. You can, however, override entries in a blackhole list using the access database, as described in Recipe 6.4. For even more control, some organizations decide to build their own DNS-based blackhole list. Recipe 6.5 shows how you build and invoke your own blackhole list.

The second argument available for the dnsbl feature is the error message displayed when mail is rejected because of the blackhole server. The format of the default message is:

550 Rejected $&{client_addr} listed at dnsbl-domain

where $&{client_addr} is the IP address that was rejected, and dnsbl-domain is the DNS blackhole list that rejected the address (i.e., dnsbl-domain is the value from the first argument provided to the dnsbl feature). Use the second dnsbl argument only if you wish to change the standard error message. Most administrators stick with the default message.

The third argument available for the dnsbl feature allows you to specify how temporary DNS lookup failures should be handled. By default, sendmail does not defer the message just because the blackhole list service is not able to respond to a DNS lookup. Placing a t in the third argument field causes sendmail to return a temporary error message and defer the message. Here is an example:

FEATURE(`dnsbl', `sbl.spamhaus.org', ,`t')

An alternative to the dnsbl feature is the enhdnsbl feature. The syntax of the enhdnsbl feature has the same three initial arguments as the dnsbl feature, but it adds a fourth argument. The fourth argument is the return value that sendmail expects from the DNS lookup. By default, any DNS lookup value returned by a blackhole list service indicates that the address being looked up is listed by the service and should therefore be rejected. The fourth argument allows you to change this so that only a value matching the fourth argument will trigger a rejection. The fourth argument does not need to be a single value: it can be a list of values or it can use the same operators as the lefthand side of a rewrite rule to match multiple values. Here is an example of the enhdnsbl feature:

FEATURE(`enhdnsbl', `sbl.spamhaus.org', , ,`127.0.0.2', `127.0.0.3.')

This macro entry enables the enhdnsbl feature and uses the sbl.spamhaus.org blackhole list service. It tells sendmail to reject the incoming message if the blackhole list service returns either the value 127.0.0.2 or 127.0.0.3 in response to the lookup of the connection address.

The access database and the blackhole lists block mail from known spam sources and from open relays. But not all spam comes from known spam sources. Sometimes you don’t know it is junk mail until you read it. Mail filtering tools can examine the content of the mail and decide how it should be handled based on the information found in the mail itself.

MILTER

sendmail provides direct access via the sockets interface to external mail filtering programs, called MILTERs, which are written in accordance with the Sendmail Mail Filter API. External mail filters are defined in the sendmail configuration using either the INPUT_MAIL_FILTER macro or the MAIL_FILTER macro. Other than the macro name, the syntax of both macros is identical. For example, here is the syntax of the INPUT_MAIL_FILTER macro:

INPUT_MAIL_FILTER(name, equates)

The name is an arbitrary name used by sendmail—much like an internal mailer name or an internal database name. There are up to three equates written in the form of key-letter = value, where key-letter is one of the following:

S

The S equate is required because it defines the socket used to communicate with the external filter. The socket definition is written in the form S= type:specification, where type is the socket type and specification defines the socket in the manner required by the given socket type. Three socket types are supported:

S=unix:path

Unix sockets are supported. path is the full pathname of the Unix socket. The keyword unix can be replaced by the synonym local (e.g., S=local:/var/run/filter1.sock).

S=inet:port @ host

The keyword inet requests an IP socket. port is the network port number used by the filter. host is the hostname or IP address of the system on which the filter is running.

S=inet6:port @ host

IPv6 sockets are also supported. The keyword inet6 requests an IPv6 socket, port identifies the IPv6 port used by the filter, and host identifies the system the filter is running on. host can be either an IPv6 address or a hostname that maps to an IPv6 address.

F= letter

Use this optional equate to define how a socket failure should be handled. By default, sendmail continues with normal mail processing if the socket fails or the filter responds in an unexpected manner. Use F=R to reject the connection with a permanent error or F=T to defer the message with a temporary error when a socket or filter problem occurs.

T= letter:value ; letter:value ; ...

Use this optional equate to change the default timeouts. Four letter values are available:

C

Defines the connection timeout. By default, the connection times out if a successful connection has not been made in five minutes (5m).

E

Defines the overall timeout. This defaults to five minutes (5m).

R

Defines the timeout for reading a reply from the filter. This defaults to 10 seconds (10s).

S

Defines the timeout for sending data to the filter. The default is 10 seconds (10s).

Given this syntax, an INPUT_MAIL_FILTER macro that adds support for the external MIMEDefang program might look like the following:

INPUT_MAIL_FILTER(`mimedefang',`S=unix:/var/run/mimedefang.sock, T=S:5m;R:5m')

This macro defines mimedefang as the internal name for this filter. sendmail will create the socket /var/run/mimedefang.sock and communicate with the filter through this Unix socket. Because sendmail creates the socket, it should not already exist. The F equate is not used in the example, therefore, sendmail will continue to process the message in a normal manner even if the socket fails or the filter responds incorrectly. The T equate increases the send and receive timers to five minutes.

The INPUT_MAIL_FILTER macro defines only one filter. To use multiple filters, add multiple INPUT_MAIL_FILTER or MAIL_FILTER macros to the sendmail configuration. When multiple filters are used, the difference between MAIL_FILTER and INPUT_MAIL_FILTER becomes clear. Here is an example. Assume the sendmail configuration contains the following macros:

INPUT_MAIL_FILTER(`filter1', `S=unix:/var/run/filter1.soc')
INPUT_MAIL_FILTER(`filter2', `S=unix:/var/run/filter2.soc')
INPUT_MAIL_FILTER(`filter3', `S=unix:/var/run/filter3.soc')

The INPUT_MAIL_FILTER macro sets the order in which the filters are used. Given these three macros and the order in which they are listed, sendmail would send data through filter1, filter2, and filter3 in that order. To create an equivalent configuration with the MAIL_FILTER macro requires four sendmail configuration lines:

MAIL_FILTER(`filter1', `S=unix:/var/run/filter1.soc')
MAIL_FILTER(`filter2', `S=unix:/var/run/filter2.soc')
MAIL_FILTER(`filter3', `S=unix:/var/run/filter3.soc')
define(`confINPUT_MAIL_FILTERS', `filter1, filter2, filter3')

MAIL_FILTER macros do not set the order in which the filters are used; therefore, they must be accompanied by a confINPUT_MAIL_FILTERS define that specifies the order of execution. If the confINPUT_MAIL_FILTERS define is not used when MAIL_FILTER macros are used, the filters defined by the macro are ignored. Of course, when MAIL_FILTER macros and the confINPUT_MAIL_FILTERS define are used, mail filters do not need to be run in the order in which they are declared. For example, changing the confINPUT_MAIL_FILTERS define to the one shown here would run the filters in reverse order:

define(`confINPUT_MAIL_FILTERS', `filter3, filter2, filter1')

The filters used by sendmail are external programs. Any reasonably skilled programmer can write a basic filter program but creating one that is truly effective at fighting mail abuse is a challenge. Luckily, many skilled people have already created useful filters. Before you reinvent the wheel, search the Web for filters that may solve your email problems. Here are a few places to start:

http://www.milter.org/

A clearing house for information about MILTERs in general.

http://www.mimedefang.org/

A powerful, extensible MILTER that supports virus scanning, deletion of attachments based on name and content, and SpamAssassin processing.[4]

http://www.snert.com/Software/milter-sender/

A MILTER that attempts to verify that the sending address is a valid email address. Many spammers do not use valid sender addresses.

http://www.amavis.org/

A virus scanning MILTER.

http://sendmail.com/

A variety of commercially supported MILTERs are available from Sendmail, Inc.

There are many more MILTER-related web sites and many more MILTERs available. However, MILTERs are not the only tools available for mail filtering; procmail is also widely used.

Filtering with procmail

Most sendmail texts, and this one is no exception, concentrate on procmail for mail filtering. There are a few reasons for this emphasis:

  • procmail is tightly integrated with sendmail.

  • procmail is a powerful tool that can be used for much more than spam filtering.

  • procmail is the default local mail delivery program for Linux systems, and it can be used as the local mailer on any Unix system by adding the local_procmail feature to the sendmail configuration.

  • The MAILER(procmail) command adds procmail to sendmail’s list of mailers.

The variety of ways that procmail can be invoked add to the flexibility of this tool. As noted above, sendmail can be configured to use procmail as the local mailer. procmail can also be invoked from the shell command line. It can be invoked from the mailertable, as described in Recipe 6.8, and it can be executed from the user’s .forward file, in the following manner:

                  $ cat > .forward
"|/usr/bin/procmail"
Ctrl-D

A common mistake is to think that, because system-wide mail filters affect a large number of users, the most important mail filtering takes place at the system level. User-level mail filtering is just as important as system-level filters. User-level filters:

  • Provide a last line of defense against spam that makes its way through the system filters.

  • Allow users to enforce their own personal email policies.

  • Permit content filtering without any fear of compromising privacy.

  • Deal with a much smaller volume of mail.

For these reasons, and more, it is good to encourage users to learn about and use the mail filters available to them. Many end user mail tools come with mail filtering features. These are not integrated into sendmail and thus are not discussed here.

procmail is a powerful, although complex, mail filtering system. Personal procmail filters are defined by the user in the user’s home directory in a file named .procmailrc. The system administrator defines system-wide mail filters in the /etc/procmailrc file and uses the /etc/procmailrc file for general anti-spam filtering. The end user uses .procmailrc to add filtering for personal preferences. The format of both files is the same.

The .procmailrc file contains two types of entries: environment variable assignments and mail filtering rules, which are called recipes in procmail parlance. Environment variable assignments are straightforward and look just like these assignments would in a shell script. For example, HOME=/home/craig is a valid environment variable assignment. The .procmailrc manpage lists more than 30 environment variables.

The real substance of a .procmailrc file are the recipes. The syntax of each recipe is:

:0 [flags] [:[lockfile]]
[* condition]
action

Every recipe begins with :0, which differentiates it from an assignment statement. The :0 is optionally followed by flags that change how the filter is processed. Table 6-3 lists the flags and their uses.

Table 6-3. procmail recipe flags

Flag

Meaning

A

Execute this recipe if the preceding recipe evaluated to true.

a

This has the same meaning as the A flag, except that the preceding recipe must also have successfully completed execution.

b

Pass the body of the message on to the destination. This is the default.

B

Filter the message body.

c

Create a carbon copy of this mail.

D

Tests are case sensitive. By default, case is ignored.

e

Execute this recipe if the execution of the preceding recipe returned an error.

E

Execute this recipe if the preceding recipe was not executed.

f

Pass the data through an external filter program.

H

Filter the message headers. This is the default.

h

Pass the message header on to the destination. This is the default.

I

Ignore write errors for this recipe.

r

Write the mail out without any additional format checks.

w

Check the exit code of the external filter program.

W

This is the same meaning as the w flag, except no error message is printed.

Use the optional lockfile variable to specify the name of the local lock file to be used for this recipe. The lock file prevents multiple copies of procmail from writing to the same mailbox at the same time, which can happen on a busy system. The lockfile name is preceded by a colon. If the colon is used and no name is specified, a default lockfile name created from the mailbox name and the extension .lock is used. If no local lock file is specified, a default lock file will be used. However, the procmail documentation encourages the use of local lock files.

The conditional test is optional. If no condition is provided, the recipe acts as if the condition is true, which means that the action is taken. If a condition is specified it must begin with an asterisk (*). The condition is written as a regular expression. If the value defined by the regular expression is found in the mail, the condition evaluates to true and the action is taken. To take an action when mail does not contain the specified value, put an exclamation in front of the regular expression. Here are some examples of valid conditional tests:

* ^From.*[email protected]
* !^Subject: Chapter

The first conditional checks to see if the mail contains a line that begins with (^) the literal string From followed by any number of characters (.*) and the literal string [email protected]. The second conditional matches all mail that does not (!) contain a line that begins with the string Subject: Chapter. If multiple conditions are defined for one recipe, each condition appears on a separate line.

While there may be multiple conditions in a procmail recipe, there can be only one action. The action can direct the mail to a file, forward it to another email address, or send it to a program, or the action can define additional recipes to process the message. If the action is an additional recipe, it begins with :0. If the action directs the mail to an email address, it begins with an exclamation (!), and if it directs the mail to a program, it begins with a vertical bar (|). If the action directs the mail to a file, just the name of the file is specified. The following example illustrates how mail is passed to an external program for processing:

:0 B
* .*pheromones
| awk -f spamscript > spam-suspects

The B flag applies the conditional test to the content of the message body. All messages that contain the word “pheromones” anywhere in the message body are passed to awk for processing. In this example, awk runs a program file named spamscript that extracts information from the mail and stores it in a file named spam-suspects. You can imagine that the administrator of this system created spamscript to extract the email addresses from suspected spam.

The example shows procmail filtering the message body. By default, procmail looks at the message headers. Message headers can also be given special attention inside of the sendmail configuration by using custom rulesets.

Custom rulesets

sendmail allows you to define custom processing for the addresses and headers from incoming mail, and it provides some hooks for this purpose. The hooks used for custom address processing are:

Local_check_relay

This is a hook into the check_relay ruleset. The Local_check_relay ruleset is passed the hostname and the IP address of the host that initiated the email connection.

Local_check_mail

This is a hook into the check_mail ruleset that processes the envelope sender address from the MAIL From: SMTP command. Recipe Recipe 6.10 contains a sample Local_check_mail ruleset.

Local_check_rcpt

This is a hook into the check_rcpt ruleset that checks the envelope recipient address defined by the RCPT To: SMTP command.

These rulesets are not specially designed to detect and delete junk mail; they have a broader applicability. However, these ruleset hooks are useful for fighting spam.

In addition to these hooks that are called from standard rulesets, a ruleset can be called from a header definition to perform custom header processing. The basic syntax of the sendmail.cf H command defines the format of mail headers. In the basic syntax, the header definition starts with the H command followed by the name of the header and the format of that header. The syntax to call a ruleset from an H command is:

Hname: $>ruleset

where name is the header name and ruleset is the ruleset called to process incoming headers of that name.

Use this capability to check incoming headers to detect spam mail from the header information. Recipe 6.9 provides an example of how this capability is used.

6.1. Blocking Spam with the access Database

Problem

Because the bulk of mail arriving from specific sites is junk, you have been asked to configure sendmail to block all mail from those sites.

Solution

Add the addresses you want blocked to the /etc/mail/access text file. The key to each entry is the spammer’s address, and the return is either DISCARD, to silently drop the mail; REJECT, to drop the mail with a standard error; or ERROR, to reject the mail with a customer error message. Use the makemap script to build a hash database from the text file.

Next, create a sendmail configuration containing the access_db feature. Here is the required FEATURE macro:

dnl Use the access database
FEATURE(`access_db')

Following the example in Recipe 1.8, rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail.

Discussion

Use REJECT, ERROR, or DISCARD in the access database to block junk mail. The following sample access database blocks mail from three sites:

example.com          REJECT
wrotethebook.net     ERROR:5.7.1:550 Invalid mail source
fake.ora.com         DISCARD

A telnet test shows what the remote site sees depending on the action defined in the database:

# telnet localhost smtp
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 chef.wrotethebook.com ESMTP Sendmail 8.12.9/8.12.9; Fri, 22 Aug 2003 12:01:37 -
0400
HELO localhost
250 chef.wrotethebook.com Hello IDENT:UWSRv+Jij66J8vALUBVBECbGPVoU8OQe@localhost 
[127.0.0.1], pleased to meet you
MAIL From:<[email protected]>
550 5.7.1 <[email protected]>... Access denied
MAIL From:<[email protected]>
550 5.7.1 <[email protected]>... Invalid mail source
MAIL From:<[email protected]>
250 2.1.0 <[email protected]>... Sender ok
QUIT
221 2.0.0 chef.wrotethebook.com closing connection
Connection closed by foreign host.

Mail from example.com is rejected with an “Access denied” error because the example.com entry in the sample access database defines REJECT as the action taken for mail received from that domain. Mail from wrotethebook.net is rejected with the error “Invalid mail source,” which was defined in the access database with the ERROR command. On the other hand, from the point of view of the remote system, mail from fake.ora.com appears to be accepted by the server. A sendmail -bt test is needed to see the effect of the DISCARD action defined in the access database for mail from fake.ora.com:

# sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> check_mail [email protected]
check_mail         input: junk @ fake . ora . com
Basic_check_mail   input: junk @ fake . ora . com
tls_client         input: $| MAIL
D                  input: < > < ? > < ! "TLS_Clt" > < >
D                returns: < ? > < > < ? > < ! "TLS_Clt" > < >
A                  input: < > < ? > < ! "TLS_Clt" > < >
A                returns: < > < ? > < ! "TLS_Clt" > < >
TLS_connection     input: $| < > < ? > < ! "TLS_Clt" > < >
TLS_connection   returns: OK
tls_client       returns: OK
CanonAddr          input: < junk @ fake . ora . com >
canonify           input: < junk @ fake . ora . com >
Canonify2          input: junk < @ fake . ora . com >
Canonify2        returns: junk < @ fake . ora . com >
canonify         returns: junk < @ fake . ora . com >
Parse0             input: junk < @ fake . ora . com >
Parse0           returns: junk < @ fake . ora . com >
CanonAddr        returns: junk < @ fake . ora . com >
SearchList         input: < + From > $| < F : junk @ fake . ora . com > < U : junk @ 
> < D : fake . ora . com > < >
F                  input: < junk @ fake . ora . com > < ? > < + From > < >
F                returns: < ? > < >
SearchList         input: < + From > $| < U : junk @ > < D : fake . ora . com > < >
U                  input: < junk @ > < ? > < + From > < >
U                returns: < ? > < >
SearchList         input: < + From > $| < D : fake . ora . com > < >
D                  input: < fake . ora . com > < ? > < + From > < >
D                returns: < DISCARD > < >
SearchList       returns: < DISCARD >
SearchList       returns: < DISCARD >
SearchList       returns: < DISCARD >
Basic_check_mail returns: $# discard $: discard
check_mail       returns: $# discard $: discard
> /quit

In this test, the address [email protected] is processed through the check_mail ruleset, which checks the MAIL From: address. The check_mail ruleset processes the address and returns “discard,” meaning that mail from fake.ora.com will be silently discarded.

See Also

The cf/README file, Chapter 3, and Introduction to this chapter provide more information about the access database. The sendmail book covers the access database in Section 7.5.

6.2. Preventing Local Users from Replying to Spammers

Problem

Some local users encourage spam by responding to spam emails. You have been asked to configure sendmail to stop the spammers and to stop those who encourage spam.

Solution

Before creating any user accounts, create an acceptable use policy that, among many other things, gives you the power to block spam communications—both inbound and outbound. Ensure that all users agree to this policy before giving out any user accounts.

Add the spam addresses you want blocked to the /etc/mail/access text file. Use To: and From: tags to prevent mail from being sent to spammers or from being accepted from spammers. Run makemap to build a hash database from the text file.

Create a sendmail configuration that enables the access database with the access_db feature. The required sendmail FEATURE command is:

dnl Use the access database
FEATURE(`access_db')

Rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail, as described in Recipe 1.8.

Discussion

By default, the access database applies to source addresses. The action defined in the database entry is taken based on the source of the email. Given the access database created for Recipe 6.1, mail from example.com, wrotethebook.net, and fake.ora.com is rejected, as the tests in that recipe show. For example, mail from anyone at example.com is rejected with an “Access denied” error. However, the access database from Recipe 6.1 does not prevent mail from the local host being sent to someone at example.com.

Adding the To: tag to an access database entry applies the action defined in the entry to recipient addresses that match the key, while the From: tag specifically requests that the action be applied to matching source addresses. Here is the access database from Recipe 6.1 rewritten with To: and From: tags:

From:example.com          REJECT
To:example.com            ERROR:5.7.1:550 Mail to this site is not allowed
From:wrotethebook.net     ERROR:5.7.1:550 Invalid mail source
To:wrotethebook.net       ERROR:5.7.1:550 Mail to this site is not allowed
From:fake.ora.com         DISCARD
To:fake.ora.com           ERROR:5.7.1:550 Mail to this site is not allowed

Because the action for the From: example.com entry is REJECT, mail from that site is rejected as shown in Recipe 6.1. With the addition of the To: entry, mail addressed to example.com is also rejected, as this test shows:

# telnet localhost smtp
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 chef.wrotethebook.com ESMTP Sendmail 8.12.9/8.12.9; Fri, 22 Aug 2003 12:01:37 -
0400
HELO localhost
250 chef.wrotethebook.com Hello IDENT:UWSRv+Jij66J8vALUBVBECbGPVoU8OQe@localhost 
[127.0.0.1], pleased to meet you
MAIL From:<[email protected]>
250 2.1.0 <[email protected]>... Sender ok
RCPT To:<[email protected]>
550 5.7.1 <[email protected]>... Mail to this site is not allowed
QUIT
221 2.0.0 chef.wrotethebook.com closing connection
Connection closed by foreign host.

Warning

Care must be taken when blocking outbound mail. Local users expect to be able to communicate with anyone, and they do not want you deciding who they can and cannot talk to. An AUP that gives you this authority is essential before you take any action. Be prepared for complaints no matter what the AUP says.

Alternatives

The blacklist_recipients feature is an alternative way to block outbound mail to known spammers. The blacklist_recipients feature applies every untagged entry in the access database to recipient addresses. The following lines added to the sendmail configuration enable the access database and apply the database to recipient addresses:

dnl Use the access database
FEATURE(`access_db')
dnl Also apply the access database to recipient addresses
FEATURE(`blacklist_recipients')

The blacklist_recipients feature works well, and it is very easy to use. However, because it applies to every untagged entry in the access database, it does not provide the level of configuration control provided by the To: tag. Additionally, tags are self-documenting. Anyone looking at the sample access database just shown understands that mail to example.com is not allowed when they see the To: tag and the error in the action field.

See Also

Chapter 3 and the Introduction to this chapter provide more information about the access database. The sendmail book covers the access database in Section 7.5 and the blacklist_recipients feature in 7.5.5. The Anti-Spam Configuration Control section of the cf/README file also covers this topic.

6.3. Reading the access Database via LDAP

Problem

You have been asked to configure sendmail to read the access database from an LDAP server.

Solution

If necessary, recompile and reinstall sendmail to add LDAP support to the sendmail host, and add the sendmail schema to the LDAP configuration on the LDAP server. Both of these steps are shown in Recipe 1.3.

On the LDAP server, enter the access database records in an LDIF file using the sendmailMTAMap object class format defined by the sendmail schema. Use the ldapadd script to store the access records in the LDAP database.

On the sendmail host, add the confLDAP_CLUSTER define and the access_db feature to the sendmail configuration. Set the confLDAP_CLUSTER to the same value used for the sendmailMTACluster attribute in the access LDAP records. Add the string LDAP to the access_db FEATURE command to tell sendmail to read the access data via LDAP. Here are sample lines that could be added to the sendmail configuration:

dnl Define the LDAP cluster name
define(`confLDAP_CLUSTER', `wrotethebook.com')
dnl Read the access database via LDAP
FEATURE(`access_db', `LDAP')

Rebuild and reinstall sendmail.cf file, then restart sendmail. See Recipe 1.8 for an example.

Discussion

The sendmail distribution provides an LDAP schema file that defines the basic attributes needed for sendmail databases and classes. You can, of course, define your own custom schema. However, using the sendmail schema simplifies both the LDAP and sendmail configurations. Using the sendmail schema to define the access entries for LDAP database, the following example converts the access entries used in Recipe 6.1 into LDAP records:

# cat > ldap-access
               dn: sendmailMTAMapName=access, dc=wrotethebook, dc=com
               objectClass: sendmailMTA
               objectClass: sendmailMTAMap
               sendmailMTACluster: wrotethebook.com
               sendmailMTAMapName: access

               dn: sendmailMTAKey=example.com, sendmailMTAMapName=access, dc=wrotethebook, dc=com
               objectClass: sendmailMTA
               objectClass: sendmailMTAMap
               objectClass: sendmailMTAMapObject
               sendmailMTAMapName: access
               sendmailMTACluster: wrotethebook.com
               sendmailMTAKey: example.com
               sendmailMTAMapValue: REJECT

               dn: sendmailMTAKey=wrotethebook.net, sendmailMTAMapName=access, dc=wrotethebook, 
dc=com
               objectClass: sendmailMTA
               objectClass: sendmailMTAMap
               objectClass: sendmailMTAMapObject
               sendmailMTAMapName: access
               sendmailMTACluster: wrotethebook.com
               sendmailMTAKey: wrotethebook.net
               sendmailMTAMapValue: ERROR:5.7.1:550 Invalid mail source

               dn: sendmailMTAKey=fake.ora.com, sendmailMTAMapName=access, dc=wrotethebook, dc=com
               objectClass: sendmailMTA
               objectClass: sendmailMTAMap
               objectClass: sendmailMTAMapObject
               sendmailMTAMapName: access
               sendmailMTACluster: wrotethebook.com
               sendmailMTAKey: fake.ora.com
               sendmailMTAMapValue: DISCARD
               Ctrl-D
# ldapadd -x -D "cn=Manager,dc=wrotethebook,dc=com" 
               > -W -f ldap-access
Enter LDAP Password: SecretLDAPpassword
adding new entry "sendmailMTAMapName=access, dc=wrotethebook, dc=com"

adding new entry "sendmailMTAKey=example.com, sendmailMTAMapName=access, 
dc=wrotethebook, dc=com"

adding new entry "sendmailMTAKey=wrotethebook.net, sendmailMTAMapName=access, 
dc=wrotethebook, dc=com"

adding new entry "sendmailMTAKey=fake.ora.com, sendmailMTAMapName=access, 
dc=wrotethebook, dc=com"

Four LDAP records are used to add the three access entries from Recipe 6.1. The first record tells LDAP the access database map name. Subsequent LDAP records reference that map name to add access records to the LDAP database.

The next three LDAP records define the three access entries described in Recipe 6.1. Notice that the sendmailMTAKey and the sendmailMTAMapValue attributes of each record match the key/value pairs from the original access entries. By varying the values stored in the sendmailMTAMapName, sendmailMTAKey, and sendmailMTAMapValue attributes, the basic LDAP record format used for the access database can be used for any sendmail database.

After the records are converted from the LDIF file and added to the LDAP database, they can be examined using ldapsearch:

# ldapsearch -LLL -x '(sendmailMTAMapName=access)' sendmailMTAMapValue
dn: sendmailMTAMapName=access, dc=wrotethebook, dc=com

dn: sendmailMTAKey=example.com, sendmailMTAMapName=access, dc=wrotethebook, dc=com
sendmailMTAMapValue: REJECT

dn: sendmailMTAKey=wrotethebook.net, sendmailMTAMapName=access, dc=wrotethebook, dc=com
sendmailMTAMapValue: ERROR:5.7.1:550 Invalid mail source

dn: sendmailMTAKey=fake.ora.com, sendmailMTAMapName=access, dc=wrotethebook, dc=com
sendmailMTAMapValue: DISCARD

This test shows that the access database records are available from the LDAP server. If your sendmail system requires -h and -b values for the ldapsearch test, those same values will be required for the sendmail configuration. Set -h and -b using the confLDAP_DEFAULT_SPEC define, as shown in Recipe Recipe 5.9.

Now, sendmail needs to be configured to use the LDAP server. First, the confLDAP_CLUSTER command is added to the sendmail configuration to tell sendmail the LDAP cluster name. The sendmail schema allows for records that apply to a single host or to a group of hosts, called a cluster. If LDAP records apply to a single host, they use the sendmailMTAHost attribute. sendmail only retrieves records that use the sendmailMTAHost attribute if the value assigned to that attribute is the fully qualified name of the sendmail host. Records that apply to a group of hosts use the sendmailMTACluster attribute. To retrieve records that use that attribute, sendmail must be configured with the cluster name. That is exactly what this recipe does. It defines the LDAP access records using the sendmailMTACluster attribute and informs sendmail of the cluster name using the confLDAP_CLUSTER define.

Adding the LDAP argument to the access_db FEATURE command tells sendmail to read the access database from the LDAP server using the standard sendmail schema. If you define a custom schema, you must tell sendmail how to use it to retrieve access records. For example:

FEATURE(`access_db', `ldap: -1 -k (&(objectClass=OurAccessDB)(OurAccesDBKey=%0)) 
-v OurAccessDBValue')

The sample attribute names should be ignored. However, the format of the FEATURE command is similar to the one you would need to define in order to retrieve access data using a custom LDAP schema. The -k option defines the LDAP search criteria used as a database key. The attributes used in that search criteria must match the attributes defined in your schema. The -v option specifies the LDAP attribute that contains the return value. Again, this must match the attribute from your custom schema. Using the default sendmail schema simplifies the sendmail configuration. Simply use the LDAP string in the access_db FEATURE command, as shown in the Solution section.

A few tests, run after this recipe is installed, show that sendmail is reading the LDAP data. First, run a sendmail -bt test and use the /map command to retrieve an access record from the LDAP server:

# sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> /map access fake.ora.com
map_lookup: access (fake.ora.com) returns DISCARD (0)
> /quit

This test shows that the access database functions in the same manner whether it is read from a local database or from an LDAP server. Rerunning the test used in Recipe 6.1 shows that sendmail blocks mail using LDAP exactly as it did using a local access database:

# sendmail -bs
220 rodent.wrotethebook.com ESMTP Sendmail 8.12.9/8.12.9; Thu, 27 Mar 2003 12:42:41 -
0500
MAIL From:<[email protected]>
550 5.7.1 <[email protected]>... Access denied
MAIL From:<[email protected]>
550 5.7.1 <[email protected]>... Invalid mail source
QUIT
221 2.0.0 rodent.wrotethebook.com closing connection

LDAP does not change the way sendmail works. The decision to use LDAP is not driven by sendmail; it is driven by LDAP. If you already use LDAP to centralize the management of information, you may choose to add sendmail configuration data to your LDAP server.

See Also

Recipe 6.1 and Recipe 6.2 explain how the access database is used to control spam; in particular, Recipe 6.1 explains the specific access database entries used for this recipe. The cf/README file covers this topic in the Using LDAP for Aliases, Maps, and Classes section. The sendmail book covers the access_db feature in Section 7.5 and the confLDAP_CLUSTER define in Section 21.9.82.

6.4. Using a DNS Blackhole List Service

Problem

You have been asked to configure sendmail to use a blackhole list service to stop a large amount of UCE from a wide array of sources with a minimal amount of effort.

Solution

Add the dnsbl feature to the sendmail configuration. Identify the specific blackhole list service you wish to use on the dnsbl command line. Here is an example:

dnl Use the DSBL blacklist service
FEATURE(`dnsbl', `list.dsbl.org')

Using Recipe 1.8 as a guide, rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail.

Discussion

The dnsbl feature adds the sendmail.cf code needed to enable a DNS blacklist service. The dnsbl feature uses a K command to define the dnsbl database as a host type database, which means lookups in dnsbl are really passed to DNS for resolution.[5] The dnsbl feature also adds a few rules to the Basic_check_relay ruleset, which is called from the check_relay ruleset. The added rules lookup the connection address in the dnsbl database. If the connection address is found in the database, mail from that address is rejected with an error message. If the connection address is not found in the dnsbl database, the mail is passed on for further processing. A sendmail -bt test shows the impact of the added rewrite rules:

# sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> .D{client_addr}192.168.111.68
> Basic_check_relay <>
Basic_check_rela   input: < >
Basic_check_rela returns: $# error $@ 5 . 7 . 1 $: "550 Rejected: " 192 . 168 . 111 .
68 " listed at list.dsbl.org"
> /quit

Because there is no active connection—this is just a test—the first step is to statically define a connection address for the test. Next, the Basic_check_relay ruleset is called and passed to an empty workspace. The workspace passed to the ruleset in this test is unimportant because the first rule added to the ruleset by the dnsbl feature unconditionally replaces the workspace with the value found in ${client_addr}. Therefore, the value looked up in the dnsbl database is the connection address stored in the ${client_addr} macro. In this test, the address 192.168.111.68 is found in the blackhole list maintained at list.dsbl.org, so mail from that address is rejected. The mail is rejected with the error message:

550 Rejected: 192.168.111.68 listed at list.dsbl.org

The error message displays the address that was rejected and the service that recommended the rejection. This information is important. The administrators at 192.168.111.68 might need to contact the blackhole service to find out why their system is blacklisted and what they can do to get it removed from the blackhole list. Often, a system is blacklisted because of a configuration error that creates an open relay. As soon as the error is fixed, the administrator wants to get the system removed from the blackhole list. Knowing which services have blacklisted the system tells the administrator which services must be contacted to get full mail service restored.

This configuration uses the blackhole server at list.dsbl.org because that is the service specified with the dnsbl feature command in this recipe, which is just an example; it is not a recommendation for the list.dsbl.org service. There are many blackhole services available, some of which are listed in Table 6-2. Go to each service’s web site and evaluate their policy for listing hosts in the database. Select the service whose policy most closely matches the policy you want to enforce on your server.

When no service is specified on the dnsbl feature command line, sendmail defaults to using blackholes.mail-abuse.org, which is the same service that was used by the deprecated sendmail rbl feature.

The enhdnsbl feature could be used as an alternative to dnsbl for this recipe. However, the enhdnsbl feature provides no real advantage in this particular case.

See Also

Before using any blackhole service, visit its web site. Using a blackhole service places an external organization in charge of the mail that your system receives. Evaluate the policy and mission of the blackhole listing service to ensure that its goals are compatible with yours. See Recipe 6.5 and Recipe 6.6 for additional information about blackhole services before implementing this recipe. The sendmail book covers the dnsbl feature in Section 7.2.1 and the enhdnsbl feature in 7.2.2.

6.5. Building Your Own DNS Blackhole List

Problem

You need to create your own DNS blackhole list because no external blackhole service provides exactly the listing policy and content you need.

Solution

The domain administrator must create a DNS zone file, in the proper format, that lists all of the connection addresses that are to be blacklisted. The special DNS address records in the zone file are constructed by reversing the IP address of the blacklisted system to create the DNS name field of the record and by using an address such as 127.0.0.2 in the data field of the address record. This format means that hosts are blacklisted by IP address instead of by name, which makes sense because the dnsbl lookup is done using the connection IP address. The DNS server must be authoritative for the domain in which the blackhole list is to be located. This is normally done by creating a special subdomain for the blackhole list within the zone of authority of the DNS server.

On the sendmail system, create a configuration containing the dnsbl feature.[6] Identify the local DNS blackhole list on the dnsbl command line. Here is an example:

dnl Point dnsbl to our local DNS blackhole list
FEATURE(`dnsbl', `dnsbl.wrotethebook.com')

Following Recipe 1.8, rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail.

Discussion

Using a blackhole list service is simple but inflexible because you can’t choose which sites are listed. This means that mail from a friendly site might be blocked just because the administrator at that site misconfigured relaying. For this reason, some organizations decide to build their own DNS-based blackhole list. Creating your own blackhole server ensures that connectivity to all of the sites you want to reach is under your direct control, but it requires both sendmail and DNS expertise.

The DNS administrator uses a zone statement in the DNS server’s named.conf file to load the blackhole database. Assuming that the blacklisted hosts are defined in a zone file named blacklisted.hosts, which provides the data for a domain named dnsbl.wrotethebook.com, the following zone statement would be used:

zone "dnsbl.wrotethebook.com" IN {
        type master;
        file "blacklisted.hosts";
        allow-update { none; };
};

Blackhole entries for addresses 10.0.187.215 and 192.168.0.3 defined in the blacklisted.hosts file would be the following:

215.187.0.10                 IN A 127.0.0.2 
3.0.168.192                  IN A 127.0.0.2

The newly created DNS domain is referenced as the source for blackhole list data on the dnsbl feature command line in the Solution section. Mail from any site listed in the dnsbl.wrotethebook.com domain is rejected, as this attempt to send mail from 192.168.0.3 shows:

# telnet chef smtp
Trying 192.168.0.8...
Connected to 192.168.0.8.
Escape character is '^]'.
220 chef.wrotethebook.com ESMTP Sendmail 8.12.9/8.12.9; Fri, 22 Aug 2003 12:01:37 -
0400
helo rodent.wrotethebook.com
250 chef.wrotethebook.com Hello rodent.wrotethebook.com [192.168.0.3], pleased to 
meet you
MAIL From:<[email protected]>
550 5.7.1 Rejected: 192.168.0.3 listed at dnsbl.wrotethebook.com
QUIT
221 2.0.0 chef.wrotethebook.com closing connection
Connection closed by foreign host.

The connection address 192.168.0.3 is found in the dnsbl.wrotethebook.com domain, so our server rejects the mail and returns the error message “550 5.7.1 Rejected: 192.168.0.3 listed at dnsbl.wrotethebook.com.” This default error message can be changed with an additional argument on the dnsbl feature command line. For example, the command:

FEATURE(`dnsbl', `dnsbl.wrotethebook.com', `"Mail rejected. "$&{client_addr}" is a 
suspected spam relay."')

changes the error message to “Mail rejected. 192.168.0.3 is a suspected spam relay.” However, the standard message works well and provides the remote site with more information.

The small number of systems used in the blackhole list in this recipe could much more easily have been handled by the access database. In most cases, using the access database to block unwanted mail connections is much easier than creating your own blackhole list. Creating and maintaining your own blackhole list is labor intensive. The systems that should be added to and removed from the list are constantly changing. Additionally, a great deal of information is needed to initially build a list. It is possible to use a mail filtering tool, such as procmail, to automatically collect suspected addresses directly from mail. However, it is difficult to create a system that collects the right information and keeps it up-to-date. Most administrators prefer to create their own blackhole list based on the blackhole list provided by a blackhole list service. The services already have large lists and they constantly maintain them. Most blackhole list services provide some way to download the entire list. For example, the DSBL list can be downloaded using rsync:

# rsync rsync.dsbl.org::dsbl/bind-list.dsbl.org .

Periodically downloading a list and customizing it is one way to create your own blackhole list. But even if you start with a preexisting list, creating your own blackhole list is not a task that should be undertaken lightly. Creating your own blackhole list is one of the most difficult techniques for controlling unwanted junk email.

As usual, the choice between using a blackhole list service or building your own blackhole list is a choice between simplicity and flexibility. Most sites choose simplicity. If you don’t have the available staff necessary to build and maintain your own blackhole list, stick with a standard blackhole list service, as described in Recipe 6.4, and use the technique described in Recipe 6.6 to make it comply with your needs.

See Also

Recipe 6.4 describes a simple method for using a blackhole list. Recipe 6.6 describes how major shortcomings of a blackhole list service can be overcome using the access database. Review both of these recipes before implementing this recipe. The sendmail book covers the dnsbl feature in Section 7.2.1 and the enhdnsbl feature in Section 7.2.2. For information on DNS configuration, see DNS and BIND, by Paul Albitz and Cricket Liu (O’Reilly), and Linux DNS Server Administration, by Craig Hunt (Sybex).

6.6. Whitelisting Blacklisted Sites

Problem

You use a blackhole list service that blacklists a few sites with which you must communicate. You need to configure sendmail to override the blackhole list for specific addresses.

Solution

To override the blackhole list service for a given address, add the address to the /etc/mail/access text file, and assign the keyword OK as the return value for the address. Use makemap to build a hash type database from the text file.

Create a sendmail configuration that uses either the dnsbl feature or the enhdnsbl feature to select a blackhole list service and the access_db feature to override the blackhole list for selected sites. Here are samples lines that might be added to the sendmail configuration to enable these features:

dnl Use dnsbl and select a blacklist service
FEATURE(`dnsbl', `list.dsbl.org')
dnl Use the access database
FEATURE(`access_db')

Rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail. See Recipe Recipe 1.8 for an example.

Discussion

The dnsbl feature adds support for a DNS blackhole list service to the sendmail.cf configuration, and it specifies the service that will be used. Table 6-2 provides a list of some of the available services. If no service is selected, the MAPS RBL is used by default. Choose a service carefully.

The sample blackhole list is configured to block email from 192.168.0.3, as this test, run from 192.168.0.3, shows:

# telnet chef smtp
Trying 192.168.0.8...
Connected to 192.168.0.8.
Escape character is '^]'.
220 chef.wrotethebook.com ESMTP Sendmail 8.12.9/8.12.9; Fri, 22 Aug 2003 12:01:37 -
0400
helo rodent.wrotethebook.com
250 chef.wrotethebook.com Hello rodent.wrotethebook.com [192.168.0.3], pleased to 
meet you
MAIL From:<[email protected]>
550 5.7.1 Rejected: 192.168.0.3 listed at list.dsbl.org
QUIT
221 2.0.0 chef.wrotethebook.com closing connection
Connection closed by foreign host.

Use the access database to override some entries in the blackhole database. In this example, we override the blackhole list service for the following sites:

# cd /etc/mail
# cat > access
               192.168.0.3        OK
               24.199.249.90      OK
               Ctrl-D
# makemap hash access < access

After building the access database, rerunning the telnet test from 192.168.0.3 shows the following result:

# telnet chef smtp
Trying 192.168.0.8...
Connected to 192.168.0.8.
Escape character is '^]'.
220 chef.wrotethebook.com ESMTP Sendmail 8.12.9/8.12.9; Fri, 22 Aug 2003 12:01:37 -
0400
helo rodent.wrotethebook.com
250 chef.wrotethebook.com Hello rodent.wrotethebook.com [192.168.0.3], pleased to 
meet you
MAIL From:<[email protected]>
250 2.1.0 <[email protected]>... Sender ok
QUIT
221 2.0.0 chef.wrotethebook.com closing connection
Connection closed by foreign host.

Now, mail from 192.168.0.3 is accepted, even though 192.168.0.3 is still listed in the blackhole list, because the action listed for address 192.168.0.3 in the access database is OK.

Using the access database to override a blackhole list service makes creating your own DNS blackhole list unnecessary for most organization. Generally, organizations shy away from using a blackhole list service because it can block mail from a friendly site. Combining the access database with the blackhole service gives you the simplicity of the blackhole service and the flexibility of directly controlling which sites you communicate with. In addition, if the blackhole service does not list a site that you think should be blacklisted, you can blacklist a site using the access database as described in Recipe Recipe 6.1.

See Also

Recipe 6.4 and Recipe 6.5 provide further examples of using a blackhole list. Recipe 6.1 and Recipe 6.2 provide additional information about using the access database for spam control. For more about the access database in general, see Chapter 3. The sendmail book covers the dnsbl feature in Section 7.2.1, enhdnsbl in Section 7.2.2, and the access_db feature in 7.5. The Anti-Spam Configuration Control section of the cf/README file covers these topics.

6.7. Filtering Local Mail with procmail

Problem

You want to filter mail with procmail before making deliveries to local users.

Solution

Add the local_procmail feature to the sendmail configuration, placing the FEATURE macro after the OSTYPE macro and before the MAILER(`local') line in the master configuration file. Values for the local mailer are usually set in the OSTYPE file. Carefully review the file for your operating system. Add the local_procmail feature to your master configuration file only if local_procmail is not already included in the OSTYPE file.

Create an /etc/procmailrc file containing the filters you want to apply to local mail.

Build and install the new configuration, as described in Recipe 1.8.

Discussion

The linux.m4 OSTYPE file contains the local_procmail feature because procmail is the local mailer used by default on most Linux systems. On a Linux system, just running a configuration that uses the linux.m4 OSTYPE file is sufficient for this recipe. Other systems are not so easy. For example, assume you have a Solaris 8 system. The solaris8.m4 OSTYPE file uses the local_lmtp feature to set mail.local as the local mailer. To change the local mailer to procmail, override the local_lmtp feature by placing the local_procmail feature in the master configuration file. Here is an example based on the generic-solaris.mc file:

VERSIONID(`Solaris with local_procmail added')
OSTYPE(solaris2)
DOMAIN(generic)
dnl Add the local_procmail feature
FEATURE(`local_procmail')
MAILER(local)
MAILER(smtp)

Because the local_procmail feature occurs after the OSTYPE macro, it overrides the local_lmtp feature defined in the OSTYPE file. The local_procmail feature is enabled once the sendmail.cf file is built, copied to sendmail.cf, and sendmail is restarted.

When the local_procmail feature is used, sendmail passes local mail to procmail for delivery. procmail processes the mail, first using the commands defined in the /etc/procmailrc file and then using the commands defined in the .procmailrc file in the recipient’s home directory. If no rc file is defined, procmail writes the mail to the user’s mailbox unaltered. Note that the user’s .procmailrc file is applied to mail delivered by the local_procmail feature. When local_procmail is used, it is not necessary for the user to call the procmail program from the .forward file as shown in this chapter’s Introduction. All the user needs to do is create a .procmailrc file and it will be applied to the mail. Using procmail as a local mailer allows both the system administrator and the user to filter inbound mail with procmail.

When procmail is used as the local mailer, sendmail runs it with three arguments: -Y, -a, and -d. The -Y argument tells procmail to use the standard Berkeley Unix mailbox format. The -d argument provides procmail with the username of the local recipient who is to receive the mail (in the mail delivery triple this is the user value). The -a argument passes an optional value to procmail that is accessible inside the procmail recipe as the $1 variable; in the mail delivery triple, this is the host value. sendmail only passes a value through -a when either the + detail syntax is used or mail is routed to the local mailer via the mailertable. In the case of the + detail syntax, the detail value is passed. In the case of the mailertable, the input address that was the key to the mailertable entry is the value passed. In all other cases, no value is passed by the -a argument and the $1 variable is unassigned.

Warning

The local_procmail feature has security implications for smrsh and for attempts to limit user mail forwarding. See Recipe 10.6 and Recipe 10.8 for more details.

See Also

Recipe 6.8 provides additional information about procmail. The sendmail book covers .forward in Chapter 13 and the local_procmail feature in Section 4.8.21. See the procmail, procmailrc, procmailex, and procmailsc manpages for more information about filtering mail with procmail.

6.8. Filtering Outbound Mail with procmail

Problem

You want to configure sendmail to filter mail addressed to specific domains using procmail as the mail filtering software.

Solution

Build a mailertable that routes mail bound for specific domains through the procmail mailer.

Create a file in the /etc/procmailrcs directory that defines the specific filtering needed. Multiple filters can be used.

Create a sendmail configuration that enables the mailertable feature and adds procmail to the list of available mailers. Here are the lines that should be added to the sendmail configuration:

dnl Enable support for the mailertable
FEATURE(`mailertable')
dnl Add procmail to the list of available mailers
MAILER(procmail)

Build the sendmail.cf file, copy it to /etc/mail/sendmail.cf, and restart sendmail, as described in Recipe 1.8.

Discussion

The MAILER(procmail) macro adds the procmail mailer definition to the sendmail.cf file. The procmail mailer is not related to the local_procmail feature. A system can use the procmail mailer without using procmail as a local mailer, and procmail can be used as a local mailer without adding the MAILER(procmail) macro to the configuration.

The MAILER(procmail) macro does not add any code to the configuration to use the procmail mailer. You must either add custom sendmail.cf rules to reference the mailer, or route mail through the procmail mailer using the mailertable. Using the mailertable is the easiest and the recommended way to access the mailer. Here we add mailertable entries that invoke procmail:

# cd /etc/mail
# cat >> mailertable
               example.com       procmail:/etc/procmailrcs/spam-filter
               wrotethebook.net  procmail:/etc/procmailrcs/spam-filter
               fake.ora.com      procmail:/etc/procmailrcs/uce-filter
               Ctrl-D
# makemap hash mailertable < mailertable

The example adds three entries to the mailertable that route mail through the procmail mailer. The first field in a mailertable entry is the key against which the recipient address is matched. The second field is the mailer value and the host value that sendmail uses to build the mail delivery triple. In this example, mail with a matching recipient address is routed through the procmail mailer. A few tests of a system running this recipe show this:

# sendmail -bv [email protected]
[email protected]... deliverable: mailer procmail, host /etc/procmailrcs/
spam-filter, user [email protected]
# sendmail -bv [email protected]
[email protected]... deliverable: mailer procmail, host /etc/procmailrcs/
spam-filter, user [email protected]
# sendmail -bv [email protected]
[email protected]... deliverable: mailer procmail, host /etc/procmailrcs/
uce-filter, user [email protected]

When mail is routed to the procmail mailer, the host value ($h) must contain the pathname of the rc-file that procmail should use to filter the mail. In the example above, two different filters, spam-filter and uce-filter, are passed to procmail depending on the destination of the email. sendmail calls procmail from the procmail mailer using the following command:

procmail -Y -m $h $f $u

The -Y flag tells procmail to use the Berkeley Unix mailbox format. The -m flag runs procmail as a general-purpose mail filter. The first argument that follows the -m flag must be the path of the rc-file that contains the procmail filter recipes. sendmail assigns the host value returned by the mailertable lookup to the $h macro, which it then passes to procmail as the first argument after the -m flag. Therefore, the host field of a mailertable entry that uses the procmail mailer must contain the full pathname of an rc-file.

The next two arguments passed to procmail are the envelope sender email address ($f) and the envelope recipient email address ($u). These values are available inside the procmail rc-file as variables $1 and $2, respectively.

Warning

Filtering outbound mail with procmail creates the potential for routing loops. Recipes that delete the mail, return it to the sender, or forward it to a third party are not a problem. However, if the mail is examined and then resent to the original recipient, it will return to sendmail, which will route it to procmail, which will return it to sendmail, which will.... You get the idea. If some of the outbound mail filtered by procmail will be resent to the original recipient, you might need to add custom sendmail.cf code to avoid the loop.

One common technique for avoiding a loop is to add the pseudodomain .PROCMAIL to the recipient address when mail is resent to the original recipient. The pseudodomain ensures that the recipient address no longer matches a value in the mailertable, which breaks the loop. The pseudodomain is added by procmail commands in the rc-file. However, a properly configured rc-file is not the complete solution. .PROCMAIL is not a real domain, so code must be added to the sendmail.cf file to ensure that the pseudodomain is properly handled. The following m4 macros and sendmail.cf code, added to the end of the this recipe’s master configuration file, handle the .PROCMAIL pseudodomain, if one is added by the rc-file:

LOCAL_CONFIG
# Add .PROCMAIL to the pseudo-domain list
CP.PROCMAIL
LOCAL_RULE_0
# Strip .PROCMAIL and send via esmtp
R$+ < @ $+ .PROCMAIL . >        $#esmtp $@ $2 $: $1<@$2>

The LOCAL_CONFIG macro marks the start of code that is to be added to the local information section of the sendmail.cf file. In this example, we add a comment and a C command to the local information section. The C command adds .PROCMAIL to class P. Class P lists pseudodomains that sendmail should not attempt to lookup in the DNS. Adding .PROCMAIL to class P avoids the delays and wasted resources that occur when sendmail looks up a domain name that does not exist.

The LOCAL_RULE_0 macro marks the start of sendmail.cf code that is added to ruleset 0—more commonly called the parse ruleset. Specifically, the code that follows the LOCAL_RULE_0 macro is added to the ParseLocal ruleset, which is a hook into the parse ruleset where locally defined rules are added.[7] The parse ruleset rewrites the delivery address to a mail delivery triple.

The code that follows the LOCAL_RULE_0 macro in the example is a comment and a rewrite rule. The R command matches input addresses of the form user @ domain .PROCMAIL, and rewrites those addresses into a mail delivery triple where the mailer is esmtp, the host value is domain, and the user value is user @ domain. After rebuilding the configuration with the new master configuration file, running a sendmail -bv test shows the impact of this rewrite rule:

# sendmail -bv [email protected]
[email protected]... deliverable: mailer esmtp, host example.com, user 
[email protected]

See Also

Recipe 6.7 provides additional information about procmail. The sendmail book covers LOCAL_CONFIG in Section 4.3.3.1 and LOCAL_RULE_0 in 4.3.3.2. See the procmail, procmailrc, procmailex, and procmailsc manpages for more information about filtering mail with procmail. Recipe 5.1 explains the mailertable and how it is used to route mail to any special purpose mailer.

6.9. Invoking Special Header Processing

Problem

You need to add customized header checks to the sendmail configuration.

Solution

Append your custom header processing to the end of the master configuration file using a LOCAL_CONFIG macro and a LOCAL_RULESETS macro. The LOCAL_CONFIG macro adds lines to the local information section of the sendmail.cf file, and, therefore, is used to define any macros, classes, or databases used by your customer header process. Use the LOCAL_RULESET macro to add your custom ruleset to the sendmail.cf file. The Discussion section provides an example of both of these macros.

Build the sendmail.cf file, copy it to /etc/mail/sendmail.cf, and restart sendmail, as described in Recipe 1.8.

Discussion

The knecht.mc file, which comes with the sendmail distribution, contains a variety of examples that illustrate different aspects of sendmail configuration. The following sample custom header check is taken from the knecht.mc file:

LOCAL_CONFIG
#
#  Names that won't be allowed in a To: line (local-part and domains)
#
C{RejectToLocalparts}   friend you
C{RejectToDomains}      public.com

LOCAL_RULESETS
HTo: $>CheckTo

SCheckTo
R$={RejectToLocalparts}@$*      $#error $: "553 Header error"
R$*@$={RejectToDomains}         $#error $: "553 Header error"

Custom header processing requires sendmail.cf code in addition to the normal m4 configuration. The LOCAL_CONFIG macro marks the beginning of lines that are added directly to the local information section of the sendmail.cf file. In the example, the two C lines that follow the LOCAL_CONFIG macro define two classes and load those classes with some values.

The LOCAL_RULESET macro indicates that a locally defined ruleset follows. The first line in the example that follows LOCAL_RULESET is the header command that calls the custom ruleset:

HTo: $>CheckTo

This H command calls the ruleset CheckTo whenever a To: header arrives in a mail stream from a remote system. The $> syntax is the standard way that rulesets are called from rewrite rules and header definitions.

The ruleset itself begins with an S command that defines a ruleset name CheckTo. The ruleset contains two rewrite rules. The first rule matches any To: header containing an address with a username found in the $={RejectToLocalparts} class. In the example, that would be any mail addressed to the username friend or the username you. The mail addressed to either of these usernames is rejected with the error message “553 Header error.”

The second rewrite rule matches any To: header that addresses mail to a hostname found in the $={RejectToDomains} class. In the example, the class contains only the hostname public.com. The mail addressed to public.com is rejected with the error message “553 Header error.”

The CheckTo ruleset is easily tested with sendmail -bt:

# sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> CheckTo [email protected]
CheckTo            input: friend @ wrotethebook . com
CheckTo          returns: $# error $: "553 Header error"
> CheckTo [email protected]
CheckTo            input: craig @ public . com
CheckTo          returns: $# error $: "553 Header error"
> CheckTo [email protected]
CheckTo            input: craig @ wrotethebook . com
CheckTo          returns: craig @ wrotethebook . com
> /quit

The ruleset is called and passed the contents of a sample To: header. Note that the ruleset is passed the contents of the header without the header name. This replicates the way that the ruleset will be called during an actual run. In all three tests, the CheckTo ruleset works as expected—the username friend and the hostname public.com are rejected but the address [email protected] passes through the ruleset unscathed.

The CheckTo ruleset is a simplified example. Implementing a customer header processing ruleset that would be effective for fighting spam would be much more complex. However, the same H command syntax for calling a custom header ruleset, the same LOCAL_CONFIG macro, and the same LOCAL_RULESET macro used in this example would implement any custom header processing. Before you create a custom header process inside sendmail to battle spam, evaluate the alternatives, such as filtering the mail with a MILTER or procmail, and make sure your approach is the simplest and most effective to implement and maintain.

See Also

Recipe 6.10 also uses an example from knecht.mc. Recipe 6.7 and Recipe 6.8 cover procmail and Recipe 6.12 covers MILTER, which are alternatives for processing headers that should be evaluated before you write custom sendmail.cf rulesets. The sendmail book covers the LOCAL_RULESETS macro in Section 4.3.3.5 and the LOCAL_CONFIG macro in Section 4.3.3.1. See TCP/IP Network Administration, Third Edition, by Craig Hunt (O’Reilly), and Linux Sendmail Administration, by Craig Hunt (Sybex), for additional information about the sendmail.cf commands.

6.10. Using Regular Expressions in sendmail

Problem

Special configuration is required for sendmail to use regular expressions to search for patterns in addresses or headers.

Solution

Run the sendmail -d0.1 command. The “Compiled with:” line output by the command should contain MAP_REGEX. If it does not, recompile sendmail as described in Recipe 1.4.

Add custom code to the end of the master configuration file. Add the K command that defines the regular expression to the local information section of the sendmail.cf file using the LOCAL_CONFIG macro, and use a LOCAL_RULESETS macro to add a custom ruleset to access the regular expression. The Discussion section provides an example of how these commands are used.

Build the sendmail.cf file, copy it to /etc/mail/sendmail.cf, and restart sendmail, as shown in Recipe 1.8.

Discussion

Regular expressions are defined using the sendmail.cf K command, which is the same command used to define a database. The regular expression is then accessed from within the configuration in the same manner as a normal database. The following example taken from the knecht.mc file, illustrates how a regular expression is defined and used:

LOCAL_CONFIG
#
#  Regular expression to reject:
#    * numeric-only localparts from aol.com and msn.com
#    * localparts starting with a digit from juno.com
#
Kcheckaddress regex -a@MATCH
   ^([0-9]+<@(aol|msn).com|[0-9][^<]*<@juno.com).?>

LOCAL_RULESETS
SLocal_check_mail
# check address against various regex checks
R$*                             $: $>Parse0 $>3 $1
R$+                             $: $(checkaddress $1 $)
R@MATCH                         $#error $: "553 Header error"

First, the LOCAL_CONFIG macro is added to the m4 master configuration file. The LOCAL_CONFIG macro marks the start of code that is to be added to the local information section of the sendmail.cf file. The K command that defines the regular expression follows this macro. The syntax of the K command is:

Kname type arguments

where K is the command, name is the internal name used to access the database defined by this command, type is the database type, and the arguments define the database being used. The arguments have the format:

flags description

where the flags define options used by the database and description identifies the database being used. The description, in most cases, is a path to an external database, either a local database or a map accessible through a database server. For a regular expression, however, the description is the definition of the regular expression against which input data is matched. The K command in the example is:

Kcheckaddress regex -a@MATCH
   ^([0-9]+<@(aol|msn).com|[0-9][^<]*<@juno.com).?>

In this example:

  • K is the command.

  • checkaddress is the internal name.

  • regex is the type.

  • -a@MATCH is a flag that tells sendmail to return the value @MATCH when a match is found.

  • ^([0-9]+<@(aol|msn).com|[0-9][^<]*<@juno.com).?> is a regular expression. This is a basic regular expression that could be used with tools such as egrep and awk. This regular expression matches email addresses from aol.com, msn.com, and juno.com that contain numeric usernames.

The K command defines the regular expression, but a rewrite rule is needed to use it. The LOCAL_RULESETS macro is used to insert a custom ruleset into the sendmail.cf file. At the heart of the sample Local_check_mail ruleset are three R commands:

R$*                             $: $>Parse0 $>3 $1
R$+                             $: $(checkaddress $1 $)
R@MATCH                         $#error $: "553 Header error"

The address passed to the Local_check_mail ruleset is first processed through ruleset 3 (also called the canonify ruleset), and the result of that process is then passed through the Parse0 ruleset. Note that both of these rulesets are called by the first rewrite command. This processing puts the address into its canonical form. The address is then pattern matched against the checkaddress regular expression by the second rewrite rule. If it matches the regular expression, the address is replaced by the string @MATCH. The third rewrite rule checks to see if the workspace contains that string. If it does, a header error is returned.

A few tests show how the regular expression and the ruleset work:

# sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> Local_check_mail [email protected]
Local_check_mail   input: 123 @ aol . com
canonify           input: 123 @ aol . com
Canonify2          input: 123 < @ aol . com >
Canonify2        returns: 123 < @ aol . com . >
canonify         returns: 123 < @ aol . com . >
Parse0             input: 123 < @ aol . com . >
Parse0           returns: 123 < @ aol . com . >
Local_check_mail returns: $# error $: "553 Header error"
> Local_check_mail [email protected]
Local_check_mail   input: win @ aol . com
canonify           input: win @ aol . com
Canonify2          input: win < @ aol . com >
Canonify2        returns: win < @ aol . com . >
canonify         returns: win < @ aol . com . >
Parse0             input: win < @ aol . com . >
Parse0           returns: win < @ aol . com . >
Local_check_mail returns: win < @ aol . com . >
 > /quit

The first test passes the address [email protected] to the Local_check_mail ruleset. This address should match the checkaddress regular expression. The error returned by the Local_check_mail ruleset shows that it does. The second test is run to show that valid addresses from aol.com do not generate the error.

This example, taken from the knecht.mc file, is not a recommendation that you filter out numeric aol.com addresses. It is an example of how a regular expression is defined and used. The LOCAL_CONFIG macro, the LOCAL_RULESET macro, and the syntax of the K command are the same for the custom regular expressions and rulesets that you create as they are for this simple example.

See Also

Recipe 6.9 provides additional information that is helpful in understanding this recipe. See Chapter 1 for a description of compiling sendmail. The sendmail book covers the LOCAL_CONFIG macro in Section 4.3.3.1, LOCAL_RULESETS in Section 4.3.3.5, and the regex map type in Section 23.7.20. The O’Reilly book Mastering Regular Expressions provides in-depth coverage of regular expressions. See TCP/IP Network Administration, Third Edition, by Craig Hunt (O’Reilly), and Linux Sendmail Administration, by Craig Hunt (Sybex), for additional information about the sendmail.cf commands.

6.11. Identifying Local Problem Users

Problem

Spammers hide their true identities. You want to provide as much information as possible to track down spammers that use your system.

Solution

Run the auth service (identd) to provide account information that cannot be hidden by masquerading or other email techniques.

Discussion

The IDENT protocol is defined in RFC 1413, Identification Protocol. The protocol provides a means for determining the identity of the user who initiated a network connection. The identd daemon implements the IDENT protocol on Unix systems. Run identd to provide additional information to remote system administrators to aid them in tracking down the cause of problems. In the context of sendmail, this information might help them track down a spammer, if one sets up shop on your system. For example, assume a user on a system running identd tries to perpetrate a forgery by issuing the SMTP EHLO command using a false hostname:

ehlo www.ora.com
250-rodent.wrotethebook.com Hello IDENT:r+9Gemj2wip8fAJDU8kDZlyUiReTZjYc@chef.
wrotethebook.com [192.168.0.8], pleased to meet you

When the remote system, in this case rodent.wrotethebook.com, responds to the EHLO command, it ignores the forged www.ora.com hostname. Instead it says “hello” to the host it finds at the connection address 192.168.0.8. It responds with the hostname associated with that address, which is chef.wrotethebook.com, and the identification information provided by the identd service running on chef. This information is propagated in the mail in a Received: header, as shown below:

Received: from www.ora.com
  (IDENT:r+9Gemj2wip8fAJDU8kDZlyUiReTZjYc@chef [192.168.0.8])
   by rodent.wrotethebook.com (8.12.9/8.12.9) with ESMTP id gB4N6T301540
   for <[email protected]>; Wed, 4 Dec 2002 18:06:40 -0500

The information provided by the identd service running on the host at 192.168.0.8 identifies the user who sent the mail. The string provided by identd, r+9Gemj2wip8fAJDU8kDZlyUiReTZjYc in the example, is not a simple username. In this case, the identd information is encrypted.

identd monitors port 113. When identd is running, the remote server can request information about any TCP connections from your server to the remote server by sending the source and destination port pair to the identification server. identd then responds by sending either the requested information associated with the connection or an error. This information allows remote mail servers to put a real username on the Received: header in incoming email. People who abuse the mail system do not like to have their real usernames known. Providing their names to their victims makes it hard for them to stay in business. Unfortunately, many firewalls block port 113 because the security people fear that too much information is given out by the identd service. This fear is unfounded when the identd information is encrypted, as it is in this example. However, many security administrators prefer to play it safe, so they block the port. If it is blocked at your firewall, you might not be able to use identd.

The IDENT protocol is also known by the service name auth, as this grep of /etc/services shows:

$ grep ^auth /etc/services
auth    113/tcp    ident   # User Verification

Most sendmail administrators prefer to call the service ident or identd to avoid confusing it with the ESMTP AUTH keyword, which is discussed in Chapter 7. Additionally, identd is not an authentication tool—it is an auditing tool. Real spammers, who control their own systems, can put anything they want in an identd response, so the response cannot be trusted for real authentication. You, however, are not a spammer. You run identd to provide additional audit trail information to track down users who abuse your system.

Many Unix systems run identd on-demand from inetd or xinetd. The following line added to inetd.conf would implement Recipe Recipe 6.1 on a system using inetd and an on-demand identd service:

auth stream tcp nowait nobody /usr/sbin/in.identd in.identd -t120

This, of course, is just an example. You would need to customize the program pathname and the command-line arguments to fit your system and your needs. You should also check the identd manpage for options that prevent the user from disabling identd.

Some other Unix systems run identd as part of the system startup process. Our sample Red Hat Linux system is an example. A chkconfig command adds identd to the boot process, and a service command starts identd immediately:

# chkconfig --list identd
identd          0:off   1:off   2:off   3:off   4:off   5:off   6:off
# chkconfig --level 35 identd on
# chkconfig --list identd
identd          0:off   1:off   2:off   3:on    4:off   5:on    6:off
# service identd start
Generating ident key:                                      [  OK  ]
Starting identd:                                           [  OK  ]

The first chkconfig command shows that identd is not included in the boot process on this sample Linux system. The second chkconfig command adds it to the startup process for run levels 3 and 5—the run levels associated with networked, multiuser operation on most Linux systems. The final chkconfig command shows the effect of this change. Of course, there is no reason to reboot the system just to start identd, so the service command is used to run the identification service immediately.

This is the first time that identd has been started on this server. Notice the first line of output from the service command. It tells us that a key is being generated for identd. This key is used to encrypt the information sent to the remote system. The administrators of the remote system cannot decrypt the information because they do not have the key. If they suspect a problem, they must send you the encrypted string, which you can then decrypt using the /etc/identd.key file and the idecrypt command. The information from the identd server is encrypted for security reasons. Security people dislike identd because it exposes information about systems and users that can be misused by spammers and intruders. Encrypting the identd response allows you to run the identification daemon without any significant security risks.

For example, the Received: header shown earlier in this section displays the 32 character, BASE64 encoded string r+9Gemj2wip8fAJDU8kDZlyUiReTZjYc that the remote system received from our sample system in response to the IDENT query. This does not provide any information that can be exploited by a spammer or an intruder, but it can be used by you to obtain information about the local user who sent the mail. When the remote system administrator contacts you with a problem report, obtain the 32-byte string, enclose it in square brackets, and decode it with the idecrypt command, as shown:

# idecrypt
               [r+9Gemj2wip8fAJDU8kDZlyUiReTZjYc]
Wed Dec  4 17:00:24 2002 500 192.168.0.8 1029 192.168.0.3 25
Ctrl-D

The decoded string provides:

  • The date and time the connection was made

  • The UID of the user who initiated the connection (500 in this example)

  • The IP address of the source of the connection (192.168.0.8)

  • The source port (1029)

  • The destination IP address (192.168.0.3)

  • The destination port of the connection (25, which is the SMTP port)

All of this information is useful in tracking who is abusing your system. However, identd does have major limitations. It only returns a useful UID if the user actually logs into your system. If it is being misused in some other way, the information provided might not be useful. Additionally, running identd adds some processing overhead to each piece of mail. As with most things, identd has both pluses and minuses.

On our sample Red Hat Linux system, the identd service is preconfigured in the /etc/identd.conf file. Additionally, the identd service can be configured from the command line using command-line options. On a Red Hat Linux system, the identd command-line options used during startup are defined as values for the IDENTDOPTS variable in the /etc/sysconfig/identd file. See the identd manpage for specifics on the identd.conf configuration commands and the command-line options.

See Also

See the manpages for identd, inetd.conf, chkconfig, and the service command.

6.12. Using MILTER

Problem

You have installed an external mail filtering tool that complies with the Sendmail Mail Filter API. You now need to configure sendmail to make use of that external mail filter.

Solution

Run the sendmail -d0.1 command. The “Compiled with:” line output by the command should contain MILTER. If it does not, add MILTER support by adding the following line to the site.config.m4 file:

APPENDDEF(`confENVDEF', `-DMILTER')

Recompile sendmail as described in Chapter 1, in Recipe 1.3 through Recipe 1.7.

Add an INPUT_MAIL_FILTER macro to the sendmail configuration that identifies the external mail filter. At a minimum, the INPUT_MAIL_FILTER macro must define the internal name of the filter and the socket specification required by the filter. Refer to the documentation that comes with the MILTER to find the recommended settings. As an example, the following line could be added to the sendmail configuration to use the vbsfilter MILTER available from http://aeschi.ch.eu.org/milter/:

INPUT_MAIL_FILTER(`sample', `S=local:/var/run/vbsfilter.sock')

Rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail, as described in Recipe 1.8.

Discussion

Before an external program can be used by sendmail, it must be located, downloaded, installed, and properly configured. The introduction to this chapter points to a few web sites where you can start your search for useful MILTERs. Because of the complexity of filtering for spam and scanning for viruses, and because of the constantly changing nature of the threats, configuring a MILTER can be much more challenging than configuring sendmail to use the MILTER. Read the MILTER documentation carefully so that you understand exactly what INPUT_MAIL_FILTER arguments are needed for sendmail to interface with the external filter.

The sample sendmail configuration in the Solution section uses an INPUT_MAIL_FILTER macro recommended by the documentation for the mail filter vbsfilter. The vbsfilter program identifies various dangerous executable attachments and renames them with the .txt extension so that they will not be automatically executed by the end user’s system. The socket defined in the INPUT_MAIL_FILTER macro must match the socket used by the MILTER. For vbsfilter, this is accomplished by running the MILTER with a -p argument that tells vbsfilter which socket to use. Given the INPUT_MAIL_FILTER macro shown in the Solution section, vbsfilter would be started with the following command:

# vbsfilter -p S=local:/var/run/vbsfilter.sock

The vbsfilter is a good one to start with because it does not require much configuration. So is the sample MILTER provided in the libmilter/README file that comes with the sendmail distribution. The sample mail filter doesn’t do any useful filtering, but it is easy to test and useful for determining that your sendmail system is properly configured and capable of interfacing with an external filter. Many filters are so complex that debugging the MILTER at the same time you are debugging sendmail can be overwhelming. Use a simple filter to debug sendmail before interfacing it to a complex filter.

See Also

Introduction to this chapter provides more information about MILTERs. The sendmail book covers MILTER in Section 7.6. The libmilter/README file also covers this topic, as do the files in libmilter/docs.

6.13. Bypassing Spam Checks

Problem

Your sendmail is configured to block incoming junk mail, and you have been asked to allow junk mail through when it is addressed to specific recipients.

Solution

Add an entry to the /etc/mail/access text file for each recipient who should be allowed to receive junk mail. Use the tag Spam: and the recipient address to create the key field of the entry. Use the keyword FRIEND as the return value for each entry. Run makemap to build a hash type database from the text file.

Create a sendmail configuration containing the access_db feature and the delay_checks feature with the optional friend argument. Make sure that the access_db FEATURE macro precedes the delay_checks FEATURE macro in the configuration. Here are the lines that would be added to the sendmail configuration:

dnl Use the access database
FEATURE(`access_db')
dnl Check for spam friends before rejecting the mail
FEATURE(`delay_checks', `friend')

Rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail, as described in Recipe 1.8.

Discussion

Someone on your system—the postmaster, a security expert, a developer writing mail filters—might need to receive junk mail that is normally blocked by sendmail. The delay_checks feature allows this by changing the order in which spam checks are applied. The delay_checks feature allows the envelope recipient address to be checked before the envelope sender address or the connection address, which, in turn, makes it possible for mail addressed to specific recipients to bypass the other two checks. To use the delay_checks feature in this way, it must be invoked with the friend argument, as shown in the Solution section.

The specific recipients allowed to receive junk mail are defined in the access database using the Spam: tag and the FRIEND return value. Here is an example access database:

Connect:example.com                  REJECT
Spam:[email protected]            FRIEND
Spam:[email protected]     FRIEND

Given the sendmail configuration described in the Solution section, this access database rejects mail from example.com unless it is addressed to [email protected] or to [email protected].

See Also

Recipe 6.14 provides a related example. Chapter 3 and the Introduction to this chapter provide more information about the access database. The sendmail book covers the access database in Section 7.5 and the delay_checks feature in Section 7.5.6. The Delay all checks section of the cf/README file also covers this topic.

6.14. Enabling Spam Checks on a Per-User Basis

Problem

You have been asked to create a sendmail configuration that applies checks only when the mail is addressed to selected recipients.

Solution

Add an entry to the /etc/mail/access text file for each recipient whose mail must pass all checks before it is delivered. Use the tag Spam: and the recipient address to create the key field of the entry. Use the keyword HATER as the return value for each entry. Run makemap to build a hash type database from the text file.

Create a sendmail configuration containing the access_db feature and the delay_checks feature with the optional hater argument. Make sure that the access_db FEATURE macro precedes the delay_checks FEATURE macro in the configuration. Here are the lines that would be added to the sendmail configuration:

dnl Use the access database
FEATURE(`access_db')
dnl Apply all checks to spam hater mail
FEATURE(`delay_checks', `hater')

Rebuild the sendmail.cf file, copy the new sendmail.cf file to /etc/mail, and restart sendmail, as described in Recipe 1.8.

Discussion

The delay_checks feature changes the order in which checks are applied by first checking the envelope recipient address. When the delay_checks feature is invoked with the hater argument, as shown in the Solution section, the envelope recipient address must be found in the access database, and it must return the value HATER before the envelope sender address or the connection address are checked. If the envelope sender address is not found in the access database or does not return the value HATER, the check of the envelope sender address performed by check_mail, and the check of the connection address performed by check_relay, are bypassed.

To apply the check_mail and check_relay checks to a recipient’s mail, the specific recipients must be defined in the access database using the Spam: tag and the HATER return value. Here are example entries:

Connect:example.com                  REJECT
Spam:[email protected]            HATER
Spam:[email protected]          HATER

Using this recipe’s sendmail configuration, this access database will reject mail from example.com when it is addressed to [email protected] or to [email protected]. Other users are allowed to receive mail from example.com.

See Also

Recipe 6.13 provides a related example. Chapter 3 and Introduction to this chapter provide more information about the access database. The sendmail book covers the access database in Section 7.5 and the delay_checks feature in Section 7.5.6. The Delay all checks section of the cf/README file also covers this topic.



[1] Purists rail against opt-out schemes, but they can work if genuinely implemented.

[2] Chapter 5 provides additional details about DSN codes and lists the SMTP code keywords. Also see RFC 2821.

[3] The optional access database tags are covered in more detail in Chapter 3.

[4] See http://spamassassin.org/ for information on the SpamAssassin program.

[5] This assumes the service switch file maps host lookups to DNS. See Chapter 5 for information on the service switch file.

[6] Alternatively, the enhdnsbl feature can be used.

[7] The ParseLocal ruleset is also known as ruleset 98.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.15.15