Postfix, maintaining relay destinations
From FreeBSDwiki
#!/usr/bin/perl
########################################################
###
### update-postfix.pl
###
### purpose: automatically maintain a list of "secret"
### destination MTAs for Postfix to relay mail
### to.
###
### usage: run without arguments to check for
### changes and update if necessary, or run
### with --force to rebuild transport and
### recipient tables and rehash them for
### postfix even if no changes have been made.
###
### method: if the md5sum for any relevant file in
### $dir does not match $dir/$file.md5,
### update $dir/$file.md5, process all
### relevant files into new postfix recipient
### and transport tables, and re-hash those
### tables for postfix.
###
### requires: for each destination MTA, place a
### file in $dir named that server's IP
### address, optionally with a port number
### appended to it, in the form
### $dir/192.168.0.10 or $dir/192.168.0.10-587
###
### Each file must contain a list of all valid
### addresses to be relayed to the MTA at that,
### address, one address per line, in the form
### user@domain. Catchall addresses may be
### used by omitting the username, and
### merely specifying @domain on that line.
###
### Any line which contains an @ will be
### processed as an email address. Any line
### which does not contain an @ will be
### ignored completely.
###
### bugs: requires IP address as relay target,
### so cannot do round-robin delivery and
### will not notice MX record changes.
###
########################################################
### config variables
#
$dir = '/usr/home/postfixfiles/';
$recipientsfile = '/usr/local/etc/postfix/recipients';
$transportfile = '/usr/local/etc/postfix/transport';
$postmapprogram = '/usr/local/sbin/postmap';
$md5sumprogram = '/sbin/md5 -q';
$logger = '/usr/bin/logger -p mail.notice';
$identity = 'update-postfix';
### begin operation
#
opendir(DIR,$dir);
@files = readdir(DIR);
closedir(DIR);
my $needsupdate = 0;
$logger .= " $identity\: ";
if ($ARGV[0] eq '--force') { $needsupdate = 1; }
foreach $file (@files) {
if ($file =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(-\d{1,4})?$/) {
my $path = $dir.$file;
my $md5path = $path.'.md5';
my $newmd5 = `$md5sumprogram $path`;
my $oldmd5;
if (-e $md5path) {
open(FH,$md5path) or die "Can't open $md5path: $!";
$oldmd5 = <FH>;
close FH;
}
if ($oldmd5 ne $newmd5) {
open(FH,">$md5path") or die "Can't open $md5path: $!";
print FH $newmd5;
close FH;
$message = "$file changed since last check";
print "$message\n";
print `$logger $message`;
$needsupdate = 1;
}
}
}
if ($needsupdate == 0) {
$message = "No data changed in $dir - update not needed.";
print "$message\n";
print `$logger $message`;
} else {
$message = "Updating Postfix configuration...\n";
if ($ARGV[0] eq '--force') {
$message = "UPDATE FORCED: " . $message;
}
print "$message\n";
print `$logger $message`;
foreach $file (@files) {
if ($file =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(-\d{1,4})?$/) {
open FH, "$dir$file" or die "Can't open $file: $!";
foreach $line (<FH>) {
if ($line =~ /\@/) {
# add ok to end of address and push it into recipients
$recipient = $line;
chomp $recipient;
$recipient .= " OK\n";
push @recipients,$recipient;
# create a domain routing line and push it into rawdomains
(my $ip,my $port) = ($file =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})-?(\d{1,4})?/);
$line = (split("@",$line))[1];
chomp $line;
$line .= " smtp:[$ip]";
if ($port ne ) { $line .= ":$port"; }
$line .= "\n";
push @rawdomains,$line;
}
}
close FH;
}
}
# sort domains for transport table to eliminate dupes
%hashTemp = map { $_ => 1 } @rawdomains;
@sorteddomains = sort keys %hashTemp;
open FH, ">$recipientsfile" or die "Can't open $recipientsfile: $!";
print FH @recipients;
close FH;
$message = scalar @recipients;
$message = $message . " recipients written to $recipientsfile";
print "$message\n";
print `$logger $message`;
open FH, ">$transportfile" or die "Can't open $transportfile: $!";
print FH @sorteddomains;
close FH;
$message = scalar @sorteddomains;
$message = $message . " domains written to $transportfile";
print "$message\n";
print `$logger $message`;
print `$postmapprogram $recipientsfile`;
print `$postmapprogram $transportfile`;
}