I decided to just put together this hack, which works well for my
situation (a very small number of users - my rcptto_patterns file is 66
lines long). Basically it dawned on me that it makes more sense to have
a single file combining white/black lists. The plugin just runs through
the list and returns the SMTP status and response message on a regex
match. It is based on check_badrcptto_patterns and the configuration
file is auto-generated from the script also attached, which is suitable
for a postfixadmin environment.
It's very light for small to mid number of users. Since running this
last night, the load on the machine (small VPS) has dropped
significantly and I no longer run out of qpsmtpd children. It's not the
ideal design, but it serves my purpose and I hope it can be of use to
somebody.
On another note, and this is probably not the right forum, but can
somebody give me some tips on dealing with distributed spams
(50-100/second) from what all seem like dynamic IP addresses, so
probably from spam bots? Qpsmtpd is doing a VERY good job filtering out
the majority primarily via dnsbl and my hacked plugin, but the rate
doesn't seem to be tapering off. Will it eventually die off or am I out
of luck? I am thinking that when this user turned on a catchall address
for his domain awhile back and got hit by a dictionary attack this
started (another good reason to deny it at the SMTP level initially).
Thanks!
Tim
Peter J. Holzer wrote:
On 2007-09-09 15:26:29 -0400, Charlie Brady wrote:
On Sun, 9 Sep 2007, Tim Tsai wrote:
It's silly to keep replying to myself, but here goes. I notice in
smtp-forward this loop:
for ($transaction->recipients) {
$smtp->to($_->address) or return (DECLINED, "To: Unable to queue message
($!)");
}
this seems to suggest that if any one recipient fails, the whole
transaction fails. That seems to be contrary to my experiences with mail
servers. Would it be better for me to count the number of valid
recipients and DECLINED or DENY only if there are no valid recipients at
all?
The right solution to this problem has been discussed here previously -
I know that it has been discussed several times, but I don't agree this
is the right solution.
the smtp-forward plugin should hook into multiple hooks, and pass the
mail_from and rcpt_to data to the back end as it is received, relaying
responses as the back end gives them.
That forces smtp-forward to be the last plugin in the rcpt hook, because
any later plugin could return a 5xx (or worse, a 4xx) error to the
client while the backend has already accepted the recipient.
Since a large percentage of the recipients doesn't exist IME, the check
for existing recipients should be (one of) the first, not the last.
hp
=pod
=head1 SYNOPSIS
This plugin checks the rcptto_patterns config. This allows
special patterns to be denied OR accepted.
=head1 CONFIG
config/rcptto_patterns
Patterns are stored in the format pattern\sresult code\sresponse, where pattern
is a Perl pattern expression. Don't forget to anchor the pattern if
you want to restrict it from matching anywhere in the string.
qpsmtpd already ensures that the address contains an @, with something
to the left and right of the @.
=head1 AUTHOR
Copyright 2005 Gordon Rowell <[EMAIL PROTECTED]>
This software is free software and may be distributed under the same
terms as qpsmtpd itself.
=cut
sub hook_rcpt
{
my ($self, $transaction, $recipient) = @_;
return (DECLINED) if $self->qp->connection->relay_client();
my @badrcptto = $self->qp->config("rcptto_patterns") or return (DECLINED);
my $host = lc $recipient->host;
my $to = lc($recipient->user) . '@' . $host;
for (@badrcptto)
{
my ($pattern, $code, $response) = split /\s+/, $_, 3;
if ($to =~ /$pattern/) {
if ($code == 550) {
return (DENYHARD, $response);
}
return (DECLINED);
}
}
return (DECLINED);
}
#!/bin/sh
USER=postfix
DB=postfix
PASSWD='mypassword'
FILE="/etc/qpsmtpd/debian-rcpthosts"
RCPT="/etc/qpsmtpd/rcptto_patterns"
BUILTIN="domain1.com domain2.com"
BUILTIN_USERS="tim user2 user3"
ALIAS=`mysql -N -u $USER --password=$PASSWD $DB -B -e "SELECT address from
alias where active = 1;"`
MAILBOX=`mysql -N -u $USER --password=$PASSWD $DB -B -e "SELECT username from
mailbox where active = 1;"`
DOMAINS=`mysql -N -u $USER --password=$PASSWD $DB -B -e "SELECT domain from
domain where active = 1;"`
TMPFILE=`tempfile`
for f in `echo $ALIAS $MAILBOX`
do
echo "^$f\$ 0 Ok" >> $TMPFILE
done
for f in `echo $BUILTIN`
do
for u in `echo $BUILTIN_USERS`
do
echo "[EMAIL PROTECTED] 0 Ok" >> $TMPFILE
done
echo "[EMAIL PROTECTED] 500 No mailbox." >> $TMPFILE
done
for f in `echo $DOMAINS`
do
echo "[EMAIL PROTECTED] 500 No mailbox." >> $TMPFILE
done
chmod a+r $TMPFILE
mv $TMPFILE $RCPT
TMPFILE=`tempfile`
for f in `echo $BUILTIN $DOMAINS`
do
echo $f >> $TMPFILE
done
chmod a+r $TMPFILE
mv $TMPFILE $FILE
cat $FILE