Here's a little script that I found handy to scan Postfix's
virtual address table, compare the domains with the ones actually
hosted by the system, and tell me what's really going on.
This works great for servers setup with Webmin and Virtualmin, or with
plain postfix installs.
See the comments about how the script determines who "we" really are.
#!/usr/bin/perl
# show_postfix_domains.pl
# Looks at /etc/postfix/virtual and tells us which of those emails
# are _actually_ hosted by this system, based on whether DNS lookups of
# the domains seem to point to "us"... where "us" is defined as any
# of the IP addresses on any of localhost's interfaces.
# Naturally, this will fail if your system is behind a gateway/firewall,
# because we have no way of probing that gadget to see how connections
# are routed from "The Internet" to us.
# Copyright (c) 2012, William Lindley bill -at- saltriversystems -dot- com
# 2012-06-06
# This script is free software, you may distribute it and/or modify it
# under the same terms as Perl itself.
use Net::DNS;
use Socket qw/inet_aton/;
use IO::Socket;
use IO::Interface qw(:flags);
my $s = IO::Socket::INET->new(Proto => 'udp');
my @interfaces = $s->if_list;
my %local_interfaces;
for my $if (@interfaces) {
my $flags = $s->if_flags($if);
if ( ( $flags & IFF_RUNNING ) &&
!( $flags & IFF_LOOPBACK ) &&
!( $flags & IFF_NOARP )) {
$local_interfaces{$if}{address} = $s->if_addr($if);
$local_interfaces{$s->if_addr($if)}{interface} = $if;
}
}
#########
my $r = Net::DNS::Resolver->new;
open VIRTUAL, '<', '/etc/postfix/virtual';
my %domains_hosted;
while (<VIRTUAL>) {
chomp;
s/#.*$//; # Remove after comment
my ($address, $alias) = split;
if ($address) {
if ($alias !~ /@/) { # Only for local addresses (not forwarded)
my ($name, $domain) = ($address =~ /^([^@]+)@(.+)$/);
next unless $name;
# print "[$name]@[$domain] -> [$alias]n";
$domains_hosted{$domain}{hosted} = 1;
$domains_hosted{$domain}{address}{$name}++;
}
}
}
use Data::Dumper;
foreach my $domain (keys %domains_hosted) {
# Liberally borrowed from David Landgren (grinder)'s code at
# http://www.perlmonks.org/?node_id=297667
my %res;
my $rr = $r->query( $domain, 'MX' );
if ($rr) {
for my $mx( $rr->answer ) {
if( $mx->type eq 'CNAME' ) {
my $a_rr = $r->query( $mx->cname, 'A' );
if( !$a_rr ) {
push @{$res{-1}}, { ip => $mx->cname, forw => $r->
errorstring, back => 'CNAME' };
} else {
$_->type eq "A"
and push @{$res{-1}}, { ip => $mx->cname, forw => $_->address, back => 'CNAME' }
for( $a_rr->answer );
}
next;
}
next unless $mx->type eq 'MX';
my $a_rr = $r->query( $mx->exchange, 'A' );
if( !$a_rr ) {
push @{$res{$mx->preference ? $mx->preference : 0}}, {
ip => $mx->exchange,
forw => $r->errorstring,
back => $r->errorstring,
};
next;
}
my @a;
for my $a( $a_rr->answer ) {
next unless $a->type eq "A";
my $ptr_rr = $r->query( join( '.', reverse( split /./ , $a->address )) . '.in-addr.arpa', 'PTR' );
if ($local_interfaces{$a->address}{interface}) {
$domains_hosted{$domain}{local}++;
}
if( !$ptr_rr ) {
push @{$res{$mx->preference}}, {
ip => $a->address,
forw => $mx->exchange,
back => $r->errorstring,
};
} else {
foreach ( $ptr_rr->answer ) {
if ( $_->type eq 'PTR' ) {
push @{$res{$mx->preference}}, {
ip => $a->address,
forw => lc $mx->exchange,
back => lc $_->ptrdname,
};
}
}
}
}
}
}
$domains_hosted{$domain}{mx} = %res;
}
# This could be greatly expanded by doing more with the data herein:
# print Dumper(%domains_hosted);
print "These email accounts are actually hosted here:n";
foreach my $domain (sort keys %domains_hosted) {
next unless $domains_hosted{$domain}{local};
print $domain . "n";
foreach my $email (sort keys %{$domains_hosted{$domain}{address}}) {
print " ${email}@${domain}n";
}
}
1;
As root: First make a backup of the existing key and certificate
file
# cd /etc/pki/dovecot
# cp -a certs/dovecot.pem certs/dovecot.pem.old
# cp -a private/dovecot.pem private/dovecot.pem.old
Create the new SSL certificate for two years:
# openssl genrsa -out private/dovecot.pem 1024
openssl req -new -x509 -key private/dovecot.pem -out certs/dovecot.pem -days 730
Restart Dovecot:
# /etc/init.d/dovecot restart
To see the start and end dates for the certificate:
# openssl x509 -dates -in certs/dovecot.pem
By default, Mailman -- which is installed by default in Virtualmin
as your mailing list manager, exhibits some nasty behavior, being open
to sending "backscatter" spam. This means that the Bad Guys send
fraudulent messages "from" the email address they actually want to send
spam to; Mailman rejects those messages, basically sending a bounce
message to the victim.
The mechanism the spammers use is left over from the days before web
interfaces. Nowadays, your subscribers interact with Mailman almost
exclusively via its HTTP interface. Other than actual postings from
subscribed members, and messages to the list owner, there is little or
no reason to keep the vestigial email aliases.
To disable the vulnerable aliases:
With Virtualmin, go into the Webmin interface, under Servers; Postfix
Mail Server; and click on the Aliases icon. You should see, for
example, defined among the email addresses:
yourlist-example.com Program /usr/lib/mailman/mail/mailman post yourlist
<strong>yourlist-admin-example.com Program /usr/lib/mailman/mail/mailman admin yourlist</strong>
yourlist-bounces-example.com Program /usr/lib/mailman/mail/mailman bounces yourlist
<strong>yourlist-confirm-example.com Program /usr/lib/mailman/mail/mailman confirm yourlist
yourlist-join-example.com Program /usr/lib/mailman/mail/mailman join yourlist
yourlist-leave-example.com Program /usr/lib/mailman/mail/mailman leave yourlist
</strong>yourlist-owner-example.com Program /usr/lib/mailman/mail/mailman owner yourlist
<strong>yourlist-request-example.com Program /usr/lib/mailman/mail/mailman request yourlist
yourlist-subscribe-example.com Program /usr/lib/mailman/mail/mailman subscribe yourlist
yourlist-unsubscribe-example.com Program /usr/lib/mailman/mail/mailman unsubscribe yourlist</strong>
for "yourlist@example.com" ... I recommend you disable these aliases
shown in bold above:
-admin-
, -confirm-
, -join-
, -leave-
, -request-
, -subscribe-
,
-unsubscribe-
.
You also need to edit /etc/postfix/virtual -- or in Webmin, open
"Servers" and click on "Postfix Mail Server" then click on the "Virtual
Domains" icon:
and delete the virtual mappings for all the addresses you just removed.
You will want to do this for each mailing list on your system.
For CentOS 5.1 -- First we install some dependencies. (This is
already present on CentOS 5.2 and CentOS 5.3.)
yum -y install perl-Net-SSLeay
step 1: webmin
Install the system, using the link at http://www.webmin.com/download.html
cd /usr/src
wget <a href="http://superb-east.dl.sourceforge.net/sourceforge/webadmin/webmin-1.450-1.noarch.rpm">http://superb-east.dl.sourceforge.net/sourceforge/webadmin/webmin-1.450-1.noarch.rpm</a>
rpm -i webmin-1.450-1.noarch.rpm
Then you can start in your browser (note: https: ) at:
https://localhost:10000
Webmin permits login from the root user as well as anyone who has sudo
privilege. To permit logging into webmin with your username and
password, give yourself permission to execute the sudo command by using
the visudo command (do not edit the file /etc/sudoers directly) and
un-comment the line:
%wheel ALL=(ALL) ALL
step 2: usermin
You might also want usermin... for the latest version, check:
<a href="http://www.webmin.com/udownload.html">http://www.webmin.com/udownload.html</a>
For example, to install:
cd /usr/src
wget http://prdownloads.sourceforge.net/webadmin/usermin-1.360-1.noarch.rpm
rpm -Uvh usermin-1.360-1.noarch.rpm
Then point your browser to
https://localhost:20000
step 3: virtualmin
For managing virtual domains, there are both GPL and commercial version
of Virtualmin. For many sites, the key difference will be that the paid
version includes the ability to manage spam and email antivirus
settings on a per-domain, per-user level, whereas the GPL doesn't.
<a href="http://www.virtualmin.com/">http://www.virtualmin.com/</a>
Download the install script and run it. Note, the installer for Centos
5 misses one permission setting. Users attempting to retrieve POP3
email can't login. If you manually connect to port 110 and login, you
will see the error as follows:
$ telnet mailserver 110
Trying 192.168.1.20...
Connected to mailserver.domain.
Escape character is '^]'.
+OK Dovecot ready.
user user.domain
+OK
pass password
+OK Logged in.
-ERR [IN-USE] Couldn't open INBOX: Internal error occurred.
Refer to server log for more information.
In the file /var/log/maillog you will see:
Feb 23 05:01:02 host dovecot: POP3(user.domain): mkdir(/var/lib/dovecot/index/user.domain/.INBOX) failed: Permission denied
Feb 23 05:01:02 host dovecot: POP3(user.domain): mkdir(/var/lib/dovecot/control/user.domain/.INBOX) failed: Permission denied
Feb 23 05:01:02 host dovecot: POP3(user.domain): mkdir(/var/lib/dovecot/index/user.domain/.INBOX) failed: Permission denied
Feb 23 05:01:02 host dovecot: POP3(user.domain): mkdir(/var/lib/dovecot/control/user.domain/.INBOX) failed: Permission denied
Feb 23 05:01:02 host dovecot: POP3(user.domain): Couldn't open INBOX: Internal error occurred. Refer to server log for more information. [2009-02-23 05:01:02]
Feb 23 05:01:02 host dovecot: POP3(user.domain): Couldn't open INBOX top=0/0, retr=0/0, del=0/0, size=0
To solve this, as root:
chmod 755 /var/lib/dovecot
chmod 777 /var/lib/dovecot/index /var/lib/dovecot/control
step 4: configuring spamassassin
Once Webmin is installed, spamassassin is very easy to turn on -- there
is a button that will automatically create the correct entries in /etc/procmailrc
... the one missing link is that, by default, Postfix doesn't use that
file. You can either manually add this line in /etc/postfix/main.cf:
mailbox_command = /usr/bin/procmail
or in Webmin, on the Local Delivery page of Postfix, set the parameter:
External command to use instead of mailbox delivery
to be:
/usr/bin/procmail
And that's all there is to getting SpamAssassin running.
step 5: change runlevel to avoid loading X
In your /etc/inittab, change the default runlevel from 5 to 3, so X
won't load. That means no graphical login -- and a bunch of saved
memory, if you're running a server instead of workstation.