Today I've spent some time implementing greylisting on our smtp server continuing my endless fight against UCE (spam). Setting this up is as easy as running "aptitude install greylistd" and adding to the exim.conf:
defer
message = $sender_host_address is not yet authorized to deliver \
mail from <$sender_address> to <$local_part@$domain>. \
Please try later.
log_message = greylisted.
!senders = :
!hosts = : +relay_from_hosts : \
${if exists {/etc/greylistd/whitelist-hosts}\
{/etc/greylistd/whitelist-hosts}{}} : \
${if exists {/var/lib/greylistd/whitelist-hosts}\
{/var/lib/greylistd/whitelist-hosts}{}}
!authenticated = *
!acl = acl_check_spf
domains = +local_domains : +relay_to_domains
verify = recipient/callout=20s,use_sender,defer_ok
condition = ${readsocket{/var/run/greylistd/socket}\
{--grey \
$sender_host_address \
$sender_address \
$local_part@$domain}\
{5s}{}{false}}
But greylisting comes with one drawback that bugs me. It requires senders of legitimate mail to retry after some amount of time. This wouldn't be a problem with sane smtp servers but with potentially misconfigured servers, we can't be sure of it.
Therefore I whitelist a broad range of well known smtp servers for which I assume that they will always send legitimate mail. But maintaining a whitelist is tedious and takes a lot of effort (for postfix p2pwl exists as a solution). That's why I decided to also whitelist hosts for which a SPF check passes. Even though its not yet widely used it reduces the chance to greylist especially big/high traffic smtp servers (I assume that those hosts return a valid SPF record).
Unfortunately exim4 doesn't come with spf enabled in debian etch for various reasons, why it is necessary to do the spf check manually with libmail-spf-query-perl which is available via apt. The upstream example which is included doesn't serve this use case though. So I had to create my own:
acl_check_spf:
accept
message = X-mkce.de-SPF: SPF check succeeded
log_message = [SPF] $sender_host_address is allowed to send mail from ${if def:sender_address_domain {$sender_address_domain}{$sender_helo_name}}.
condition = ${run{/usr/bin/spfquery --ip \"$sender_host_address\" --mail-from \"$sender_address\" --helo \"$sender_helo_name\"}\
{${if eq {$runrc}{0}{yes}{no}}}}
warn
log_message = [SPF] Temporary DNS error while checking SPF record.
condition = ${if eq {$runrc}{5}{yes}{no}}
warn
log_message = [SPF] SPF check negative with ${if eq {$runrc}{1}{fail}{${if eq {$runrc}{2}{softfail}\
{${if eq {$runrc}{3}{neutral}{${if eq {$runrc}{4}{unknown}{${if eq {$runrc}{6}{none}{error}}}}}}}}}}
condition = ${if <={$runrc}{6}{yes}{no}}
warn
log_message = [SPF] Unexpected error in SPF check.
condition = ${if >{$runrc}{6}{yes}{no}}
I'll monitor my logfiles closely the next days, but even after a couple of hours the result looks promising.
May this piece of information help somebody else. :-)