Table of Contents

Recipient Validation / Recipient Access

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

Recipient Database - ze-rcpt

This database is used to :

  1. define for which target domains recipient validation will be done
  2. define default access for target domains
  3. define access for each recipient inside target domains.

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

Some Examples

# 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

Recipient Database Management Recipes

Here are some ideas, which can be combined, to put all you need in place to manage the database of recipients.

Create the ze-rcpt.txt database (text file version) from a list of valid 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.

Getting the list of valid recipients

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) :

to dump the list of valid recipients
#! /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
You can write a similar script to get the list of valid recipients, if you're using postfix.

Assigning attributes to some recipients

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
If an user is found twice or both in users.txt and users.plus files, the one with an attribute will be selected.

Recipient Validation on a SMTP gateway

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 :

  1. Retrieve the list of valid users for all internal mail servers
  2. Create one access list text file (ze-rcpt format) for each internal mail server
  3. Concatenate all access list files in a single one.
  4. You may use cron to periodically update your recipient database.

Using a Makefile to automate database management

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 :

  1. If 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.
  2. You'll find these scripts inside 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 *~

Getting valid recipient lists from internal mail servers

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 :

to retrieve distant list of valid users
# 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