105 lines
5.1 KiB
PHP
105 lines
5.1 KiB
PHP
|
# $Id: acl-greylist-sqlite,v 1.1 2006/06/13 13:56:54 dwmw2 Exp $
|
||
|
|
||
|
GREYDB=/var/spool/exim/db/greylist.db
|
||
|
|
||
|
# ACL for greylisting. Place reason(s) for greylisting into a variable named
|
||
|
# $acl_m_greylistreasons before invoking with 'require acl = greylist_mail'.
|
||
|
# The reasons should be separate lines of text, and will be reported in
|
||
|
# the SMTP rejection message as well as the log message.
|
||
|
#
|
||
|
# When a suspicious mail is seen, we temporarily reject it and wait to see
|
||
|
# if the sender tries again. Most spam robots won't bother. Real mail hosts
|
||
|
# _will_ retry, and we'll accept it the second time. For hosts which are
|
||
|
# observed to retry, we don't bother greylisting again in the future --
|
||
|
# it's obviously pointless. We remember such hosts, or 'known resenders',
|
||
|
# by a tuple of their IP address and the name they used in HELO.
|
||
|
#
|
||
|
# We also include the time of listing for 'known resenders', just in case
|
||
|
# someone wants to expire them after a certain amount of time. So the
|
||
|
# database table for these 'known resenders' looks like this:
|
||
|
#
|
||
|
# CREATE TABLE resenders (
|
||
|
# host TEXT PRIMARY KEY,
|
||
|
# helo TEXT,
|
||
|
# time INTEGER
|
||
|
# );
|
||
|
#
|
||
|
# To remember mail we've rejected, we create an 'identity' from its sender
|
||
|
# and recipient addresses and its Message-ID: header. We don't include the
|
||
|
# sending IP address in the identity, because sometimes the second and
|
||
|
# subsequent attempts may come from a different IP address to the original.
|
||
|
#
|
||
|
# We do record the original IP address and HELO name though, because if
|
||
|
# the message _is_ retried from another machine, it's the _first_ one we
|
||
|
# want to record as a 'known resender'; not just its backup path.
|
||
|
#
|
||
|
# Obviously we record the time too, so the main table of greylisted mail
|
||
|
# looks like this:
|
||
|
#
|
||
|
# CREATE TABLE greylist (
|
||
|
# id TEXT PRIMARY KEY,
|
||
|
# expire INTEGER,
|
||
|
# host TEXT,
|
||
|
# helo TEXT
|
||
|
# );
|
||
|
#
|
||
|
|
||
|
greylist_mail:
|
||
|
# First, accept if it there's absolutely nothing suspicious about it...
|
||
|
accept condition = ${if eq{$acl_m_greylistreasons}{} {1}}
|
||
|
# ... or if it was generated locally or by authenticated clients.
|
||
|
accept hosts = :
|
||
|
accept authenticated = *
|
||
|
|
||
|
# Secondly, there's _absolutely_ no point in greylisting mail from
|
||
|
# hosts which are known to resend their mail. Just accept it.
|
||
|
accept hosts = sqlite;GREYDB SELECT host from resenders \
|
||
|
WHERE helo='${quote_sqlite:$sender_helo_name}' \
|
||
|
AND host='$sender_host_address';
|
||
|
|
||
|
# Generate the mail identity (as described above)
|
||
|
warn set acl_m_greyident = ${hash{20}{62}{$sender_address$recipients$h_message-id:}}
|
||
|
|
||
|
# Attempt to look up this mail in the greylist database. If it's there,
|
||
|
# remember the expiry time for it; we need to make sure they've waited
|
||
|
# long enough.
|
||
|
warn set acl_m_greyexpiry = ${lookup sqlite {GREYDB SELECT expire FROM greylist \
|
||
|
WHERE id='${quote_sqlite:$acl_m_greyident}';}{$value}}
|
||
|
|
||
|
# If the mail isn't already the database, defer it with an appropriate
|
||
|
# message, and add it. Do the addition to the greylist database as a
|
||
|
# hackish side-effect of the log-message, appending 'success' or 'failure'
|
||
|
# to the log-message depending on whether the SQL worked (which it always
|
||
|
# should). This is where the 5 minute timeout is set ($tod_epoch + 300)
|
||
|
# should you wish to change it.
|
||
|
defer condition = ${if eq {$acl_m_greyexpiry}{} {1}}
|
||
|
log_message = Greylisted $h_message-id: for offences: ${sg {$acl_m_greylistreasons}{\n}{,}}:\
|
||
|
${lookup sqlite {GREYDB INSERT INTO greylist \
|
||
|
VALUES ( '$acl_m_greyident', \
|
||
|
'${eval10:$tod_epoch+300}', \
|
||
|
'$sender_host_address', \
|
||
|
'${quote_sqlite:$sender_helo_name}' );}\
|
||
|
{success}{failure}}
|
||
|
message = Your mail was considered suspicious for the following reason(s):\n$acl_m_greylistreasons \
|
||
|
The mail has been greylisted for 5 minutes, after which it should be accepted. \
|
||
|
We apologise for the inconvenience. Your mail system should keep the mail on \
|
||
|
its queue and retry. When that happens, your system will be added to the list \
|
||
|
genuine mail systems, and mail from it should not be greylisted any more. \
|
||
|
In the event of problems, please contact postmaster@$qualify_domain
|
||
|
|
||
|
# If the message was already listed but its time hasn't yet expired, keep rejecting it
|
||
|
defer condition = ${if > {$acl_m_greyexpiry}{$tod_epoch}}
|
||
|
message = Your mail was previously greylisted and the time has not yet expired.\n\
|
||
|
You should wait another ${eval10:$acl_m_greyexpiry-$tod_epoch} seconds.\n\
|
||
|
Reason(s) for greylisting: \n$acl_m_greylistreasons
|
||
|
|
||
|
# The message was listed but it's been more than five minutes. Accept it now and whitelist
|
||
|
# the sending host by its { IP, HELO } so that we don't delay its mail again. The addition
|
||
|
# to the database is again done as a hackish side-effect; this time a side-effect of
|
||
|
# evaluating a condition which comes out as '1' whether the database bit succeeds or not.
|
||
|
accept condition = ${lookup sqlite {GREYDB INSERT INTO resenders \
|
||
|
VALUES ( '$sender_host_address', \
|
||
|
'${quote_sqlite:$sender_helo_name}',
|
||
|
'$tod_epoch' ); }{1}{1}}
|
||
|
|