Compare commits
14 Commits
main
...
rcpt_mysql
Author | SHA1 | Date | |
---|---|---|---|
aee624bbc0 | |||
d7fb6dc7a4 | |||
e851de04da | |||
eabc37d23b | |||
d76ad8da45 | |||
102139ebe3 | |||
bc4433b429 | |||
5c8a8b4943 | |||
05ff0ad608 | |||
1197d6524e | |||
99844dec19 | |||
dde0e7ea9d | |||
7fb5b3df28 | |||
c4f5490abd |
252
plugins/rcpt_mysql
Normal file
252
plugins/rcpt_mysql
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
use Qpsmtpd::Constants;
|
||||||
|
use DBI;
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# called when initializing the plugin
|
||||||
|
#
|
||||||
|
sub init {
|
||||||
|
my ($self, $qp, %args) = @_;
|
||||||
|
|
||||||
|
# some default values
|
||||||
|
$self->{database} = "mail";
|
||||||
|
$self->{host} = "localhost";
|
||||||
|
$self->{port} = "3306";
|
||||||
|
$self->{user} = undef;
|
||||||
|
$self->{pass} = undef;
|
||||||
|
$self->{rawquery}= undef;
|
||||||
|
|
||||||
|
# the cache timeout in seconds
|
||||||
|
$self->{cacheTimeout} = 500; #seconds
|
||||||
|
|
||||||
|
# a map for caching database repsonses
|
||||||
|
# done on a per email basis
|
||||||
|
$self->{cache} = {};
|
||||||
|
|
||||||
|
# parse the configuration file
|
||||||
|
$self->parseConfig();
|
||||||
|
|
||||||
|
$self->createQuery();
|
||||||
|
|
||||||
|
$self->createDSN();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub createDSN
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
#my $dsn = "DBI:mysql:database=$database;host=$hostname;port=$port";
|
||||||
|
my $dsn = "DBI:MariaDB:database=" . $self->{database} . ";host=" . $self->{host} . ";port=" . $self->{port};
|
||||||
|
$self->{dsn} = $dsn;
|
||||||
|
|
||||||
|
# try to parse the dsn to ensure it is valid
|
||||||
|
my @data = DBI->parse_dsn($self->{dsn});
|
||||||
|
|
||||||
|
if (@data == 0)
|
||||||
|
{
|
||||||
|
$self->log(LOGERROR, "DSN " . $self->{dsn} . " not valid");
|
||||||
|
$self->{dsn}="";
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->log(LOGDEBUG, "created DSN " . $self->{dsn});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub createQuery
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
#
|
||||||
|
# !u the user part of the rcpt
|
||||||
|
# !d the domain part of the rcpt
|
||||||
|
|
||||||
|
my @params;
|
||||||
|
my @variables = split /!/,$self->{rawquery};
|
||||||
|
|
||||||
|
for my $v (@variables)
|
||||||
|
{
|
||||||
|
if ($v eq "u")
|
||||||
|
{
|
||||||
|
push(@params,"user");
|
||||||
|
}
|
||||||
|
elsif ($v eq "d")
|
||||||
|
{
|
||||||
|
push(@params,"domain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{sqlparams}=\@params;
|
||||||
|
|
||||||
|
my $query = $self->{rawquery};
|
||||||
|
$query =~s/!u/?/g;
|
||||||
|
$query =~s/!d/?/g;
|
||||||
|
|
||||||
|
$self->{sqlquery}=$query;
|
||||||
|
|
||||||
|
$self->log(LOGDEBUG, "created query " . $self->{sqlquery});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prepareParams
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
my $recipient = shift;
|
||||||
|
|
||||||
|
my @params;
|
||||||
|
|
||||||
|
for my $p (@params)
|
||||||
|
{
|
||||||
|
if ($p eq "user")
|
||||||
|
{
|
||||||
|
push(@params,$recipient->user);
|
||||||
|
}
|
||||||
|
elsif($p eq "domain")
|
||||||
|
{
|
||||||
|
push(@params,$recipient->user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return @params;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parseConfig
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
# parse the configuration file of this plugin line by line
|
||||||
|
my @config = $self->qp->config('rcpt_mysql');
|
||||||
|
|
||||||
|
for my $line (@config)
|
||||||
|
{
|
||||||
|
$self->log(LOGDEBUG, "config line " . $line);
|
||||||
|
my @value = split /:=/, $line;
|
||||||
|
|
||||||
|
my $key = lc($value[0]);
|
||||||
|
|
||||||
|
if ( $key eq "database")
|
||||||
|
{
|
||||||
|
$self->{database} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "host")
|
||||||
|
{
|
||||||
|
$self->{host} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "user")
|
||||||
|
{
|
||||||
|
$self->{user} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "pass")
|
||||||
|
{
|
||||||
|
$self->{pass} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "port")
|
||||||
|
{
|
||||||
|
$self->{port} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "cachetimeout")
|
||||||
|
{
|
||||||
|
$self->{cacheTimeout} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "pass")
|
||||||
|
{
|
||||||
|
$self->{pass} = $value[1];
|
||||||
|
}
|
||||||
|
elsif ( $key eq "query")
|
||||||
|
{
|
||||||
|
$self->{rawquery} = $value[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warn("Key \"" . $key . "\" is an unknown configuration option");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub askCache
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
my $recipient = shift;
|
||||||
|
|
||||||
|
# combine to a normal recipient
|
||||||
|
my $rcpt = lc $recipient->user . '@' . lc $recipient->host;
|
||||||
|
|
||||||
|
# check if there is something in the cache for this recipient
|
||||||
|
if ($self->{cache}->{$rcpt} && $self->{cache}->{$rcpt}->{time}-time() <= $self->{cacheTimeout}) {
|
||||||
|
if ($self->{cache}->{$rcpt}->{hit} == 0 )
|
||||||
|
{
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub askDatabase
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
my $recipient = shift;
|
||||||
|
|
||||||
|
if (length($self->{dsn}) == 0)
|
||||||
|
{
|
||||||
|
$self->log(LOGERROR, "DSN not valid not checking recipient in database");
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $dsn = $self->{dsn};
|
||||||
|
my $dbh = DBI->connect($dsn, $self->{user}, $self->{pass});
|
||||||
|
|
||||||
|
if ($dbh->err())
|
||||||
|
{
|
||||||
|
$self->log(LOGERROR, "error connecting to DB: " . $dbh->errstr());
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $sth = $dbh->prepare($self->{sqlquery});
|
||||||
|
if ($sth->err())
|
||||||
|
{
|
||||||
|
$self->log(LOGERROR, "error preparing query: " . $sth->errstr());
|
||||||
|
return DECLINED ;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sth->execute($self->prepareParams($recipient));
|
||||||
|
|
||||||
|
my $ret = DECLINED;
|
||||||
|
|
||||||
|
if ($sth->rows > 0)
|
||||||
|
{
|
||||||
|
$ret = OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# plugin hook called if rcpt_to is issued within the smtp session
|
||||||
|
#
|
||||||
|
sub rcpt_to {
|
||||||
|
my ($self, $transaction, $recipient) = @_;
|
||||||
|
|
||||||
|
# some basic validations
|
||||||
|
return DECLINED unless $recipient->host && $recipient->user;
|
||||||
|
|
||||||
|
# ask the cache for results
|
||||||
|
my $cacheResult = $self->askCache($recipient);
|
||||||
|
return $cacheResult if defined($cacheResult);
|
||||||
|
|
||||||
|
# ask the database for results
|
||||||
|
return $self->askDatabase($recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# called for registering all the hooks
|
||||||
|
#
|
||||||
|
sub register {
|
||||||
|
my ($self, $qp, %args) = @_;
|
||||||
|
|
||||||
|
|
||||||
|
$self->register_hook("rcpt", "rcpt_to");
|
||||||
|
|
||||||
|
}
|
@ -55,6 +55,8 @@
|
|||||||
605 rcpt_ok rok rcpok
|
605 rcpt_ok rok rcpok
|
||||||
608 bogus_bounce bog bogus check_bogus_bounce
|
608 bogus_bounce bog bogus check_bogus_bounce
|
||||||
609 greylisting gry greyl
|
609 greylisting gry greyl
|
||||||
|
610 rcpt_mysql rmy rcmys
|
||||||
|
|
||||||
#
|
#
|
||||||
# Content Filters
|
# Content Filters
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user