postfix and dovecot 2.0.9 rejecting over quota user on smtp stage

No Comments »

i’m switching from courier-imap to dovecot recently. unfortunately on my centos 6.7, i only have dovecot 2.0.9 available. quota work as expected. the only thing that bother me, everytime someone outside world sent email to one of overquota user, dovecot create bounce mail to the sender. which is not good. expert said : “you will create backscattering mail!”.

long time ago when i was using courier-imap, i was creating simple perl daemon to check user quota and disk usage. dovecot have additional mysql table for storing user quota usage/bytes and messages.

so here how i’ve done.

perl daemon

#!/usr/bin/perl
use File::Find;
use strict;
use warnings;
use DBI;
use DBD::mysql;
use Sys::Syslog qw(:DEFAULT setlogsock);
use base qw(Net::Server::PreFork);

#
# Initalize and open syslog.
#
openlog('postfix::CHECK-SIZE::','pid','mail');

__PACKAGE__->run;
exit;

###

sub configure_hook {
        my $self = shift;

        $self->{server}->{port}     = '127.0.0.1:20028';
        $self->{server}->{user}     = 'vmail';
        $self->{server}->{group}    = 'mail';
        $self->{server}->{pid_file} = '/tmp/quota.pid';
        $self->{server}->{setsid}   = 1;
        $self->{basedir}            = "/data/vmail/example.com/";

}

### process the request
sub process_request {
        my $self = shift;
        while(my $line = <STDIN>) {
                chomp($line);
                if ($line=~/^get\s+(.+)/i) {
                        my $user = $1;
                        trim($user);
                        my $sqlsize = checksqlsize($user);
                        if (defined $sqlsize && $sqlsize == 0) {
                                print STDOUT "200 DUNNO\n";
                                #print STDOUT "sqlsize: $sqlsize\n";
                                next;
                        }
                        #print STDOUT "sqlsize: $sqlsize\n";

                        my $usrdirsize = $user;
                        $usrdirsize =~ s/\@example\.com$/\//;
                        my $dir = $self->{basedir} . $usrdirsize;
                        my $sqlusage =  checksqlusage($user);

                        if (defined $sqlusage && defined $sqlsize) {
                        syslog("info","Checking %s maildir size: define=%s, diskusage=%s", $user, $sqlsize, $sqlusage);
                                if ( $sqlusage > $sqlsize) {
                                        print STDOUT "200 REJECT $user is over quota! maildir size: define=$sqlsize, diskusage=$sqlusage\n
";
                                        next;
                                }
                        }
                }
                print STDOUT "200 DUNNO\n";
        }
}

sub trim{
        $_[0]=~s/^\s+//;
        $_[0]=~s/\s+$//;
        return;
}

sub checksqlsize {
        my $user = $_[0];
        my $sqlresult;
        trim($user);
        my $dbh = DBI->connect('DBI:mysql:postfix:localhost', 'postfix', 'yourpassword', { RaiseError => 1 });
        my $sth = $dbh->prepare(qq{SELECT quota FROM mailbox WHERE username='$user'});
        $sth->execute();
        while (my @row = $sth->fetchrow_array) {
                $sqlresult = $row[0];
        }
        $sth->finish();
        $dbh->disconnect;
        if ($sqlresult >= 0 ) {
                return $sqlresult;
        } else {
                return undef;
        }
}

sub checksqlusage {
        my $user = $_[0];
        my $sqlresult;
        trim($user);
        my $dbh = DBI->connect('DBI:mysql:postfix:localhost', 'postfix', 'yourpassword', { RaiseError => 1 });
        my $sth = $dbh->prepare(qq{SELECT bytes FROM quota2 WHERE username='$user'});
        $sth->execute();
        while (my @row = $sth->fetchrow_array) {
                $sqlresult = $row[0];
        }
        $sth->finish();
        $dbh->disconnect;
        if ($sqlresult >= 0 ) {
                return $sqlresult;
        } else {
                return undef;
        }
}

1;

postfix section

smtpd_recipient_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        reject_unauth_destination,
        reject_non_fqdn_sender,
        reject_non_fqdn_recipient,
        reject_unknown_recipient_domain,
        check_recipient_access proxy:tcp:[127.0.0.1]:20028,
        reject_rbl_client zen.spamhaus.org,
        reject_rbl_client bl.spamcop.net,
        reject_rbl_client dnsbl.sorbs.net,

test

# telnet localhost 20028
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get foo@example.com
200 REJECT foo@example.com is over quota! maildir size: define=102400000, diskusage=147383243

you’re good to go :)

Share

Postfix Changing Outgoing IP By Time Interval Using TCP_TABLE And Perl

14 Comments »

Someone asked me if i can make a perl scripts that can change the ip address based on time interval, say he want ip address 1.2.3.4 used within one hour, if done next ip address will be used within next one hour..and so on. when it came to highest number of ip address in array, they will be reset back to the start. first i suggest him to look at the articles i wrote. But then i decide to write Perl script which was made for the purposes mention above.

here we are..

Postfix section:

master.cf
127.0.0.1:2527 inet  n       n       n       -       0      spawn
          user=nobody argv=/etc/postfix/ip_by_time.pl

ip1  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-ip1
          -o smtp_helo_name=smtp1.example.com
          -o smtp_bind_address=1.2.3.1

ip2  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-ip2
          -o smtp_helo_name=smtp2.example.com
          -o smtp_bind_address=1.2.3.2

ip3  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-ip3
          -o smtp_helo_name=smtp3.example.com
          -o smtp_bind_address=1.2.3.3

ip4  unix -       -       n       -       -       smtp
          -o syslog_name=postfix-ip4
          -o smtp_helo_name=smtp4.example.com
          -o smtp_bind_address=1.2.3.4
....
....

main.cf

transport_maps = tcp:[127.0.0.1]:2527
127.0.0.1:2527_time_limit = 3600s

Read the rest of this entry »

Share
keep looking »