Permanent Links

Poll

What should be the topic for the next Impossibly Stupid poll?

A Town Square Poll Space

Tech Corner

See Also

[ICO]NameLast modifiedSizeDescription

[PARENTDIR]Parent Directory  -  
[TXT]README.html2018-01-25 13:58 6.3K 
[   ]info.json2018-01-22 15:07 35  
[   ]tags=auto2015-03-26 18:30 0  
[   ]tags=meta2015-03-26 18:30 0  
[   ]tags=ragtag2015-03-26 18:31 0  
[   ]zone2exim.zip2018-01-22 15:10 11K 

Exim configuration using DNS zone files

A few years ago I wrote about how I use special anti-spam measures in order to limit the amount of junk that gets directed to my inbox. The long and short of it is that, behind the scenes, I set up special-use subdomains that handle the grunt work for my throwaway email addresses. One common way they’re constructed is to be time-limited, so they should be used only until the end of a given year or a given month or whatever. Since it was just the end of the year, it was once again time for me to set up a new batch of subdomains to start receiving messages for 2018.

Without automation, this can be a laborious process, especially if you use the same technique to manage contacts for multiple different sites. You have to first create the names themselves by whatever scheme you use (e.g., if you wanted wordy monthly addresses you might go with january-2018.example.com, february-2018.example.com, etc.). Then you have to enter them into some sort of software that can be queried by people on the Internet (e.g., a web form that serves as the front end for your registrar’s DNS servers). Then you have add them to your email server’s configuration files, and/or give them some kind of special entry for handling by a configuration management tool.

And that’s essentially what I’ve manually done in the past. It’s not really that bad once you get into the flow after doing it a couple times, but in the spirit of automation, I went looking for the best ways to shave off some of those minutes. And, of course, it all starts with a bit of Retro Avant-Garde thinking.

There are many ways to establish a name for a server (perhaps too many; an issue I will explore in future articles on automation). The old-school way, though, is using the venerable zone file format. Being a text file, it’s easy enough to edit directly, but there also exists some parsing software that makes it even easier to use for the purposes of automation. After some searching and testing of the alternatives, I settled with this Ruby library to handle the heavy lifting. Based on that, the (partial) Ruby script to create the example entries given above would be something like:

Date::MONTHNAMES[1..12].each do |month|
	hostname = month.downcase + "-2018"
	zf.mx << { :class => 'IN', :name => hostname, :pri => 10, :host => 'smtp1.example.net.' }
end

As always, the needs of your scheme or policies may differ slightly (e.g., you may want to use Time.now.year + 1 instead of hardcoding it, but then you need to be sure your use case only involves running the script in the previous year). It may make more sense to just have a simple script that creates a single ad-hoc entry, and then set up a cron job to run it at the start of each month to supply it with the valid time period. However you populate it, what’s really important here is that you have this zone file as your point of reference for future use.

The second step is pushing out this information to your DNS provider (assuming you don’t run your own servers for that). Some of them say they provide APIs to edit DNS records, or will accept zone files directly. Don’t believe them! I’ve been testing the DNS services of a number of new registrars over the past year, and I’ve been really disappointed in the automation services they have all provided. More on this in a future post. Suffice it to say I’m still looking for a better registrar to use for my domains (and, yes, impossiblystupid.com is expiring soon, so let me know if you have any recommendations!).

The third step is configuring your email server so that it will deliver messages sent to these new subdomains. As I have mentioned before, I decided to go with Exim as my mail handler. And it’s running on a Debian distribution, which may or may not differ from your installation. For me, what it boils down to is the fact that I have I one particular file, /etc/exim4/domains.virtual that needs to contain a list of every domain that my server accepts messages for. Now that we know we can reference our zone files as the one true source of valid MX records, there’s no need to retype or copy-paste the entries into the Exim config file. I just run this (partial) script to extract the valid servers:

ARGV.each do |file|
	zf = Zonefile.from_file(file)
	
	zf.mx.each do |rr|
		puts zf.hostName(rr[:name])
	end
end

Note that in the case of MX records, there are often multiple entries, so this “raw” list will actually contain duplicates. While we could handle this special case on the Ruby side of things, it’s also easy enough to remove them while running the final command that replaces the Exim config file. Depending on where you keep your valid zones, it would look something like this:

./exim_virtual_domains.rb /var/named/*.db | sort -u > /etc/exim4/domains.virtual

And that does it for the main configuration. Another related policy I have is that I set up catch-all addresses for those subdomains (which is tons easier than also creating actual accounts for every expiring email address I want to hand out). Fortunately, that is something that is also fairly straightforward to do at the command line:

grep -v '^\w*\.\w*$' /etc/exim4/domains.virtual | sed -E s/'(.*\.)(\w*)(\..*)'/'\@\1\2\3 : \2-catchall'/g > /etc/exim4/catchall.virtual

Now all that remains is to run update-exim4.conf && service exim4 restart to get Exim to use the changes and you’re good to go. Enjoy! For the full picture, I put the actual Ruby scripts I wrote in this handy .zip file. Let me know if you have any suggestions for improvements.