Anti-UBE FEATUREs in sendmail 8.10/8.11

Last Update 2001-03-28


sendmail 8.10/8.11 overcomes the problems of the standard rulesets in sendmail 8.9.

access map: Tag for the LHS

The LHS of entries in the access map can be tagged with
for connection information, i.e., {client_name} and {client_addr}.
for envelope sender
for envelope recipient
These tags are currently optional, an untagged entry is used for (nearly) all checks to be compatible with previous releases.
Connect:1.2.3			REJECT
Connect:			OK
Connect:relay.domain	RELAY
To:another.domain		RELAY
From:friend.domain			OK
From:some.domain		REJECT
From:friend@some.domain	OK
To:olduser@				REJECT
This gives high flexibility without resorting to multiple maps. Even though the table might be hard to read, it is easy to generate it from simpler descriptions (e.g., different files). This is optional, the default behavior (and map content) is backward compatible (except for some slight enhancements). Since we tag the LHS, we can have `multiple' entries regarding the same `key', because they are distinguished by the tags. A drawback might be a larger map, as can be seen from the example. The entries above will allow connections from the IP number and reject everything else in the net 1.2.3. It allows relaying from relay.domain and to another.domain.

Order of calls

As explained the new rulesets for SMTP connections are called in the order: check_relay (host name and host address when a client connects), check_mail for the MAIL command, and check_rcpt for the RCPT command. Hence it is per default not possible to override rejections in check_relay by the sender address, or rejections in check_mail for individual recipients. The new FEATURE(`delay_checks') changes the order by modifying the names of some rulesets. This allows you to:
  1. accept mail from specific (envelope) senders, even though the server rejects connections from some clients,
  2. accept mail for specific recipients, e.g., postmaster, even though the mail would be rejected by other means.

By using FEATURE(`delay_checks') the rulesets check_mail and check_relay will not be called when a client connects or issues a MAIL command, respectively. Instead, check_rcpt is the first check_* ruleset to be called. After it completes, check_mail and check_relay will be called in order. Moreover, one argument can be specified for the delay_checks feature:

FEATURE(`delay_checks', `friend')
enable spamfriend test
FEATURE(`delay_checks', `hater')
enable spamhater test
If such an argument (at most one) is given, the recipient will be looked up in the access map (using the tag To:). If the argument is friend, then the other rulesets will be skipped if the recipient address is found and has RHS SPAMFRIEND, i.e., the default is to apply the usual rulesets unless an entry in the access map is specified. If the argument is hater, then the other rulesets will be applied if the recipient address is found and has RHS SPAMHATER, i.e., the default is to skip the usual rulesets unless an entry in the access map is specified.

This allows for simple exceptions from the tests, e.g. by activating the spamfriend option and having

in the access map, mail to abuse@localdomain will get through. It is also possible to specify a full address or an address with +detail:	SPAMFRIEND
To:me+abuse@		SPAMFRIEND

Enhanced Header Checks

The possibilities for header checks of 8.9 have been enhanced in 8.10. The format:
HSubject: $>+CheckSubject
does not strip comments (in parentheses) before passing the value of the header field to CheckSubject. A default ruleset for headers which don't have a specific ruleset defined for them can be given by:
H*: $>CheckHdr
After all of the headers are read, the check_eoh ruleset will be called for any final header-related checks. The ruleset is called with the number of headers and the size of all of the headers in bytes separated by $|. One example usage is to reject messages which do not have a Message-Id: header is given in the cf/README file.

A very first version of my header check rulesets is available for 8.10.

Add Headers

Esp. in combination with the new macro map headers can be added to a message.
H?${macro}?hname: htemplate
The htemplate is macro-expanded before insertion into the message. The header will be in the message if {macro} is set, which can be done by using any of the normal methods, as well as with the macro storage map in a ruleset. If one of these headers is in the input it is reflected to the output regardless of these flags or macros.


HMessage-Id: $>CheckMessageId
Kstorage macro
H?${MyMacro}?X-MsgId: ${MyMacro}

R$< $+ @ $+  >	$@ OK
R$+				$: $(storage {MyMacro} $@ Illegal Message-Id $) $1
Note: the syntax has been changed in beta 12, it was without the question marks before:
H${macro}hname: htemplate

More check_* Rulesets

The new rulesets check_etrn, check_vrfy, and check_expn receive the parameter of the corresponding SMTP command as argument. They can accept or reject the SMTP command.


Multiple DNS based black lists

sendmail 8.10 can make use of multiple DNS based black lists, i.e., FEATURE(`dnsbl') can be included several times with different arguments. For example:

Unresolvable client address

Some people want to accept only mail from systems which have a valid PTR entry in DNS. In many cases this will reject also legitimate mail hence it is not a feature provided by sendmail. However, if you really want to do this, here is how:
R$*		$: $&{client_resolve}
RTEMP		$#error $@ 4.7.1 $: "450 Access temporarily denied. Cannot resolve PTR record for " $&{client_addr}
RFORGED		$#error $@ 4.7.1 $: "450 Access temporarily denied. IP name possibly forged " $&{client_name}
RFAIL		$#error $@ 4.7.1 $: "450 Access temporarily denied. IP name lookup failed " $&{client_name}
You can put these rules in any of the Local_check_* rulesets depending on your needs.

Maps useful for anti-UBE

The new arith map can be used for something like scoring; initialize a macro {SpamScore} with 0 (using the macro map) and add a score each time you find something "suspicious" in the envelope or header. Then check it in the check_eoh ruleset and accept or reject the e-mail accordingly. A simple binary system (Yes/No) can of course also be implemented: set a macro {Friend} to YES if the envelope from address or the address of the connecting system can be found in the access map with an appropriate RHS.

Macros useful for anti-UBE

{client_resolve} holds the result of the resolve call for {client_name}: OK, FAIL, FORGED, TEMP.

{currHeader} contains the current header value as a quoted string. If {hdrlen} is greater than or equal MAXNAME the header has been truncated.

[(links)] [Hints] [Avoiding UBE] [cf/README] [New]
Copyright © Claus Aßmann Please send comments to: <ca at>
Disclaimer: the information provided may be inaccurate or outdated or incomplete. Please contact me if you find an error.