Next: Local Account Verification, Previous: Sending Rate, Up: Tutorial [Contents][Index]
Greylisting is a simple method of defending against the spam
proposed by Evan Harris. In few words, it consists in recording the
‘sender IP’-‘sender email’-‘recipient email’ triplet of
mail transactions. Each time the unknown triplet is seen, the
corresponding message is rejected with the tempfail
code. If the
mail is legitimate, this will make the originating server retry
the delivery later, until the destination eventually accepts it. If,
however, the mail is a spam, it will probably never be retried, so
the users will not be bothered by it. Even if the spammer will retry
the delivery, the greylisting period will give spam-detection
systems, such as DNSBLs, enough time to detect and blacklist it,
so by the time the destination host starts accepting emails from this
triplet, it will already be blocked by other means.
You will find the detailed description of the method in The Next Step in the Spam Control War: Greylisting, the original whitepaper by Evan Harris.
The mailfromd
implementation of greylisting is based on
greylist
function. The function takes two arguments:
the key
, identifying the greylisting triplet, and the
interval
. The function looks up the key in the greylisting
database. If such a key is not found, a new entry is created for it
and the function returns true
. If the key is
found, greylist
returns false
, if it was inserted to the
database more than interval
seconds ago, and true
otherwise.
In other words, from the point of view of the greylisting algorithm, the
function returns true
when the message delivery should be
blocked. Thus, the simplest implementation of the algorithm would be:
prog envrcpt do if greylist("${client_addr}-$f-${rcpt_addr}", interval("1 hour")) tempfail 451 4.7.1 "You are greylisted" fi done
However, the message returned by this example, is not informative
enough. In particular, it does not tell when the message will be
accepted. To help you produce more informative messages, greylist
function stores the number of seconds left to the end of the
greylisting period in the global variable
greylist_seconds_left
, so the above example could be enhanced
as follows:
prog envrcpt do set gltime interval("1 hour") if greylist("${client_addr}-$f-${rcpt_addr}", gltime) if greylist_seconds_left = gltime tempfail 451 4.7.1 "You are greylisted for %gltime seconds" else tempfail 451 4.7.1 "Still greylisted for %greylist_seconds_left seconds" fi fi done
In real life you will have to avoid greylisting some messages, in particular those coming from the ‘<>’ address and from the IP addresses in your relayed domain. It can easily be done using the techniques described in previous sections and is left as an exercise to the reader.
Mailfromd
provides two implementations of greylisting
primitives, which differ in the information stored in the database.
The one described above is called traditional. It keeps in the
database the time when the greylisting was activated for the given
key, so the greylisting
function uses its second argument
(interval
) and the current timestamp to decide whether the key
is still greylisted.
The second implementation is called by the name of its inventor
Con Tassios. This implementation stores in the database the
time when the greylisting period is set to expire, computed by the
greylist
when it is first called for the given key, using the
formula ‘current_timestamp + interval’. Subsequent calls to
greylist
compare the current timestamp with the one stored in
the database and ignore their second argument. This implementation is
enabled by one of the following pragmas:
#pragma greylist con-tassios
or
#pragma greylist ct
When Con Tassios implementation is used, yet another function
becomes available. The function is_greylisted
(see is_greylisted) returns
‘True’ if its argument is greylisted and ‘False’ otherwise.
It can be used to check for the greylisting status without actually
updating the database:
if is_greylisted("${client_addr}-$f-${rcpt_addr}") … fi
One special case is whitelisting, which is often used
together with greylisting. To implement it, mailfromd
provides the function dbmap
, which takes two mandatory arguments:
dbmap(file, key)
(it also allows an optional third
argument, see dbmap, for more information on it). The first argument is
the name of the DBM file where to search for the key, the second one
is the key to be searched. Assuming you keep your whitelist database
in file /var/run/whitelist.db, a more practical example will be:
prog envrcpt do set gltime interval("1 hour") if not ($f = "" or relayed(hostname(${client_addr})) or dbmap("/var/run/whitelist.db", ${client_addr})) if greylist("${client_addr}-$f-${rcpt_addr}", gltime) if greylist_seconds_left = gltime tempfail 451 4.7.1 "You are greylisted for %gltime seconds" else tempfail 451 4.7.1 "Still greylisted for %greylist_seconds_left seconds" fi fi fi done
Next: Local Account Verification, Previous: Sending Rate, Up: Tutorial [Contents][Index]