If anyone has been paying attention over the last couple weeks I've been trying to put together a BATV (Bounce Address Tag Validation) configuration on my server. BATV prevents bounces from being returned to your server that did not originate from it. Every time there is a virus outbreak I get a load of messages returned to me from viruses that forged my return address. Even worse is the number of support calls that have to be answered from users who want to know why they are getting messages returned that they did not send.
The examples in the spec.txt file assume tagging will only be performed for select users. While this may be a little less heavy handed. That is, the return address will only be tagged for users that send through the server exclusively, and not those who use third-party services to deliver messages with their own address. The vast majority of my users only send mail using my server. So I will sign all outbound addresses from my domains, and reject any bounces that are returned without a signature. So there is a rare chance that a valid bounce could be turned away, but with the number of false bounces I see every day, the positives outweigh the negatives in my case. What follows are the changes made to the default Exim configuration file. I will make notes where I feel explanations are needed. Note: Somewhere near the top of the configuration file add this macro definition. Change "privatekey" to something unique for your server. # Define the server-wide private key to be used in BATV signatures. BATVKEY = privatekey Note: Place the following in the "acl_check_rcpt" section. First bounces need to be limited to having only one recipient, so that later in the DATA ACL the $recipients variable will only have one address. Then check the validity of any signed address from empty senders. This will only deny the recipient address if the signature has expired or the hash is invalid. Unsigned addresses will pass. One thing of which to make special note, the way the $return_path is modified when sending messages is caseful. The hash check will fail if case of the local part is not preserved. # Bounces must only be returned to one recipient. deny message = bounce messages must contain only one RCPT senders = : condition = ${if >{$rcpt_count}{1}} # Empty sender (a bounce) to prvs address, check signature. deny message = invalid or expired BATV signature senders = : control = caseful_local_part condition = ${prvscheck [EMAIL PROTECTED] !condition = $prvscheck_result control = caselower_local_part Note: This next bit can go in the existing "acl_check_data" section, or you can create a predata check and place it there. I'm running mine after the DATA has been completed, because I do not know for sure how other MTAs will react to an error response directly after the DATA command. # If this message is a true bounce (i.e. made it to DATA), and not just a # callout, require that the recipient not be unsigned. deny message = bounce messages must be returned to a BATV signed address senders = : !condition = ${prvscheck {$recipients}{BATVKEY}{true}} Note: Place this router before existing "dnslookup" router. It may also be useful create another domain list for a BATV signing blacklist. I've found a few servers that will reject sender addresses that contain either an '=' or a '/', both of which occur in signed return-paths. # This router will be used for senders with addresses at any of the domains # defined by "domainlist local_domains". Messages matching this condition # will be sent to the external_smtp_batv transport to have their # return-path signed with a BATV key. Other messages that do not have a local # domain will fall through to the next router. dnslookup_batv: driver = dnslookup condition = ${if match_domain{$sender_address_domain}{+local_domains}} domains = ! +local_domains transport = external_smtp_batv ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 Note: This router also needs to go very early on in the list. I put mine just before the "system_aliases" router so it could still do its work on the decoded addresses. # This router removes the BATV signature to return the original recipient # address. batv_redirect: driver = redirect data = ${prvscheck [EMAIL PROTECTED] Note: Finally the transport that signs outbound messages. # This transport is used for delivering messages over SMTP connections, # while adding BATV signing to the return-path. external_smtp_batv: driver = smtp return_path = ${prvs {$return_path}{BATVKEY}} -- ## List details at http://www.exim.org/mailman/listinfo/exim-users ## Exim details at http://www.exim.org/ ## Please use the Wiki with this list - http://www.exim.org/eximwiki/