Recipient Validation is absolutely necessary in mail gateways. Some reasons are :
Recipient Validation is the set of data and procedures needed to identify the class of the recipient being handled (valid or protected recipient, spamtrap, …) and the action to be taken, eventually different from normal transparent actions (ACCEPT, REJECT, DISCARD, …), which may depend on data other than simply the recipient email address (e.g., SMTP client IP address, …).
Why check recipient access inside the filter ? sendmail access database isn't enough ? Yes and no !
To check recipient access with ze-filter, enable it at ze-filter.cf file and define all entries at ze-rcpt database.
CHECK_RCPT_ACCESS YES DB_RCPT ze-rcpt.db
This database is used to :
There are two kind of records :
Domain records - These records allow you to configure for which domains you want to check recipient access. Syntax for these entries are as follows :
CheckRcptDomain:KEY VALUE
KEY may be something like domain.com or *.domain.com. The first entry matches only domain.com and the second one matches all subdomains of domain.com.
VALUE may be one of :
Recipient records - These records allow you to configure access for each recipient.
RcptAccess:RCPT ACTION
RCPT can be a domain name (to define the default action for this domain), a full address or the user part of an address.
ACTION can be one of :
A typical ze-rcpt database looks something like :
# Enable checking recipients for this domain CheckRcptDomain:example.com YES # Define a default value RcptAccess:example.com USER-UNKNOWN # Entries needed by RFCs (don't remove...) RcptAccess:abuse@example.com OK RcptAccess:postmaster@example.com OK # Users in the domain RcptAccess:alice@example.com OK RcptAccess:bob@example.com OK # all@example.com can't receive messages from the "world" RcptAccess:all@example.com KNOWN-NET
# Check recipient access for domain.com ... CheckRcptDomain:domain.com LOCAL # # ... and for all sub domains of this domain CheckRcptDomain:.domain.com LOCAL # # default is "Unknown user" if not defined RcptAccess:domain.com USER-UNKNOWN # # toto exists in domain.com and all sub domains RcptAccess:toto@ OK # # titi exists only in domain.com RcptAccess:titi@domain.com OK # # this is a spamtrap RcptAccess:spam@domain.com SPAMTRAP # # accept messages for everybody only if the connection # comes from a known network RcptAccess:everybody@domain.com KNOWN-NET
# CheckRcptDomain:domain.com YES # # default access is "OK" RcptAccess:domain.com OK # # this is a spamtrap RcptAccess:spam@domain.com SPAMTRAP # # accept messages for everybody only if the connection # comes from a known network RcptAccess:everybody@domain.com KNOWN-NET
CheckRcptDomain:univmed.fr LOCAL CheckRcptDomain:*.univmed.fr LOCAL RcptAccess:univmed.fr USER-UNKNOWN RcptAccess:3pe@aaa.univ.fr OK RcptAccess:7emepcrdt@bbb.univ.fr OK RcptAccess:aad@ OK RcptAccess:aae@aaa.univ.fr OK ...
aad is ok for *.univ.fr, but aae only for aaa.univ.fr
CheckRcptDomain:univ.fr YES CheckRcptDomain:*.univ.fr REJECT RcptAccess:univ.fr USER-UNKNOWN CheckRcptDomain:aaa.univ.fr YES RcptAccess:aaa.univ-mrs.fr USER-UNKNOWN RcptAccess:abac@aaa.univ.fr OK
Here RcptAccess is allways fully qualified
Here are some ideas, which can be combined, to put all you need in place to manage the database of recipients.
If you have a list of valid recipients, say users.txt
, one recipient per line, you can use the mk_rcpt.pl script to build the textual version of ze-rcpt database.
mk_rcpt.pl -d example.com -a USER-UNKNOWN users.txt > ze-rcpt.txt
Use -d option to define your domain name and -a option to define default action for undefined users.
If your mailserver is runs sendmail
, it's enough to dump the list of all valid users. It shall be something like this (but not necessarily) :
#! /bin/sh # begin with an empty file cp /dev/null users.txt # add real users getent passwd | awk -F: '{print $1}' >> users.txt # dump all your aliases for db in /etc/mail/aliases*.db do makemap -u hash $db | awk '{print $1}' >> users.txt done # dump the table of virtual users db=/etc/mail/virtusertable.db makemap -u hash $db | awk '{print $1}' | \ awk -F@ '/@example.com/ {print $1}' >> users.txt
postfix
.
If you want to assign particular attributes to some recipients - other than simply saying that the recipient is a valid one, the simpler way is to use an additional file (named, e.g., users.plus). Put one recipient per line, with its attribute separated by an space :
all intranet john known accounting local ceo domain john.smith spamtrap root reject grey tempfail
ze-rcpt database will be created with :
mk_rcpt.pl -d example.com -a USER-UNKNOWN users.txt users.plus > ze-rcpt.txt
users.txt
and users.plus
files, the one with an attribute will be selected.
As said before, if you run ze-filter on an inbound SMTP gateway, you must do recipient validation, for all your internal mail servers (domains and sub domains), mainly to avoid generating backscatter. One way (but not the only one) to create the recipient database is :
It's possible to use Makefile rules to automate the generation of ze-rcpt database for a bunch of domains, if the names of input files follow the template “domain.action”, where :
“User Unknown”
mk_rcpt.pl
finds a file with file extension plus
and the same domain
part of the input file being handled, it appends its contents to the end of current input file. This is useful, e.g., if you have a fixed number of recipients with special attributes.contrib/rcpt-database
directory of ze-filter distribution.# You need GNU make to process this Makefile .SUFFIXES : .rcpt .unknown .relay .local .domain .friend .known .txt .db RSRC = $(wildcard *.relay) ROBJ := $(RSRC:%.relay=%.rcpt) USRC = $(wildcard *.unknown) UOBJ := $(USRC:%.unknown=%.rcpt) LSRC = $(wildcard *.local) LOBJ := $(LSRC:%.local=%.rcpt) DSRC = $(wildcard *.domain) DOBJ := $(DSRC:%.domain=%.rcpt) KSRC = $(wildcard *.known) KOBJ := $(KSRC:%.known=%.rcpt) OBJ = $(ROBJ) $(LOBJ) $(DOBJ) $(KOBJ) $(UOBJ) .unknown.rcpt : mk_rcpt.pl -a USER-UNKNOWN $< > $@ .relay.rcpt : mk_rcpt.pl -a USER-UNKNOWN $< > $@ .local.rcpt : mk_rcpt.pl -a LOCAL-NET $< > $@ .domain.rcpt : mk_rcpt.pl -a DOMAIN-NET $< > $@ .known.rcpt : mk_rcpt.pl -a KNOWN-NET $< > $@ .txt.db : ze-makemap -m e -m u -b $@ < $< all : ze-rcpt.db ze-rcpt.txt : $(OBJ) @ cat $(OBJ) > ze-rcpt.txt clean : rm -f $(OBJ) ze-rcpt.txt ze-rcpt.db *~
If you're running the filter in an inbound SMTP gateway and you don't have direct access to the whole list of valid users of your domain, it's surely possible to make each internal server dumps its own list of valid addresses, and to aggregate them using the ideas explained above (Makefile rules). You can use wget
or rsync
to collect each list of valid addresses, this is how I do. You can do something like this :
# Using wget to retrieve the list of remote users HOST="math.univ.fr" echo $HOST | awk '{ printf " . %-32s", $0 }' /usr/sbin/ping $HOST 1 > /dev/null if [ "$?" = "0" ] ; then echo " 8-)" wget -q -t 2 --connect-timeout=5 --read-timeout=10 \ -N http://$HOST/mail/$HOST.relay else echo " ;-(" fi # Using rsync to retrieve the list of remote users HOST="phys.univ.fr" echo $HOST | awk '{ printf " . %-32s", $0 }' /usr/sbin/ping $HOST 1 > /dev/null if [ "$?" = "0" ] ; then echo " 8-)" rsync -aq rsync://$HOST/mail/$HOST.relay . else echo " ;-(" fi