Something you don't want to do when using Spamhaus's DQS with Exim

For reasons outside the scope of this entry, we recently switched from Spamhaus 's traditional public DNS (what is now called the 'public mirrors') to an account with their Data Query Service. The DQS data can still be queried via DNS, which presents a problem: DNS queries have no way to carry any sort of access key with them. Spamhaus has solved this problem by embedding your unique access key in the zone name you must use. Rather than querying, say, zen.spamhaus.org, you query '<key>.zen.dq.spamhaus.net'. Because your DQS key is tied to your account and your account has query limits, you don't want to spread your DQS key around for other people to pick up and use.

We use the Exim mailer (which is more of a mailer construction kit out of the box). Exim has a variety of convenient features for using DNS (block) lists . One of them is that when Exim finds an entry in a DNS blocklist in an ACL , it sets some (Exim) variables that you can use later in various contexts, such as creating log messages. To more or less quote from the Exim documentation on (string) expansion variables :

$dnslist_domain
$dnslist_matched
$dnslist_text
$dnslist_value

When a DNS (black) list lookup succeeds, these variables are set to contain the following data from the lookup: the list’s domain name, the key that was looked up, the contents of any associated TXT record, and the value from the main A record. [...]

To make life easier on yourself, it's conventional to use these variables (among others) in things like SMTP error messages and headers that you add to messages:

deny hosts = !+local_networks
     message = $sender_host_address is listed \
               at $dnslist_domain: $dnslist_text
     dnslists = rbl-plus.mail-abuse.example

warn dnslists = weird.example
     add_header = X-Us-DNSBL: listed in $dnslist_domain

However, if you're using Spamhaus DQS, using $dnslist_domain as these examples do is dangerous. The DNS list domain will be the full domain, and that full domain will include your DQS access key, which you will thus be exposing in message headers and SMTP error messages. You probably don't want to do that.

(Certainly it feels like a bad practice to leak a theoretically confidential value into the world, even if the odds are that no one is going to pick it up and abuse it.)

You have two options. The first option is to simply hard code some appropriate name for the list instead of using $dnslist_domain. However, this only works if you're using a single DNS list in each ACL condition, instead of something where you check multiple DNS blocklists at once (with 'dnslists = a.example : b.example : c.example'). It's also a bit annoying to have to repeat yourself.

(This is what I did to our Exim configuration when I realized the problem.)

The second option is that Exim has a comprehensive string expansion language , so determined people can manipulate $dnslist_domain to detect that it contains your DQS key and remove it. The brute force way would be to use ${sg} (from expansion items ) to replace your key with nothing, something like (this is untested):

${sg{$dnslist_domain}{<DQS key>}{}}

You could probably wrap this up in an Exim macro , call it ' DNSLIST_NAME ', and then write ACLs as, say:

deny hosts = !+local_networks
     message = $sender_host_address is listed \
               at DNSLIST_NAME
     dnslists = rbl-plus.mail-abuse.example

(Because we're using ${sg}, we won't change the name of a DNSBL domain that doesn't contain the DQS key.)

This isn't terrible and it does cope with a single Exim ACL condition that checks multiple DNS blocklists.