Hello,

I've been hanging around on this newsgroup for a couple of months, but never contributed. I'm from a consulting company at Spain (CAPSiDE), and we are studying on implementing qpsmtpd in a couple of projects. Currently we are beta-testing it, and like it very much. Please note that we don't have any production qpsmtp server, so I can't try out what I will describe below.

        On the list, I saw that Johan Almqvist said that:
------------
The most noteworthy change is that the number of earlytalkers has decreased by an order of magnitude.
------------

I saw that Hanno Hecker responded:
------------
Depending on what your earlytalker parameters are... there's a shift to longer wait times on the clients. In the beginning most early talkers just started to talk... most have changed to a higher wait time now. Try raising wait time if you can afford and see again. My earlytalkers have a 1:5-1:10 ratio of "talk immediately" / "wait some seconds", depending on server ("immediately": < 1.0 second).
------------

It looks like spammers are learning, and that they wait to pipe all the message, adapting to earlytalker filters, making you have to upper the wait on the helo. Is this intuition correct?

Working on a tarpit plugin, I realized that if the SMTP server sleeps for each RCPT TO, the spammers can pipe all the mail through without waiting for the 200, making the tarpit very ineffective. Why not look if the client has transmitted something while the 200 response was delayed (much like earlytalking, but between commands), and cut the connection if it has talked. I have an initial draft of a tarpitting plugin, but I am not detecting the early chatting after the sleep.

I think this could be a good thing, because we would be making spammers talk SMTP, without piping the message after waiting a while. We have not seen this functionality in any plugin, so CAPSiDE is contributing this tarpit module to the project. It ramps up the sleep following: ('delay' * extra RCPT after on_count has been reached) seconds. Maybe someone wants to chip in the earlytalking code and try it out in production.

Maybe the linear delay approach after the nth SMTP command is not all that good. Maybe wait a fixed number of seconds on each rcpt to (so we catch them on the first command), and then ramp up after the nth RCPT TO.

Hope it helps. I'm open to corrections and comments on the subject. You guys have a better inside view on these topics.

Jose Luis Martinez Torres
[EMAIL PROTECTED]
CAPSiDE
# -*- perl -*-
=head1 NAME

tarpit - tarpitting for qpsmtpd

=head1 DESCRIPTION

Delays each RCPT TO command

=head1 NOTES


=cut

sub register {
  my ($self, $qp, @args) = @_;

  if (@args % 2) {
        $self->log(LOGERROR, "Unrecognized/mismatched arguments");
        return undef;
  }
  $self->{_args} = {
                'on_count' => 10,
                'delay' => 2,
        @args
  };
  
  $qp->log( LOGINFO, sprintf('tarpitting module initialized with on_count %s 
and delay %s',
                             $self->{_args}->{'on_count'},
                             $self->{_args}->{'delay'})
  );
                             
}

sub hook_rcpt {
  my ($self, $transaction, $recipient, %param) = @_;

  #TODO: Do not tarpit relay AUTHorized clients
  
  my $rcount = $transaction->notes('tarpit.rcpt_count');
  
  if (not defined $rcount) { 
    $rcount = 1;
  } else {
    $rcount++;
  }

  # save the recipient count
  $transaction->notes('tarpit.rcpt_count', $rcount);
  
  $self->log( LOGDEBUG, sprintf('tarpit rcpt count: %d', $rcount) );
  
  my $left_to_tarpit = $self->{'_args'}->{'on_count'} - $rcount;
  
  if ($left_to_tarpit > 0) {
    return (DECLINED);
  } else {
    if ($left_to_tarpit == 0) {
      $transaction->log( LOGINFO, sprintf('starting to tarpit sender %s from IP 
%s',
                                          $transaction->sender,
                                          $self->qp->connection->remote_ip)
      );
    }

    # when left_to_tarpit enters the negative range, we can use it's absolute
    # value as a multiplier for the sleep.
    $left_to_tarpit = abs($left_to_tarpit);

    my $sleep = ($left_to_tarpit + 1) * $self->{_args}->{'delay'};

    # don't trigger an unnecessary sleep if it's not needed.
    if ($sleep != 0) {
      $transaction->log( LOGINFO, sprintf('tarpit for %d seconds', $sleep) );
      sleep($sleep);
    }   
  }
  
  return (DECLINED);
}

Reply via email to