Using a Database in the check_* Rulesets with an Error Message

Last Update 2003-02-22

Further Enhanced Version to use a Database in check_mail/check_relay

Using a map lookup has the advantage that you don't need to restart sendmail when you change the entries in the database. Moreover, if the file gets large (as it may happen since UCEs become nearly ubiquitous) the match should be faster. This enhanced version uses a common database for check_mail3 and check_relay3 . For the latter, you need a patch for sendmail 8.8.5 to make this work.

The new version of check_mail can also make more rigorous validations of the supplied FROM address. These rules can be activated by define(`_CHECK_FROM_') if you use check_mail3 from the check.tar file. At least the rule removes an extraneous dot at the end of the address since this would circumvent the check for valid domains.

The database (map) contains entries for well-known spammers in the form:

spammer@address.domain "Error-Code Error-Text"
spammer@address.domain SPAMMER
and for junk domains in the form
junk.domain "Error-Code Error-Text"
junk.domain JUNK
and for IP numbers which are not allowed to connect to your mail server:
D.X.Y.Z "Error-Code Error-Text"
C.X.Y "Error-Code Error-Text"
B.X "Error-Code Error-Text"
A "Error-Code Error-Text"
where the lines refer to full IP addresses, class B, C, or A nets. The right hand side of the map can also be the string JUNK, in which case a standard error code and text will be used, just as for SPAMMER .

An example for entries in the map is:	"501 is a dummy domain -- check your configuration" "550 This domain is banned." "550 Go away, Spamford." "550 Honey, you're a spammer, go away." "550 You're a real lamer, go away."
205.199.212	"No access for you, Spamford."
The last entry has no error code, since check_relay3 refuses access always with 550 Access denied and logs the error string.

The map can be used in as:

Kjunk dbm -a@JUNK /etc/mail/junk
(you may choose another database type and another location). This is now used in the ruleset as follows:
# don't check these
R<$*@$=w>	$@ ok			shortcut
# idea from Steven Schultz
R<>		$: <$n @ $(dequote "" $&{client_name} $) >
# mark address
#R$*		$:<@>$1
# is the syntax ok (uses <> and no dot at the end?)
#R<@><$*@$*$~.>	$:<$1@$2$3>
# mark still there: error...
#R<@>$*		$#error $@ 5.1.8 $: 550 illegal MAIL FROM $1,
# if we don't to the above: remove at least the dot...
R<$*@$*.>	<$1@$2>
R$*		$: $>3 $1			canonify
R$-		$@ ok				local host
# no host without a . in the FQHN ?
# if you get local e-mail from hosts without full domains,
# put a hash in front of the next rule
R$*<@$->$*	$#error $@ 5.1.8 $: 550 invalid host name $2, check your configuration.
# lookup IP address (reverse mapping available?)
# R$*<@[$-.$-.$-.$-]>$*	$: $1 < @ $[ [ $2.$3.$4.$5 ] $] > $6 
# copy the result of the lookup
R$*		$:$1 $| $1
# now remove the dot
R$* $| $*<@$*.>$*	$: $1 $| $2<@$3>$4
# and check the database
R$* $| $*<@$*>$*	$: $1 $| $>junk $2<@$3>
# match: return given error code (rhs of map)
R$* $| $*<@$*@JUNK>$*	$#error $@ 5.7.1 $: $3
# restore original value (after canonicalization by ruleset 3)
# this is only required if you want to enable the last rule
# R$* $| $*		$: $1
# no DNS entry? this is dangerous!
# R$*<@$*$~P>$*	$#error $@ 4.1.8 $: 451 unresolvable host name $2$3, check your setup.

# check for junk domain/spammers
# lookup domain in database
R$*<@$+>		$:$1<@$(junk $2$)>
# exists? return
R$*<@JUNK@JUNK>		$@$1<@ "550 mail from your spam domain not accepted." @JUNK>
R$*<@$*@JUNK>		$@$1<@$2@JUNK>
# lookup address in database
R$*<@$+>		$:$1<@$(junk $1@$2 $:$2$)>
# exists? return
R$*<@SPAMMER@JUNK>	$@$1<@ "550 mail from your spam address not accepted." @JUNK>
R$*<@$*@JUNK>		$@$1<@$2@JUNK>
# remove one subdomain, try again
R$*<@$-.$-.$+>		$: $>junk $1<@$3.$4>
# check IP
R$+ $| $+	$: $1 $| $>junkIP $2
R$+ $| JUNK@JUNK	$#error $@ 5.7.1 $: "550 access from your IP address denied."
R$+ $| $*@JUNK	$#error $@ 5.7.1 $: $2
# check hostname
R$+ $| $+	$: $>junk <@$1>
R$*<@JUNK@JUNK>$*	$#error $@ 5.7.1 $: "550 access from your hostname denied."
R$*<@$*@JUNK>$*	$#error $@ 5.7.1 $: $2

# lookup IP in database
# full IP address
R$-.$-.$-.$-	$: $(junk $1.$2.$3.$4 $)
# class C net
R$-.$-.$-.$-	$: $(junk $1.$2.$3 $: $1.$2.$3.$4 $)
# class B net
R$-.$-.$-.$-	$: $(junk $1.$2 $: $1.$2.$3.$4 $)
# class A net
R$-.$-.$-.$-	$: $(junk $1 $: $1.$2.$3.$4 $)
It is also available as HACK(check_mail3.m4) and HACK(check_relay3.m4) in the check.tar file for use in a .mc file.

Accept some Addresses without Check

The check_mail2 and check_mail3 versions in the check.tar file have a "backdoor" to accept some addresses without checking them. This can be activated with:
Default for the database is:
dbm -o -a@ACCEPT /etc/mail/accept
Other values can be given as argument, e.g.,
define(`_ACCEPT_SOME_',`hash -a@ACCEPT /etc/AcceptIt')
Entries must have the form:
user@address	OK
domain	OK

Use Regular Expressions

Jan Krüger provides a patch to use regular expressions in check_mail3 has now a hook to incorporate this check. It can be enabled with: HACK(checkregex) For further information see Jan Krüger's page.
[(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.