Making your Backup MX do recipient verification with Exim...
Well, in response to Kevin and Pascal's posts regarding backup MX's, I
decided to actually do something about mine...
My backup MX does backup for my domain, as well as for a few friends and
acquaintances. One such acquaintance happens to get one hell of a lot of spam
traffic to his domain, which is directed at the backup MX... Me. He also happens
to have recipient verification turned on. So, I end up with a gazillion messages
in the queue on my backup MX.
So, I found a solution FOR EXIM *3* which gives the backup MX the
ability to do recipient verification, without needing some static list of
recipients available for a domain.
For those that want to do the same, here's the instructions.
To start with, you need an exim with the embedded perl interpreter, which isn't
available with woody's exim. Source build time. Commands:
apt-get build-dep exim
apt-get install libperl-dev
apt-get source exim
cd exim-3.35
Edit src/EDITME, and uncomment the line: EXIM_PERL=perl.o
dpkg-buildpackage -us -uc -rfakeroot
cd ..
sudo dpkg -i exim_3.35-1woody3_i386.deb
Right, now we have an exim package installed with the embedded perl interpreter
enabled.
Second up, we need to make a few changes to exim.conf, so that we can do
verification on domains we relay for. Here's a list:
- Move all domains that we relay for, from the relaydomains
directive to the localdomains directive [0].
- Add "domains = !<relay domains>" to all existing
directors
Add the following to the main configuration section:
# Lets get perl going
perl_at_start = true
perl_startup = do '/etc/exim/relay_verify.pl'
Add the following to the directors section:
# This is to verify local parts of relayed domains
relay_verify:
domains = <relay domains>
driver = smartuser
verify_only = true
new_address = ${perl{relay_verify}}
relay_deliver:
domains = <relay domains>
driver = smartuser
transport = remote_smtp_relay
Add the following to the transports section:
remote_smtp_relay:
driver = smtp
hosts = ${perl{relay_getmx}}
That's exim done. Now we just need to create the perl script that'll do the job
for us. From above, create /etc/exim/relay_verify.pl with the following:
#!/usr/bin/perl
use strict;
use Net::SMTP;
sub relay_verify
{
# Get the local part and domain of the address we're relaying to.
my $local_part = Exim::expand_string('$local_part');
my $domain = Exim::expand_string('$domain');
# Get our hostname for the HELO string below...
my $hostname = Exim::expand_string('$primary_hostname');
# Get the mx entries from exim, for the domain we're relaying for
my $primarymx = relay_getmx();
my $code = 451;
my $msg = "Unknown error. Try again later.";
if (defined $primarymx) {
my $smtp = Net::SMTP->new($primarymx,
Hello => $hostname,
Timeout => 10,
Debug => 0);
if (defined $smtp) {
$smtp->mail('');
$smtp->to("$local_part\@$domain");
$code = $smtp->code();
$msg = $smtp->message();
$smtp->quit;
} else {
# Cut our losses, if the primary MX isn't responding,
# Accept anyway.
$code = 250;
}
}
if ($code >= 500) {
return ":fail: $msg";
} elsif ($code >= 400) {
return ":defer: $msg";
} else {
return "$local_part\@$domain";
}
}
sub relay_getmx
{
# Get the mx entries from exim, for the domain we're relaying for
my $mxs = Exim::expand_string('${lookup dnsdb{mx=$domain}{$value}fail}');
my $lowest = -1;
my $primarymx;
# Get the lowest valued MX entry.
for my $entry (split("\n", $mxs)) {
my ($pref, $host) = split(" ", $entry);
if (($lowest == -1) or ($pref < $lowest)) {
$lowest = $pref;
$primarymx = $host;
}
}
return $primarymx;
}
The Code should be fairly self explanatory - in effect, if we can get a reply
from the Primary MX for a domain we're relaying for to either fail or defer an
arbitrary address, we pass that on to the system contacting the backup MX. If we
get no reply in 10 seconds, we just accept the mail, since that's what a backup
MX is supposed to do.
Setting the Debug option to 1 in the arguments to the Net::SMTP
constructor, and using exim's -bh option, you can do some testing to
see that this is working. (e.g.: exim -bh <some remote IP> )
[0]: I use files to list the domains my mailservers use, so I have things like:
local_domains = /etc/exim/local_domains : /etc/exim/virtual_domains
relay_domains = /etc/exim/relay_domains
[04:52]
[/Hacking]
[permanent link]
|