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`; }