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

Reply via email to