hi all,

I'm a french perl coder and debian admin, I've been lurking this list for few 
months, time 
to make known to Jedis ;)

thanx for the great tool qpsmtpd is, it saves my job position during the last 
massive spam 
attack on our servers, now Exim4 is merely poking at the underlying level,

here is a mod for Marc Sebastian Pelzer's check_rcptto_exists :  

- instead of seeking user in the file-based Exim4 aliases routing tables, it 
asks MySQL 
Virtual Exim [http://silverwraith.com/vexim/] database if user exists on the 
system,

- if you put any domain in the file /etc/qpsmtpd/rcptto_domains_nocheck, this 
domain passes 
through this plugin, allowing to have a catchall for it,

don't know if it is the right place to post code, this is a draft, successfully 
tested 
in production, feel free to spread it and to report any feedback !

cheers,

=== check_rcptto_exists+vexim+catchall ===

# check_rcptto_exists Version 1.0 by Marc Sebastian Pelzer
#
# ============================================================================
# modified: 2007-12-03 by Etienne LEMEE aka Et!L3W <coding AT etilem DOT net> 
#           in order to connect to vexim database 
#           and to allow per domain catchall 
# ============================================================================
# 
# This plugin check wether a recipient of an incoming email exists in our local 
vexim 
# database.
#
# Access parameters to the database are hard-coded into this plug-in and you 
may need to 
# modify it a bit in order to fit your set-up.
#
# Should not be a big problem if you know Perl :)
#
# You should create a config-file called "config/relayclients" which should 
contain a (maybe 
# dynamically created) list of IP's or hostnames which are white-listed from 
this plug-in.
#
# You should also create a config-file called "config/rcptto_domains_nocheck" 
which should 
# contain a list of domains which are white-listed from this plug-in, allowing 
per domain 
# catchall
#
# It is recommended to put your relay-client's IP's inside this file, otherwise 
all outgoing 
# connections will be rejected because the recipient of the outgoing mail is 
not locally 
# known.

#
# Fell free to change that behaviour as you like and to use this plug-in as an 
example for 
# your own alias check.
#
use strict qw(vars);
use Mysql;
use Qpsmtpd::DSN;

sub hook_rcpt {

  my ($self, $transaction, $recipient) = @_;
  my ($line, $user, $tmp);

  my $userExists = 0;

  my $remote_ip = $self->qp->connection->remote_ip;
  my $remote_host = $self->qp->connection->remote_host;

  # relayclients can send email to whoever thay want
  #
  my @relayclients = $self->qp->config("relayclients");
  
  foreach $tmp (@relayclients) {

    if ($remote_host =~ m!$tmp! || $remote_ip =~ m!$tmp!) {

        $self->log( LOGNOTICE, 
                    "Ok - remote peer is a allowed RELAY client ($remote_host / 
$remote_ip)");
        return DECLINED;
    }
  }

  return (DECLINED) unless $recipient->host && $recipient->user;

  my $host = lc $recipient->host;
  my $lpar = lc $recipient->user;

  # Et!L3W - domains found in /etc/qpsmtpd/rcptto_domains_nocheck passes 
through this plugin
  
  my @nocheckdomains = $self->qp->config("rcptto_domains_nocheck");
  
  foreach my $tmp (@nocheckdomains) {

    if ($host =~ m!$tmp!) {

        $self->log( LOGNOTICE, 
                    "Ok - $host domain is allowed to have a catchall");
        return DECLINED;
    }
  }

  # Et!L3W - connection to Mysql 
  
  my ($db_host, $db_user, $db_pass, $db_base) = qw(localhost vexim CHANGEME 
vexim);
  
  my $dbh = Mysql->connect($db_host, $db_base, $db_user, $db_pass);

  $dbh->selectdb($db_base);

  my $sth;
  
  # Et!L3W - query for real domain, in case of domain alias (needs subselect 
feature from MySQL)
  
  $sth = $dbh->query(sprintf(
  "select domain from domains where domain_id in " .
  "(select domain_id from domainalias where alias='%s')", 
  $host));
  
  my $real = $sth->fetchrow;
  
  $host = $real ? $real : $host;
  
  my $from = $lpar . '@' . $host;
      
  # Et!L3W - query for username
  
  $sth = $dbh->query(sprintf(
  "select count(*) from users where username='%s'", 
  $from)); 
  
  $userExists = $sth->fetchrow;

  if ($userExists < 1) {

      # Et!L3W - I pick the default SMTPD timeout for qpsmtpd found in 
/etc/qpsmtpd/timeoutsmtpd 
      #          instead of hardcoding it to set the slow-down delay, or fall 
back to 60 seconds 

      my $sleep = $self->qp->config("timeoutsmtpd") || 60;
      
      # Et!L3W - adding the delay advice (second logging message part) 

      $self->log(LOGNOTICE, "Recipient '$from' does not exists here. " .
                            "Slowing down spammer for $sleep seconds...");
            
      sleep $sleep; # slow down spammer
                         
      return Qpsmtpd::DSN->no_such_user("mail to $from not accepted here");
  }

  # Et!L3W - adding the userExists count advice  

  $self->log(LOGNOTICE, "OK, recipient '$from' exists [count=$userExists]. " .
                        "Allowing to pass through ...");

  return (DECLINED);
}


=== rcptto_domains_nocheck ===
# domains, one per line, found in this file are not checked by 
check_rcptto_exists
# e.g.:
# domain.tld
# anotherdomain.tld


=== timeoutsmtpd ===
# qpsmtpd timeout in seconds
30


-- 
Etienne
 /\_/\
(=°o°=)
http://etilem.net

Reply via email to