Add greylisting

This commit is contained in:
David Woodhouse 2007-02-07 12:18:24 +00:00
parent 02080aee53
commit dcfda4841d
4 changed files with 180 additions and 3 deletions

104
exim-greylist.conf.inc Normal file
View File

@ -0,0 +1,104 @@
# $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}}

View File

@ -12,7 +12,7 @@
Summary: The exim mail transfer agent
Name: exim
Version: 4.66
Release: 1%{?dist}
Release: 2%{?dist}
License: GPL
Url: http://www.exim.org/
Group: System Environment/Daemons
@ -33,6 +33,10 @@ Source11: exim.pam
%if 0%{?buildsa}
Source13: http://marc.merlins.org/linux/exim/files/sa-exim-4.2.tar.gz
%endif
Source20: exim-greylist.conf.inc
Source21: mk-greylist-db.sql
Source22: greylist-tidy.sh
Patch4: exim-rhl.patch
Patch6: exim-4.50-config.patch
Patch8: exim-4.24-libdir.patch
@ -45,6 +49,7 @@ Patch18: exim-4.62-dlopen-localscan.patch
Patch19: exim-4.63-procmail.patch
Patch20: exim-4.63-allow-filter.patch
Patch21: exim-4.63-localhost-is-local.patch
Patch22: exim-4.66-greylist-conf.patch
Requires: /etc/aliases
BuildRequires: db4-devel openssl-devel openldap-devel pam-devel
@ -105,9 +110,34 @@ as follows:
deny message = This message contains malware ($malware_name)
malware = *
For further details of Exim content scanning, see chapter 40 of the Exim
For further details of Exim content scanning, see chapter 41 of the Exim
specification:
http://www.exim.org/exim-html-4.62/doc/html/spec_html/ch40.html#SECTscanvirus
http://www.exim.org/exim-html-%{version}/doc/html/spec_html/ch41.html
%package greylist
Summary: Example configuration for greylisting using Exim
Group: System Environment/Daemons
Requires: sqlite exim %{_sysconfdir}/cron.daily
%description greylist
This package contains a simple example of how to do greylisting in Exim's
ACL configuration. It contains a cron job to remove old entries from the
greylisting database, and an ACL subroutine which needs to be included
from the main exim.conf file.
To enable greylisting, install this package and then uncomment the lines
in Exim's configuration /etc/exim.conf which enable it. You need to
uncomment at least two lines -- the '.include' directive which includes
the new ACL subroutine, and the line which invokes the new subroutine.
By default, this implementation only greylists mails which appears
'suspicious' in some way. During normal processing of the ACLs we collect
a list of 'offended' which it's committed, which may include having
SpamAssassin points, lacking a Message-ID: header, coming from a blacklisted
host, etc. There are examples of these in the default configuration file,
mostly commented out. These should be sufficient for you to you trigger
greylisting for whatever 'offences' you can dream of, or even to make
greylisting unconditional.
%prep
%setup -q
@ -129,6 +159,7 @@ cp exim_monitor/EDITME Local/eximon.conf
%patch19 -p1 -b .procmail
%patch20 -p1 -b .filter
%patch21 -p1 -b .localhost
%patch22 -p1 -b .grey
%build
%ifnarch s390 s390x
@ -243,6 +274,12 @@ ln -sf clamd $RPM_BUILD_ROOT/usr/sbin/clamd.exim
mkdir -p $RPM_BUILD_ROOT%{_var}/run/clamd.exim
%endif
# Set up the greylist subpackage
install -m644 %{SOURCE20} $RPM_BUILD_ROOT/%_sysconfdir/exim/exim-greylist.conf.inc
install -m644 %{SOURCE21} $RPM_BUILD_ROOT/%_sysconfdir/exim/mk-greylist-db.sql
mkdir -p $RPM_BUILD_ROOT/%_sysconfdir/cron.daily
install -m755 %{SOURCE22} $RPM_BUILD_ROOT/%_sysconfdir/cron.daily/greylist-tidy.sh
touch $RPM_BUILD_ROOT/%_var/spool/exim/db/greylist.db
%clean
rm -rf $RPM_BUILD_ROOT
@ -309,6 +346,13 @@ if [ "$1" -ge "1" ]; then
fi
fi
%post greylist
if [ ! -r %{_var}/spool/exim/db/greylist.db ]; then
sqlite3 %{_var}/spool/exim/db/greylist.db < %{_sysconfdir}/exim/mk-greylist-db.sql
chown exim.exim %{_var}/spool/exim/db/greylist.db
chmod 0660 %{_var}/spool/exim/db/greylist.db
fi
%files
%defattr(-,root,root)
%attr(4755,root,root) %{_sbindir}/exim
@ -394,7 +438,16 @@ test "$1" = 0 || %{_initrddir}/clamd.exim condrestart >/dev/null || :
%attr(0750,exim,exim) %dir %{_var}/run/clamd.exim
%endif
%files greylist
%config %{_sysconfdir}/exim/exim-greylist.conf.inc
%ghost %{_var}/spool/exim/db/greylist.db
%{_sysconfdir}/exim/mk-greylist-db.sql
%{_sysconfdir}/cron.daily/greylist-tidy.sh
%changelog
* Wed Feb 7 2007 David Woodhouse <dwmw2@infradead.org> 4.66-2
- Add example of greylisting implementation in Exim ACLs
* Tue Feb 6 2007 David Woodhouse <dwmw2@infradead.org> 4.66-1
- Update to 4.66
- Add dovecot authenticator

8
greylist-tidy.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
if [ -r /var/spool/exim/db/greylist.db ]; then
sqlite /var/spool/exim/db/greylist.db <<EOF
.timeout 5000
DELETE FROM greylist WHERE expire < $((`date +%s` - 604800));
EOF
fi

12
mk-greylist-db.sql Normal file
View File

@ -0,0 +1,12 @@
CREATE TABLE resenders (
host TEXT PRIMARY KEY,
helo TEXT,
time INTEGER
);
CREATE TABLE greylist (
id TEXT PRIMARY KEY,
expire INTEGER,
host TEXT,
helo TEXT
);