Author: vetinari
Date: Thu Jan 24 10:43:34 2008
New Revision: 836

Added:
   trunk/plugins/noop_counter
Modified:
   trunk/docs/plugins.pod
   trunk/lib/Qpsmtpd/Plugin.pm
   trunk/lib/Qpsmtpd/SMTP.pm

Log:
Pluggable hook "noop" with example plugin (noop_counter) and doc update.
... now check_earlytalker can be expanded to VRFY and NOOP (see RFC 1854, #2.1)


Modified: trunk/docs/plugins.pod
==============================================================================
--- trunk/docs/plugins.pod      (original)
+++ trunk/docs/plugins.pod      Thu Jan 24 10:43:34 2008
@@ -1003,7 +1003,7 @@
   my ($self, $transaction, $trace, $hook, $plugin, @log) = @_;
   # $trace: level of message, for example 
   #          LOGWARN, LOGDEBUG, ...
-  # $hook:  the hook in\/for which this logging 
+  # $hook:  the hook in/for which this logging 
   #          was called
   # $plugin: the plugin calling this hook
   # @log:   the log message
@@ -1174,6 +1174,37 @@
 
 =pod
 
+=head2 hook_noop 
+
+If the client sents the B<NOOP> command, this hook is called. Default is to
+return C<250 OK>.
+
+Allowed return codes are:
+
+=over 4
+
+=item DONE
+
+Plugin gave the answer
+
+=item DENY_DISCONNECT
+
+Return error code and disconnect client
+
+=item DENY
+
+Return error code.
+
+=item Anything Else...
+
+Give the default answer of B<250 OK>.
+
+=back
+
+Arguments are
+
+  my ($self,$transaction,@args) = @_;
+
 =head2 hook_post_fork
 
 B<NOTE:> This hook is only available in qpsmtpd-async.

Modified: trunk/lib/Qpsmtpd/Plugin.pm
==============================================================================
--- trunk/lib/Qpsmtpd/Plugin.pm (original)
+++ trunk/lib/Qpsmtpd/Plugin.pm Thu Jan 24 10:43:34 2008
@@ -7,7 +7,7 @@
     logging config pre-connection connect ehlo_parse ehlo
     helo_parse helo auth_parse auth auth-plain auth-login auth-cram-md5
     rcpt_parse rcpt_pre rcpt mail_parse mail mail_pre 
-    data data_post queue_pre queue queue_post vrfy
+    data data_post queue_pre queue queue_post vrfy noop
     quit reset_transaction disconnect post-connection
     unrecognized_command deny ok received_line help
 );

Modified: trunk/lib/Qpsmtpd/SMTP.pm
==============================================================================
--- trunk/lib/Qpsmtpd/SMTP.pm   (original)
+++ trunk/lib/Qpsmtpd/SMTP.pm   Thu Jan 24 10:43:34 2008
@@ -502,7 +502,22 @@
 
 sub noop {
   my $self = shift;
+  $self->run_hooks("noop");
+}
+
+sub noop_respond {
+  my ($self, $rc, $msg, $args) = @_;
+  return 1 if $rc == DONE;
+
+  if ($rc == DENY || $rc == DENY_DISCONNECT) {
+    $msg->[0] ||= "Stop wasting my time."; # FIXME: better default message?
+    $self->respond(500, @$msg);
+    $self->disconnect if $rc == DENY_DISCONNECT;
+    return 1;
+  }
+
   $self->respond(250, "OK");
+  return 1;
 }
 
 sub vrfy {

Added: trunk/plugins/noop_counter
==============================================================================
--- (empty file)
+++ trunk/plugins/noop_counter  Thu Jan 24 10:43:34 2008
@@ -0,0 +1,65 @@
+#
+# 
+#
+
+=head1 NAME
+
+noop_counter - disconnect after too many consecutive NOOPs, example plugin for 
the hook_noop()
+
+=head1 DESCRIPTION
+
+The B<noop_counter> counts the number of consecutive C<NOOP> commands given
+by a client and disconnects after a given number. 
+
+Any other command than a C<NOOP> resets the counter.
+
+One argument may be given: the number of C<NOOP>s after which the client will
+be disconnected.
+
+=head1 NOTE
+
+This plugin should be loaded early to be able to reset the counter on any other
+command.
+
+=cut
+
+sub register {
+    my ($self, $qp, @args) = @_;
+    $self->{_noop_count} = 0;
+    $self->{_max_noop}   = 3;
+    if ($args[0] && $args[0] =~ /^\d+$/) {
+        $self->{_max_noop} = shift @args;
+    }
+}
+
+sub hook_noop {
+    my ($self, $transaction, @args) = @_;
+    ++$self->{_noop_count};
+    ### the following block is not used, RFC 2821 says we SHOULD ignore 
+    ### any arguments... so we MAY return an error if we want to :-) 
+    # return (DENY, "Syntax error, NOOP does not take any arguments")
+    #   if $args[0];
+    
+    if ($self->{_noop_count} >= $self->{_max_noop}) {
+        return (DENY_DISCONNECT, 
+               "Stop wasting my time, too many consecutive NOOPs");
+    }
+    return (DECLINED);
+}
+
+sub reset_noop_counter {
+   $_[0]->{_noop_count} = 0;
+   return (DECLINED);
+}
+
+# and bind the counter reset to the hooks, QUIT not useful here:
+*hook_helo = *hook_ehlo =       # HELO / EHLO
+    *hook_mail =                # MAIL FROM: 
+    *hook_rcpt =                # RCPT TO:
+    *hook_data =                # DATA
+    *hook_reset_transaction =   # RSET
+    *hook_vrfy =                # VRFY
+    *hook_help =                # HELP
+        \&reset_noop_counter;
+
+# vim: ts=4 sw=4 expandtab syn=perl

Reply via email to