This is a small set of Exim configuration changes you can apply to enable automatic signing of outgoing mail and filtering of incoming junk bounces. This makes your system immune to "joe jobs", that is, bounces you receive in response to spam where the spammer put *your* address as the sender. It also prevents you from receiving spam with a null envelope sender. YOU WILL NEED: exim-4.??. There is a bug in exim-4.30 and earlier which means that $message_body contains stale data when multiple messages are received in the same SMTP session. It's been reported to ph10, but until a fix is out you should consider this is something for "playing with" only. HOW IT WORKS: All outgoing messages (apart from bounces) have an extra header added, of the form X-bounce-key: example.net-1;you@example.com;1077198109;fb7e6ffa; (1) (2) (3) (4) (1): a key identifier, typically the ISP's domain plus a number. This allows multiple MTAs to sign the message in transit and not clash with each other. The number allows the signing key to be changed smoothly if needed. (2): the E-mail address to which a bounce may be sent. This header is only valid for messages to that address. (3): the time when the message was sent out. Bounces older than a certain age (I have configured +/- 10 days) are ignored. (4): a 32-bit cryptographic checksum, calculated as a hash over (1), (2), (3) and a secret value We rely on any MTA which sends us a bounce, that is a message with an empty envelope-sender, quoting back the headers of the message in a non-obscured form (e.g. not base64 encoded). A bounce is then considered acceptable if it contains a valid X-bounce-key line somewhere within it; otherwise it is rejected. The X-bounce-key can be indented, it doesn't have to start on the beginning of a line. Unlike VERP/SRS, we do not modify the envelope-sender in any way. This should ensure that very little breaks. The only problem is that you will lose bounces if the remote MTA does not quote back at least the headers of the message it is returning, and auto-responder messages ("I am away on vacation") if they are sent with an empty envelope sender and do not quote the message back. I can live without those; in any case the empty return address is a declaration by the sender that "I do not care if this is delivered successfully or not". The cost is minimal: a hash calculation and extra header on all outgoing mail, and a body scan on incoming bounces (only). Because this is all done within exim's configuration language there is no overhead in shelling out or communicating with another process. This configuration is free. Use, enjoy, but don't blame me (or call me) if you lose mail. Brian Candler 2004-02-19 ########### In the top section, add the following ################## # A unique key for your company, e.g. a domain you own and a serial number # to allow the key to be changed in future BOUNCE_ID = example.com-1 # A genuinely random key. e.g. from # head -c16 /dev/urandom | md5 # If running across multiple mailservers they will all need to share the # same key, and you will need to keep it secret from anyone else. BOUNCE_SECRET = 1d5ded6522fb2a120bbd7293ccaa6672 # You will also need to add the following line to activate filtering: # comment it out until you have been signing outgoing mails for a few days # and are ready to start rejecting unsigned bounces. acl_smtp_data = check_bounce_key # (Note: if you already have acl_smtp_data for some reason, then leave it # alone and *add* the ACL lines below to your existing ACL) ########### In the section 'begin acl', add the following ################## check_bounce_key: deny senders = : condition = ${if ! eq{$recipients_count}{1}{1}} message = Bounces must have only a single recipient deny senders = : ! condition = ${if match \ {$message_body $message_body_end} \ {[xX]-bounce-key:\\s*BOUNCE_ID;${rxquote:${lc:$recipients}};(\\d+);(\\w+)} \ {${if eq {$2} \ {${length_8:${md5:BOUNCE_ID;${lc:$recipients};$1;BOUNCE_SECRET}}} \ {${if <{${sg{${eval:$tod_epoch-$1}}{-}{}}}{864000}{1}}}}}} message = Bounce does not contain a valid X-bounce-key signature accept ########### In the section 'begin transports', modify your existing ########### remote_smtp transport as follows remote_smtp: driver = smtp headers_add = ${if eq{$return_path}{}{}{X-bounce-key: BOUNCE_ID;${lc:$return_path};$tod_epoch;${length_8:${md5:BOUNCE_ID;${lc:$return_path};$tod_epoch;BOUNCE_SECRET}};}} # Note: it's OK for multiple MTA's handling a message to add their own # X-bounce-key headers. With some extra work we could test for # an existing header with the same BOUNCE_ID;$return_path portion to # prevent duplication, but it doesn't really seem worth it. ########### THAT'S IT! ##############