pavement

Postfix, maintaining relay destinations

From FreeBSDwiki
(Difference between revisions)
Jump to: navigation, search
 
Line 1: Line 1:
 +
This script will make maintaining lists of relay destinations - particularly "secret" destinations not listed in DNS - much simpler.
 +
 +
For every relay destination your server maintains, create a file with the name of that server's IP address, and inside it list each valid email address that destination services.  For example, if you have one mail server at 192.168.0.15 which handles tom, bob, and sue at example.tld and ANY address at example2.tld, you would put the following file in /home/postfixfiles:
 +
 +
mx# cat /home/postfixfiles/192.168.0.15
 +
tom@example.tld
 +
bob@example.tld
 +
sue@example.tld
 +
@example2.tld
 +
 +
Now run the update-postfix.pl script, and it will generate transport and recipients files for Postfix, map them, and put appropriate entries in the mail log.
 +
 +
mx# /usr/local/bin/update-postfix.pl
 +
192.168.0.15 changed since last check
 +
Updating Postfix configuration...
 +
5 recipients written to /usr/local/etc/postfix/recipients
 +
2 domains written to /usr/local/etc/postfix/transport
 +
 +
If you need to target a non-standard SMTP port, you can just place it at the end of the filename.  For example, if you want mail to example3.tld to go to port 2525 instead of the default port 25, just make the filename 192.168.0.16-2525:
 +
 +
mx# cat /home/postfixfiles/192.168.0.16-2525
 +
harry@example3.tld
 +
mx# /usr/local/bin/update-postfix.pl
 +
192.168.0.15-2525 changed since last check
 +
Updating Postfix configuration...
 +
6 recipients written to /usr/local/etc/postfix/recipients
 +
3 domains written to /usr/local/etc/postfix/transport
 +
 +
And looking at /usr/local/etc/postfix/transport shows that the port is specified for example3.tld, but not for example.tld or example2.tld:
 +
 +
mx# cat /usr/local/etc/postfix/transport
 +
example.tld smtp:[192.168.0.15]
 +
example2.tld smtp:[192.168.0.15]
 +
example3.tld smtp:[192.168.0.15]:2525
 +
 +
The script uses md5 checksums to see if the files in its config directory have changed, so you can run it frequently from cron to have it automatically pick up changes.  You can also run it manually if you like, or run it manually with the --force argument to make it re-read its configuration files and rebuild the transport and recipients tables whether it thinks it needs to or not.
 +
 +
Be sure to check locations of important programs and config directories in the config variables section before you use the script.
 +
 
  #!/usr/bin/perl
 
  #!/usr/bin/perl
 
   
 
   

Revision as of 16:02, 6 October 2009

This script will make maintaining lists of relay destinations - particularly "secret" destinations not listed in DNS - much simpler.

For every relay destination your server maintains, create a file with the name of that server's IP address, and inside it list each valid email address that destination services. For example, if you have one mail server at 192.168.0.15 which handles tom, bob, and sue at example.tld and ANY address at example2.tld, you would put the following file in /home/postfixfiles:

mx# cat /home/postfixfiles/192.168.0.15
tom@example.tld
bob@example.tld
sue@example.tld
@example2.tld

Now run the update-postfix.pl script, and it will generate transport and recipients files for Postfix, map them, and put appropriate entries in the mail log.

mx# /usr/local/bin/update-postfix.pl
192.168.0.15 changed since last check
Updating Postfix configuration...
5 recipients written to /usr/local/etc/postfix/recipients
2 domains written to /usr/local/etc/postfix/transport

If you need to target a non-standard SMTP port, you can just place it at the end of the filename. For example, if you want mail to example3.tld to go to port 2525 instead of the default port 25, just make the filename 192.168.0.16-2525:

mx# cat /home/postfixfiles/192.168.0.16-2525
harry@example3.tld
mx# /usr/local/bin/update-postfix.pl
192.168.0.15-2525 changed since last check
Updating Postfix configuration...
6 recipients written to /usr/local/etc/postfix/recipients
3 domains written to /usr/local/etc/postfix/transport

And looking at /usr/local/etc/postfix/transport shows that the port is specified for example3.tld, but not for example.tld or example2.tld:

mx# cat /usr/local/etc/postfix/transport
example.tld smtp:[192.168.0.15]
example2.tld smtp:[192.168.0.15]
example3.tld smtp:[192.168.0.15]:2525

The script uses md5 checksums to see if the files in its config directory have changed, so you can run it frequently from cron to have it automatically pick up changes. You can also run it manually if you like, or run it manually with the --force argument to make it re-read its configuration files and rebuild the transport and recipients tables whether it thinks it needs to or not.

Be sure to check locations of important programs and config directories in the config variables section before you use the script.

#!/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`;
}
Personal tools