Exim4 with DKIM and conditional greylisting

Exim4 in recent Debian GNU/Linux Lenny — Debian testing as of this writing — is quite easy to configure to use DKIM. The original implementation, DomainKeys, you’ve probably heard of. DKIM is the recent incarnation of DKIM and the one you’d want to implement today.

Building DKIM aware Exim4

First, you’ll want to build a version of Exim that supports DKIM. Building is the most difficult step, but it’s not as challenging as it once was. You’ll need to install version 1.0.19 of libdkim. Today, you can fetch it from Lenny and it installs cleanly on Etch.

(The bonus conditional greylisting information is at the end of the post.)

# apt-get install libdkim-dev

Next, you’ll need to build your own custom Exim4 daemon. The packager has made this relatively easy to do. First, you’ll need to download the sources. Add the relevant source line to your /etc/apt/sources.list.

deb-src http://ftp.us.debian.org/debian lenny main contrib non-free

Then, install the sources.

# cd /usr/src
# apt-get install build-essential debuild devscripts
# apt-get source exim4
... unpacks stuff ...
# cd exim4-4.69/
# fakeroot debian/rules unpack-configs

Once you have unpacked, you can copy the heavy config file, then make the two changes below. Where in the file they go doesn’t especially matter.

# cp EDITME.exim4-heavy EDITME.exim4-custom
# echo "EXPERIMENTAL_DKIM=yes" >> EDITME.exim4-custom
# echo "LDFLAGS += -ldkim" >> EDITME.exim4-custom
# fakeroot debian/rules pack-configs

It’s possible to use some other name, but the custom name works by default and requires no additional steps. I had no success getting an alternate name to work instead.

It’s also necessary to modify the debian/rules file. (Not strictly, as you’ll see in the file. You can always redefine extradaemonpackages instead.) Simply change extradaemonpackages to be defined as:

extradaemonpackages=exim4-daemon-heavy exim4-daemon-custom

Finally, a small patch is necessary so Exim4 will build against the most recent libdkim.

echo "80_libdkim_patch" >> debian/patches/00list

Then, a patch file must be made. The following is simply borrowed from an existing patch to be applied. After the last line, the actual patch will be added. The actual patch is by Russell Stuart in the Debian BTS #486437.

#! /bin/sh /usr/share/dpatch/dpatch-run
## 70_remove_exim-users_references.dpatch by Marc Haber <mh+debian-packages@zugschlus.de>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.
 
@DPATCH@
wget 'http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=5;filename=99_libdkim_1.0.19.dpatch;att=1;bug=486437' -O - | \
  cat >> 80_libdkim_patch.dpatch

Once that’s complete, it’s time to build.

# debuild -uc -us

When that’s complete, assuming it succeeds, you’ll have:

# ls ../*.deb | grep exim4
../exim4_4.69-7_all.deb
../exim4-base_4.69-7_amd64.deb
../exim4-config_4.69-7_all.deb
../exim4-daemon-custom_4.69-7_amd64.deb
../exim4-daemon-custom-dbg_4.69-7_amd64.deb
../exim4-daemon-heavy_4.69-7_amd64.deb
../exim4-daemon-heavy-dbg_4.69-7_amd64.deb
../exim4-daemon-light_4.69-7_amd64.deb
../exim4-daemon-light-dbg_4.69-7_amd64.deb
../exim4-dbg_4.69-7_amd64.deb
../exim4-dev_4.69-7_amd64.deb
../eximon4_4.69-7_amd64.deb

Configuring DKIM

If you are doing this on Debian Etch, be advised that 4.69 has configuration changes. You will have to merge changes to your configuration from 4.63 into 4.69. The templating for update-exim4.conf.conf is different internally. What’s more, the init script will generate an error, but it still works fine.

If the build installs and you’re not upgrading from the Etch version of Exim4, configuration is the easy part. You’ll want to add a few lines to your split configuration. First in /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp:

  dkim_selector = dkim
  dkim_domain = DKIM_DOMAIN
  dkim_private_key = DKIM_PRIVATE_KEY
  dkim_strict = 0
  dkim_canon = relaxed

Finally, in /etc/exim4/conf.d/main/01_exim4-local_config:

DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/exim4/dkim/${lc:${domain:$h_from:}}.priv
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}

A new directory, dkim, is necessary under /etc/exim4. Obviously, you’ll want to keep the permissions restrictive on the private key.

ls /etc/exim4/dkim/
edseek.com.priv  edseek.com.pub

Last, create a DKIM key for your particular domain.

# Generate RSA key in priv.key:
openssl genrsa -out domain.com.priv 1024
 
# Show public part of it:
openssl rsa -in domain.com.priv -pubout > domain.com.pub
# chmod 640 /etc/exim4/dkim/domain.com.priv
# chmod 750 /etc/exim4/dkim
# chown :Debian-exim /etc/exim4/dkim/domain.com.priv
# chown :Debian-exim /etc/exim4/dkim

Upon success, the following will appear in the mainlog:

2008-11-30 11:48:03 xXxxX-0007qF-Qw Message signed with DKIM: DKIM-Signature
: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=edseek.com; s=dkim; h=From:To:Subject:Date:References:
        In-Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding:
        Message-Id; bh=x3Xo0CzQf4k2H7iKUOLK/XXnzDkh6dJ1XXuCjLE3yf0=; b=B
        zLwxxCqGkCt48ruEI8EUQQ39eC4Yn7zJQw1ZXX/IqKZOM9QrS5w3RPn+ccpzdS6f
        J2ZfP6xhPzyxopb8bpG8J8jI4MvpJc77Q2EsoCch+rfz9wkF1WhHUn0qbQyC+ojb
        J57m6Xk0eaxvZdWdaLgBKDZVpApGuodbPmi+6EwWLI=

Last, DNS must be updated with the public portion of the key, so other mail hosts can actually verify the signature you’ve gone to such lengths to produce. While that’s an entirely different exercise, the djbdns record creator may be of use, since DKIM TXT records must instead use the custom record type of tinydns.

The one for edseek.com is the following:

# custom record with dkim RSA public key
:dkim._domainkey.edseek.com:16:\341k=rsa;\040p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKAstwIMRr7VxDlrqx3qek+36dPJsYsAYgRbHektkMR2VL+X0Jyp51gEL5Ed+yMXTlaOlLlxdbyicEP2E4LS++\057dmuJg3RvLE1iwfKbXW7iiAV7r+6XObeDnodFrz1N0uNjdZDJvc3\057RYoFXHtK+pS4q8kXnwaqNUul4b97dvJQIDAQAB:86400

Greylisting based upon DNSBL hits

Finally, it’s possible to greylist only hosts that appear on chosen DNSBLs. I prefer this approach to greylisting everyone (oops, have to whitelist 1,000 Google and Yahoo IP ranges) and it’s still highly effective.

First, install greylistd. Do not let it modify your configuration. At least in Debian Etch, it will eat your split configuration, forcing you to edit it or Exim4 won’t start.

# apt-get intstall greylistd

Now, create acl/22_exim4-config_selective_dnsbl_greylist_deny:

acl_check_skip_greylist:
        deny
        dnslists    = dul.dnsbl.sorbs.net:zen.spamhaus.org \
                        :list.dsbl.org:dnsbl.njabl.org
        # Accept everything else
        accept

Add the magic for greylistd, including a call to the above ACL, near the top of /etc/exim4/conf.d/acl/30_exim4-config_check_rcpt:

acl_check_rcpt:
... stuff ...
  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_local_deny_exceptions
    !acl           = acl_check_skip_greylist
    domains        = +local_domains : +relay_to_domains
    verify         = recipient/callout=20s,use_sender,defer_ok
    condition      = ${readsocket{/var/run/greylistd/socket}\
                                 {--grey \
                                  ${mask:$sender_host_address/24} \
                                  $sender_address \
                                  $local_part@$domain}\
                                 {5s}{}{false}}

 # Deny if blacklisted by greylist
 deny
   message = $sender_host_address is blacklisted from delivering \
                     mail from <$sender_address> to <$local_part@$domain>.
   log_message = blacklisted.
   !senders        = :
   !authenticated = *
   verify         = recipient/callout=20s,use_sender,defer_ok
   condition      = ${readsocket{/var/run/greylistd/socket}\
                                 {--black \
                                  $sender_host_address \
                                  $sender_address \
                                  $local_part@$domain}\
                                 {5s}{}{false}}
... tons more stuff ...

Any hosts on the DNSBLs above will be greylisted. All other mail hosts will not be subjected to the greylist. Combined with dspam, I find it highly effective.

References

2 Comments

  1. Posted 2/19/2009 at 2:30 pm | Permalink

    Thanks for the info! I’ve used this info to build exim+dkim several times now.

    You might want to mention that dpatch is required to unpack the configs. The warning message you get without it isn’t terribly intuitive.

  2. Chris How
    Posted 12/11/2010 at 6:04 am | Permalink

    Thanks from me too.

    Just used this again to reinstall the latest security update to exim.

    Top banana!

Post a Comment

Your email is never shared. Required fields are marked *

*
*