reject and reject_type handling for plugins #23

Closed
wants to merge 3 commits into
from
View
@@ -89,7 +89,7 @@ connection before any auth succeeds, defaults to C<0>.
=back
-=head2 Plugin settings
+=head2 Plugin settings files
=over 4
@@ -153,5 +153,48 @@ only currenlty.
=back
+=head2 Plugin settings arguments
+
+These are arguments that can be set on the config/plugins line, after the name
+of the plugin. These config options are available to all plugins.
+
+=over 4
+
+=item loglevel
+
+Adjust the quantity of logging for the plugin. See docs/logging.pod
+
+=item reject
+
+ plugin reject [ 0 | 1 | naughty ]
+
+Should the plugin reject mail?
+
+The special 'naughty' case will mark the connection as a naughty. Most plugins
+skip processing naughty connections. Filtering plugins can learn from them.
+Naughty connections are terminated up by the B<naughty> plugin.
+
+Plugins that use $self->get_reject() or $self->get_reject_type() will
+automatically honor this setting.
+
+=item reject_type
+
+ plugin reject_type [ perm | temp | disconnect | temp_disconnect ]
+
+Default: perm
+
+Values with temp in the name return a 4xx code and the others return a 5xx
+code.
+
+The I<reject_type> argument and the corresponding get_reject_type() method
+provides a standard way for plugins to automatically return the selected
+rejection type, as chosen by the config setting, the plugin author, or the
+get_reject_type() method.
+
+Plugins that are updated to use the $self->get_reject() or
+$self->get_reject_type() methods will automatically honor this setting.
+
+=back
+
=cut
View
@@ -210,6 +210,42 @@ sub compile {
die "eval $@" if $@;
}
+sub get_reject {
+ my $self = shift;
+ my $message = shift || "why didn't you pass an error message?";
+ my $log_info = shift || '';
+ $log_info = ", $log_info" if $log_info;
+
+ my $reject = $self->{_args}{reject};
+ if ( defined $reject && ! $reject ) {
+ $self->log(LOGINFO, 'fail, reject disabled');
+ return DECLINED;
+ };
+
+ # the naughty plugin will reject later
+ if ( $reject eq 'naughty' ) {
+ $self->log(LOGINFO, 'fail, NAUGHTY');
+ $self->connection->notes('naughty', $message);
+ return (DECLINED);
+ };
+
+ # they asked for reject, we give them reject
+ $self->log(LOGINFO, 'fail'.$log_info);
+ return ( $self->get_reject_type(), $message);
+};
+
+sub get_reject_type {
+ my $self = shift;
+ my $default = shift || DENY;
+ my $deny = $self->{_args}{reject_type} or return $default;
+
+ return $deny =~ /^(temp|soft)$/i ? DENYSOFT
+ : $deny =~ /^(perm|hard)$/i ? DENY
+ : $deny eq 'disconnect' ? DENY_DISCONNECT
+ : $deny eq 'temp_disconnect' ? DENYSOFT_DISCONNECT
+ : $default;
+};
+
sub _register_standard_hooks {
my ($plugin, $qp) = @_;
View
@@ -35,9 +35,9 @@ I would be surprised if a valid message ever had a date header older than a week
Determine if the connection is denied. Use the I<reject 0> option when first enabling the plugin, and then watch your logs to see what would have been rejected. When you are no longer concerned that valid messages will be rejected, enable with I<reject 1>.
- check_basicheaders [ reject 0 | 1 ]
+ check_basicheaders reject [ 0 | 1 ]
-Default policy is to reject.
+Default: 1
=head2 reject_type
@@ -47,7 +47,7 @@ Whether to issue a permanent or temporary rejection. The default is permanent.
Using a temporary rejection is a cautious way to enable rejections. It allows an administrator to watch for a trial period and assure no valid messages are rejected. If a deferral of valid mail is noticed, I<reject 0> can be set to permit the deferred message to be delivered.
-Default policy is a permanent rejection.
+Default: perm
=head2 loglevel
@@ -94,40 +94,44 @@ sub register {
$self->{_args}{past} = $self->{_args}{days};
};
};
+# set explicit defaults
+ $self->{_args}{reject_type} ||= 'perm';
+ if ( ! defined $self->{_args}{reject} ) {
+ $self->{_args}{reject} = 1;
+ };
}
sub hook_data_post {
my ($self, $transaction) = @_;
- my $deny = $self->{_args}{reject_type} eq 'temp' ? DENYSOFT : DENY;
- $deny = DECLINED if defined $self->{_args}{reject} && ! $self->{_args}{reject};
+ my $type = $self->get_reject_type();
if ( $transaction->data_size == 0 ) {
$self->log(LOGINFO, "fail: no data");
- return ($deny, "You must send some data first");
+ return ($type, "You must send some data first");
};
my $header = $transaction->header or do {
$self->log(LOGINFO, "fail: no headers");
- return ($deny, "missing header");
+ return ($type, "missing header");
};
return DECLINED if $self->is_immune();
if ( ! $header->get('From') ) {
$self->log(LOGINFO, "fail: no from");
- return ($deny, "We require a valid From header")
+ return ($type, "We require a valid From header");
};
my $date = $header->get('Date') or do {
$self->log(LOGINFO, "fail: no date");
- return ($deny, "We require a valid Date header");
+ return ($type, "We require a valid Date header");
};
chomp $date;
my $err_msg = $self->invalid_date_range($date);
if ( $err_msg ) {
- return ($deny, $err_msg );
+ return ($type, $err_msg );
};
return (DECLINED);