From 2f3a326e118eed44d88ef69141fa72cae9c0a1b8 Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Thu, 24 Jan 2008 18:43:34 +0000 Subject: [PATCH] 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) git-svn-id: https://svn.perl.org/qpsmtpd/trunk@836 958fd67b-6ff1-0310-b445-bb7760255be9 --- docs/plugins.pod | 33 +++++++++++++++++++++- lib/Qpsmtpd/Plugin.pm | 2 +- lib/Qpsmtpd/SMTP.pm | 15 ++++++++++ plugins/noop_counter | 65 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 plugins/noop_counter diff --git a/docs/plugins.pod b/docs/plugins.pod index 7c0d8b6..7cf1be1 100644 --- a/docs/plugins.pod +++ b/docs/plugins.pod @@ -1003,7 +1003,7 @@ Arguments are 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 @@ as arguments to the hook =pod +=head2 hook_noop + +If the client sents the B 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 This hook is only available in qpsmtpd-async. diff --git a/lib/Qpsmtpd/Plugin.pm b/lib/Qpsmtpd/Plugin.pm index 413b6fc..577adce 100644 --- a/lib/Qpsmtpd/Plugin.pm +++ b/lib/Qpsmtpd/Plugin.pm @@ -7,7 +7,7 @@ our @hooks = qw( 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 ); diff --git a/lib/Qpsmtpd/SMTP.pm b/lib/Qpsmtpd/SMTP.pm index 12ba5dc..fa11616 100644 --- a/lib/Qpsmtpd/SMTP.pm +++ b/lib/Qpsmtpd/SMTP.pm @@ -502,7 +502,22 @@ sub help_respond { 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 { diff --git a/plugins/noop_counter b/plugins/noop_counter new file mode 100644 index 0000000..8e84ce3 --- /dev/null +++ b/plugins/noop_counter @@ -0,0 +1,65 @@ +# +# +# + +=head1 NAME + +noop_counter - disconnect after too many consecutive NOOPs, example plugin for the hook_noop() + +=head1 DESCRIPTION + +The B counts the number of consecutive C commands given +by a client and disconnects after a given number. + +Any other command than a C resets the counter. + +One argument may be given: the number of Cs 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