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 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.
Keyword |
Action |
|
Accepts messages from or to the specified address. |
|
Drops any message from or to the specified address. |
|
Issues an error message and drops any mail from or to the specified address. |
|
Rejects the mail with the specified response code and error message. |
|
Adds the |
|
Skips the |
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.
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.
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.
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:
A clearing house for information about MILTERs in general.
A powerful, extensible MILTER that supports virus scanning, deletion of attachments based on name and content, and SpamAssassin processing.[4]
A MILTER that attempts to verify that the sending address is a valid email address. Many spammers do not use valid sender addresses.
A virus scanning MILTER.
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.
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.
Flag |
Meaning |
|
Execute this recipe if the preceding recipe evaluated to true. |
|
This has the same meaning as the |
|
Pass the body of the message on to the destination. This is the default. |
|
Filter the message body. |
|
Create a carbon copy of this mail. |
|
Tests are case sensitive. By default, case is ignored. |
|
Execute this recipe if the execution of the preceding recipe returned an error. |
|
Execute this recipe if the preceding recipe was not executed. |
|
Pass the data through an external filter program. |
|
Filter the message headers. This is the default. |
|
Pass the message header on to the destination. This is the default. |
|
Ignore write errors for this recipe. |
|
Write the mail out without any additional format checks. |
|
Check the exit code of the external filter program. |
|
This is the same meaning as the |
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.*simon@oreilly\.com * !^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
simon@oreilly.com
. 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.
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.
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.
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.
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 - 0400HELO localhost
250 chef.wrotethebook.com Hello IDENT:UWSRv+Jij66J8vALUBVBECbGPVoU8OQe@localhost [127.0.0.1], pleased to meet youMAIL From:<crooks@example.com>
550 5.7.1 <crooks@example.com>... Access deniedMAIL From:<thieves@wrotethebook.net>
550 5.7.1 <thieves@wrotethebook.net>... Invalid mail sourceMAIL From:<junk@fake.ora.com>
250 2.1.0 <junk@fake.ora.com>... Sender okQUIT
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 junk@fake.ora.com
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 junk@fake.ora.com 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.
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.
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.
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.
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 - 0400HELO localhost
250 chef.wrotethebook.com Hello IDENT:UWSRv+Jij66J8vALUBVBECbGPVoU8OQe@localhost [127.0.0.1], pleased to meet youMAIL From:<craig@chef.wrotethebook.com>
250 2.1.0 <craig@chef.wrotethebook.com>... Sender okRCPT To:<crook@example.com>
550 5.7.1 <crook@example.com>... Mail to this site is not allowedQUIT
221 2.0.0 chef.wrotethebook.com closing connection Connection closed by foreign host.
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.
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.
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.
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.
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: DISCARDCtrl-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 - 0500MAIL From:<crooks@example.com>
550 5.7.1 <crooks@example.com>... Access deniedMAIL From:<thieves@wrotethebook.net>
550 5.7.1 <thieves@wrotethebook.net>... Invalid mail sourceQUIT
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.
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.
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.
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.
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.
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.
You need to create your own DNS blackhole list because no external blackhole service provides exactly the listing policy and content you need.
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.
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 - 0400helo rodent.wrotethebook.com
250 chef.wrotethebook.com Hello rodent.wrotethebook.com [192.168.0.3], pleased to meet youMAIL From:<craig@rodent.wrotethebook.com>
550 5.7.1 Rejected: 192.168.0.3 listed at dnsbl.wrotethebook.comQUIT
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.
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).
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.
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.
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 - 0400helo rodent.wrotethebook.com
250 chef.wrotethebook.com Hello rodent.wrotethebook.com [192.168.0.3], pleased to meet youMAIL From:<craig@rodent.wrotethebook.com>
550 5.7.1 Rejected: 192.168.0.3 listed at list.dsbl.orgQUIT
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 OKCtrl-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 - 0400helo rodent.wrotethebook.com
250 chef.wrotethebook.com Hello rodent.wrotethebook.com [192.168.0.3], pleased to meet youMAIL From:<craig@rodent.wrotethebook.com>
250 2.1.0 <craig@rodent.wrotethebook.com>... Sender okQUIT
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.
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.
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.
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.
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.
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.
You want to configure sendmail to filter mail addressed to specific domains using procmail as the mail filtering software.
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.
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-filterCtrl-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 crooks@example.com
crooks@example.com... deliverable: mailer procmail, host /etc/procmailrcs/ spam-filter, user crooks@example.com #sendmail -bv spammers@wrotethebook.net
spammers@wrotethebook.net... deliverable: mailer procmail, host /etc/procmailrcs/ spam-filter, user spammers@wrotethebook.net #sendmail -bv thieves@fake.ora.com
thieves@fake.ora.com... deliverable: mailer procmail, host /etc/procmailrcs/ uce-filter, user thieves@fake.ora.com
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.
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 crooks@example.com.PROCMAIL
crooks@example.com.PROCMAIL... deliverable: mailer esmtp, host example.com, user
crooks@example.com
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.
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.
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 friend@wrotethebook.com
CheckTo input: friend @ wrotethebook . com CheckTo returns: $# error $: "553 Header error" >CheckTo craig@public.com
CheckTo input: craig @ public . com CheckTo returns: $# error $: "553 Header error" >CheckTo craig@wrotethebook.com
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
craig@wrotethebook.com 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.
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.
Special configuration is required for sendmail to use regular expressions to search for patterns in addresses or headers.
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.
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 123@aol.com
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 win@aol.com
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 123@aol.com 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.
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.
Spammers hide their true identities. You want to provide as much information as possible to track down spammers that use your system.
Run the auth
service (identd)
to provide
account information that cannot be
hidden by masquerading or other email techniques.
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 <craig@rodent.wrotethebook.com>; 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 25Ctrl-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 the manpages for identd, inetd.conf, chkconfig, and the service command.
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.
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.
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.
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.
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.
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.
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:uce@wrotethebook.com FRIEND Spam:clark+junk@wrotethebook.com FRIEND
Given the sendmail configuration described in the Solution section, this access database rejects mail from example.com unless it is addressed to uce@wrotethebook.com or to clark+junk@wrotethebook.com.
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.
You have been asked to create a sendmail configuration that applies checks only when the mail is addressed to selected recipients.
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.
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:jay@wrotethebook.com HATER Spam:alana@wrotethebook.com HATER
Using this recipe’s sendmail configuration, this access database will reject mail from example.com when it is addressed to jay@wrotethebook.com or to alana@wrotethebook.com. Other users are allowed to receive mail from example.com.
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.
[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.