howto convert from amavisd-new to qpsmtpd
Until recently I was using a postfix/amavisd-new/spamassassin based anti-spam solution on our mailserver. That resulted in constant high swap-in/outs, and as we are using XEN based virtual machines this lead to an unbearable cpu utilisation (100% io wait).
I changed the setup to a qpsmtpd/spamassassin configuration recently. This cut memory usage in half (500MByte to 250MByte), reduced swapping to around 0 pageins/second and decreased the load average from around 1.5-2 to 0-0.5. Overall not a bad change.
For more detailed information, including the adapted scripts for usage with postfixadmin follow the next link:
Why?
Our current amavisd-new/postfix mail setup used way too much memory and led the server to constant swapping. This hurt us badly as in our virtual XEN instance IO access is usually the bottleneck.
Old System
The old system used postfix as the incoming MTA, the mails were further dispatched to amavisd which used clamav and spamassassin for spam filtering. Authentication for mail relaying was done through the postfix sasl support for the dovecot imap server. For all user configuration related tasks postfixadmin is used.
New System
qpsmtpd is used as our new incoming SMTP server. It uses the postfixadmin database through custom SQL queries to verify mail recipients and relaying. The mails are further dispatched to spamassassin which is used for spam and virus classification. Finally the existing postfix system (sans the amavis step) is used for delivering the mails.
Adapted qpsmtpd scripts postfixadmin
Suggestions – or even better code – is highly welcomed.
Using the postfixadmin user database for relaying
This script will change soon:
- gain username/password/database through program parameters
#!/usr/bin/perl -w=head1 NAMEauth_postfixadmin - Authenticate to a postfixadmin user database via MySQL=head1 DESCRIPTIONThis plugin authenticates users directly against a postfixadmin mysqldatabase.=head1 CONFIGURATIONcurrently none.=head1 AUTHORAndreas Happe <andreashappe@snikt.net>=head1 COPYRIGHT AND LICENSECopyright (c) 2006 Andreas HappeThis plugin is licensed under the same terms as the qpsmtpd package itself.Please see the LICENSE file included with qpsmtpd for details.=cutsub register { my ( $self, $qp ) = @_; $self->register_hook("auth-plain", "authsql" ); $self->register_hook("auth-login", "authsql" );}sub authsql { use DBI; use Qpsmtpd::Constants; my $connect = "dbi:mysql:dbname=dbname"; my $dbuser = "username"; my $dbpasswd = "password"; my $dbh = DBI->connect( $connect, $dbuser, $dbpasswd ); $dbh->{ShowErrorStatement} = 1; my ( $self, $transaction, $method, $user, $passClear, $passHash, $ticket ) = @_; my ( $pw_name, $pw_domain ) = split "@", lc($user); unless ( defined $pw_domain ) { return DECLINED; } $self->log(LOGINFO, "Authentication to postfixadmin via mysql: $pw_name@$pw_domain"); my $sth = $dbh->prepare(<<SQL);SELECT * FROM mailbox WHERE username = ?SQL $sth->execute( $user ); my $passwd_hash = $sth->fetchrow_hashref; $sth->finish; $dbh->disconnect; my $pw_clear_passwd = exists $passwd_hash->{'password'} ? $passwd_hash->{'password'} : undef; if ( not defined $pw_clear_passwd) { return ( DECLINED, "authsql/$method" ); } if ( defined $passClear and ($pw_clear_passwd eq $passClear)) { $self->qp->connection->relay_client(1); return ( OK, "authsql/$method" ); } else { return ( DENY, "authsql/$method - wrong password" );
}
Using the postfixadmin domain database for recipient domains
Script name: rcpt_postfixadmin. Just replace rcpt_ok with rcpt_postfixadmin.
This also needs some updates:
- use program arguments for database definition
- check aliases
- check usernames
I’m currently testing a new version of this script which checks the supplied user against the user database more thoroughly, but it still has some problems with catchall alias. Hopefully this will be resolved rather soon.
use Qpsmtpd::DSN;use DBI;sub hook_rcpt { my ($self, $transaction, $recipient) = @_; my $host = lc $recipient->host; my $connect = "dbi:mysql:dbname=postfix"; my $dbuser = "username"; my $dbpasswd = "password"; my $dbh = DBI->connect($connect, $dbuser, $dbpasswd); $dbh->{ShowErrorStatements} = 1; my $sth = $dbh->prepare("select * from domain where domain = ? and active = 1"); $sth->execute($host); $self->log(LOGINFO, "trying to connect to $host:" + $sth->err + "->" + $sth->rows); my $result = $sth->fetchrow_hashref; $sth->finish; $dbh->disconnect; if ($self->qp->connection->relay_client) { return (OK); } if(exists $result->{'domain'}) {# alias checking is still done by postfix return (OK); } else { return Qpsmtpd::DSN->relaying_denied(); }
}
No related posts.
From → Admin-stuff, Linux