Skip to content
This repository

Naughty #24

Closed
wants to merge 16 commits into from

1 participant

Matt Simerson
Matt Simerson
Collaborator

naughty - dispose of naughty connections

Rather than immediately terminating naughty connections, plugins often mark
the connections and dispose of them later. Examples are B, B,
B, B and B.

Disconnecting later is inefficient because other plugins continue to do their
work, oblivious to the fact that the connection is destined for the bit bucket.

Naughty provides plugins with an efficient way to offer late disconnects. It
does this by allowing other plugins to detect that a connection is naughty.
For efficiency, other plugins should skip processing naughty connections.
Plugins like SpamAssassin and DSPAM can benefit from using naughty connections
to train their filters.

Instead of each plugin handling cleanup, B does it. Set I to
the hook you prefer to reject in and B will reject the naughty
connections, regardless of who identified them, exactly when you choose.

Matt Simerson msimerson closed this August 05, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
2  config.sample/flat_auth_pw
... ...
@@ -1,2 +1,4 @@
  1
+# used by plugins/auth/auth_flat_file
  2
+# example entries
1 3
 good@example.com:good_pass
2 4
 bad@example.com:bad_pass
4  config.sample/plugins
@@ -45,6 +45,10 @@ check_spamhelo
45 45
 # sender_permitted_from
46 46
 # greylisting p0f genre,windows
47 47
 
  48
+#auth/auth_checkpassword checkpw /usr/local/vpopmail/bin/vchkpw true /usr/bin/true
  49
+#auth/auth_vpopmail
  50
+#auth/auth_vpopmaild
  51
+#auth/auth_vpopmail_sql
48 52
 auth/auth_flat_file
49 53
 auth/authdeny
50 54
 
1  config.sample/smtpauth-checkpassword
... ...
@@ -0,0 +1 @@
  1
+/usr/local/vpopmail/bin/vchkpw /bin/true
4  lib/Qpsmtpd/Auth.pm
@@ -57,6 +57,10 @@ sub SASL {
57 57
             ( $msg ? " - $msg" : '');
58 58
         $session->respond( 235, $msg );
59 59
         $session->connection->relay_client(1);
  60
+        if ( $session->connection->notes('naughty' ) ) {
  61
+            $session->log( LOGINFO, "auth success cleared naughty" );
  62
+            $session->connection->notes('naughty',0);
  63
+        };
60 64
         $session->log( LOGDEBUG, $msg );  # already logged by $session->respond
61 65
 
62 66
         $session->{_auth_user} = $user;
1  plugins/auth/auth_checkpassword
@@ -124,6 +124,7 @@ sub auth_checkpassword {
124 124
 
125 125
     my $binary = $self->connection->notes('auth_checkpassword_bin');
126 126
     my $true = $self->connection->notes('auth_checkpassword_true');
  127
+    chomp ($binary, $true);
127 128
 
128 129
     my $sudo = get_sudo($binary);
129 130
 
4  plugins/auth/auth_vpopmail
@@ -45,7 +45,7 @@ use warnings;
45 45
 use Qpsmtpd::Auth;
46 46
 use Qpsmtpd::Constants;
47 47
 
48  
-#use vpopmail;    # we eval this in $test_vpopmail
  48
+#use vpopmail;    # we eval this in $test_vpopmail_module
49 49
 
50 50
 sub register {
51 51
     my ($self, $qp) = @_;
@@ -86,7 +86,7 @@ sub test_vpopmail_module {
86 86
     my $self = shift;
87 87
 # vpopmail will not allow vauth_getpw to succeed unless the requesting user is vpopmail or root.
88 88
 # by default, qpsmtpd runs as the user 'qpsmtpd' and does not have permission.
89  
-    eval "use vpopmail";
  89
+    eval 'use vpopmail';
90 90
     if ( $@ ) {
91 91
         $self->log(LOGERROR, "skip: is vpopmail perl module installed?");
92 92
         return;
9  plugins/auth/auth_vpopmail_sql
@@ -69,11 +69,18 @@ use warnings;
69 69
 use Qpsmtpd::Auth;
70 70
 use Qpsmtpd::Constants;
71 71
 
72  
-use DBI;
  72
+#use DBI;  # done in ->register
73 73
 
74 74
 sub register {
75 75
     my ( $self, $qp ) = @_;
76 76
 
  77
+    eval 'use DBI';
  78
+    if ( $@ ) {
  79
+        warn "plugin disabled. is DBI installed?\n";
  80
+        $self->log(LOGERROR, "skip: plugin disabled. is DBI installed?\n");
  81
+        return;
  82
+    };
  83
+
77 84
     $self->register_hook('auth-plain',    'auth_vmysql');
78 85
     $self->register_hook('auth-login',    'auth_vmysql');
79 86
     $self->register_hook('auth-cram-md5', 'auth_vmysql');
44  plugins/check_badmailfrom
@@ -17,6 +17,20 @@ listed in badmailfrom. A line in badmailfrom may be of the form
17 17
 You may include an optional message after the sender address (leave a space),
18 18
 to be used when rejecting the sender.
19 19
 
  20
+=head1 CONFIGURATION
  21
+
  22
+=head2 reject
  23
+
  24
+  badmailfrom reject [ 0 | 1 | naughty ]
  25
+
  26
+I<0> will not reject any connections.
  27
+
  28
+I<1> will reject naughty senders.
  29
+
  30
+I<connect> is the most efficient setting. It's also the default.
  31
+
  32
+To reject at any other connection hook, use the I<naughty> setting and the
  33
+B<naughty> plugin.
20 34
 
21 35
 =head1 PATTERNS
22 36
 
@@ -42,14 +56,27 @@ stage, so store it until later.
42 56
 
43 57
 =head1 AUTHORS
44 58
 
45  
-initial author of badmailfrom - Jim Winstead
  59
+2002 - Jim Winstead - initial author of badmailfrom
46 60
 
47  
-pattern matching plugin - Johan Almqvist <johan-qpsmtpd@almqvist.net>
  61
+2010 - Johan Almqvist <johan-qpsmtpd@almqvist.net> - pattern matching plugin
48 62
 
49  
-merging of the two and plugin tests - Matt Simerson <matt@tnpi.net>
  63
+2012 - Matt Simerson - merging of the two and plugin tests
50 64
 
51 65
 =cut
52 66
 
  67
+sub register {
  68
+    my ($self,$qp) = shift, shift;
  69
+    $self->{_args} = { @_ };
  70
+
  71
+    # preserve legacy "reject during rcpt" behavior
  72
+    $self->{_args}{reject} = 1 if ! defined $self->{_args}{reject};
  73
+
  74
+    return if ! $self->{_args}{reject};               # reject 0, log only
  75
+    return if   $self->{_args}{reject} eq 'naughty';  # naughty will reject
  76
+
  77
+    $self->register_hook('rcpt', 'rcpt_handler');
  78
+};
  79
+
53 80
 sub hook_mail {
54 81
     my ($self, $transaction, $sender, %param) = @_;
55 82
 
@@ -69,8 +96,11 @@ sub hook_mail {
69 96
         next unless $bad;
70 97
         next unless $self->is_match( $from, $bad, $host );
71 98
         $reason ||= "Your envelope sender is in my badmailfrom list";
72  
-        $transaction->notes('badmailfrom', $reason);
  99
+        $self->connection->notes('naughty', $reason);
73 100
     }
  101
+    if ( ! $self->connection->notes('naughty') ) {
  102
+        $self->log(LOGINFO, "pass");
  103
+    };
74 104
     return DECLINED;
75 105
 }
76 106
 
@@ -96,11 +126,11 @@ sub is_match {
96 126
     return 1;
97 127
 };
98 128
 
99  
-sub hook_rcpt {
  129
+sub rcpt_handler {
100 130
     my ($self, $transaction, $rcpt, %param) = @_;
101  
-    my $note = $transaction->notes('badmailfrom') or return (DECLINED);
  131
+    my $note = $self->connection->notes('naughty') or return (DECLINED);
102 132
 
103  
-    $self->log(LOGINFO, $note);
  133
+    $self->log(LOGINFO, "fail, $note");
104 134
     return (DENY, $note);
105 135
 }
106 136
 
161  plugins/naughty
... ...
@@ -0,0 +1,161 @@
  1
+#!perl -w
  2
+
  3
+=head1 NAME
  4
+
  5
+naughty - dispose of naughty connections
  6
+
  7
+=head1 BACKGROUND
  8
+
  9
+Rather than immediately terminating naughty connections, plugins often mark
  10
+the connections and dispose of them later. Examples are B<dnsbl>, B<karma>, 
  11
+B<greylisting>, B<resolvable_fromhost> and B<SPF>. 
  12
+
  13
+This practice is based on RFC standards and the belief that malware will retry
  14
+less if we disconnect after RCPT. This may have been true, and may still be,
  15
+but my observations in 2012 suggest it makes no measurable difference whether
  16
+I disconnect during connect or rcpt.
  17
+
  18
+Disconnecting later is inefficient because other plugins continue to do their
  19
+work, oblivious to the fact that the connection is destined for the bit bucket.
  20
+
  21
+=head1 DESCRIPTION
  22
+
  23
+Naughty provides the following:
  24
+
  25
+=head2 efficiency
  26
+
  27
+Naughty provides plugins with an efficient way to offer late disconnects. It
  28
+does this by allowing other plugins to detect that a connection is naughty.
  29
+For efficiency, other plugins should skip processing naughty connections.
  30
+Plugins like SpamAssassin and DSPAM can benefit from using naughty connections
  31
+to train their filters.
  32
+
  33
+Since so many connections are from blacklisted IPs, naughty significantly
  34
+reduces the processing time required for disposing of them. Over 80% of my
  35
+connections are disposed of after after a few DNS queries (B<dnsbl> or one DB
  36
+query (B<karma>) and 0.01s of compute time.
  37
+
  38
+=head2 naughty cleanup
  39
+
  40
+Instead of each plugin handling cleanup, B<naughty> does it. Set I<reject> to
  41
+the hook you prefer to reject in and B<naughty> will reject the naughty
  42
+connections, regardless of who identified them, exactly when you choose.
  43
+
  44
+=head2 simplicity
  45
+
  46
+Rather than having plugins split processing across hooks, they can run to
  47
+completion when they have the information they need, issue a 
  48
+I<reject naughty> if warranted, and be done.
  49
+
  50
+This may help reduce the code divergence between the sync and async
  51
+deployment models.
  52
+
  53
+=head2 authentication
  54
+
  55
+When a user authenticates, the naughty flag on their connection is cleared.
  56
+This is to allow users to send email from IPs that fail connection tests such
  57
+as B<dnsbl>. Keep in mind that if I<reject connect> is set, connections will
  58
+not get the chance to authenticate.
  59
+
  60
+=head2 naughty
  61
+
  62
+<naughty> provides a a consistent way for plugins to mark connections as
  63
+naughty. Set the connection note I<naughty> to the message you wish to send
  64
+the naughty sender during rejection.
  65
+
  66
+   $self->connection->notes('naughty', $message);
  67
+
  68
+This happens for plugins automatically if they use the $self->get_reject()
  69
+method and have set I<reject naughty> in the plugin configuration.
  70
+
  71
+=head1 CONFIGURATION
  72
+
  73
+=head2 reject
  74
+
  75
+  naughty reject [ connect | mail | rcpt | data | data_post ]
  76
+
  77
+The phase of the connection in which the naughty connection will be terminated.
  78
+Keep in mind that if you choose rcpt and a plugin (like B<rcpt_ok>) runs first,
  79
+and B<rcpt_ok> returns OK, then this plugin will not get called and the
  80
+message will not get rejected.
  81
+
  82
+Solutions are to make sure B<naughty> is listed before rcpt_ok in config/plugins
  83
+or set naughty to run in a phase after the one you wish to complete.
  84
+In this case, use data instead of rcpt to disconnect after rcpt_ok. The latter
  85
+is particularly useful if your rcpt plugins skip naughty testing. In that case,
  86
+any recipient is accepted for naughty connections, which prevents spammers
  87
+from detecting address validity.
  88
+
  89
+=head2 reject_type [ temp | perm | disconnect ]
  90
+
  91
+What type of rejection should be sent? See docs/config.pod
  92
+
  93
+=head2 loglevel
  94
+
  95
+Adjust the quantity of logging for this plugin. See docs/logging.pod
  96
+
  97
+=head1 EXAMPLES
  98
+
  99
+Here's how to use naughty and get_reject in your plugin:
  100
+
  101
+ sub register {
  102
+    my ($self,$qp) = shift, shift;
  103
+    $self->{_args} = { @_ };
  104
+    $self->{_args}{reject} ||= 'naughty';
  105
+ };
  106
+
  107
+ sub connect_handler {
  108
+     my ($self, $transaction) = @_;
  109
+     ... do a bunch of stuff ...
  110
+     return DECLINED if is_okay();
  111
+     return $self->get_reject( $message );
  112
+ };
  113
+
  114
+=head1 AUTHOR
  115
+
  116
+ 2012 - Matt Simerson - msimerson@cpan.org
  117
+
  118
+=cut
  119
+
  120
+use strict;
  121
+use warnings;
  122
+
  123
+use Qpsmtpd::Constants;
  124
+
  125
+sub register {
  126
+    my ($self, $qp ) = shift, shift;
  127
+    $self->log(LOGERROR, "Bad arguments") if @_ % 2;
  128
+    $self->{_args} = { @_ };
  129
+    $self->{_args}{reject} ||= 'rcpt';
  130
+    $self->{_args}{reject_type} ||= 'disconnect';
  131
+
  132
+    my $reject = lc $self->{_args}{reject};
  133
+    my %hooks  = map { $_ => 1 } 
  134
+        qw/ connect mail rcpt data data_post hook_queue_post /;
  135
+
  136
+    if ( ! $hooks{$reject} ) {
  137
+        $self->log( LOGERROR, "fail, invalid hook $reject" );
  138
+        $self->register_hook( 'data_post', 'naughty');
  139
+        return;
  140
+    };
  141
+
  142
+    # just in case naughty doesn't disconnect, which can happen if a plugin
  143
+    # with the same hook returned OK before naughty ran, or ....
  144
+    if ( $reject ne 'data_post' && $reject ne 'hook_queue_post' ) {
  145
+        $self->register_hook( 'data_post', 'naughty');
  146
+    };
  147
+
  148
+    $self->log(LOGDEBUG, "registering hook $reject");
  149
+    $self->register_hook( $reject, 'naughty');
  150
+}
  151
+
  152
+sub naughty {
  153
+    my $self = shift;
  154
+    my $naughty = $self->connection->notes('naughty') or do {
  155
+        $self->log(LOGINFO, "pass, clean");
  156
+        return DECLINED;
  157
+    };
  158
+    $self->log(LOGINFO, "disconnecting");
  159
+    return ( $self->get_reject_type(), $naughty );
  160
+};
  161
+
1  t/Test/Qpsmtpd.pm
@@ -69,6 +69,7 @@ sub input {
69 69
 }
70 70
 
71 71
 sub config_dir {
  72
+    return './t/config' if $ENV{QPSMTPD_DEVELOPER};
72 73
     './config.sample';
73 74
 }
74 75
 
4  t/Test/Qpsmtpd/Plugin.pm
@@ -5,8 +5,10 @@ package Test::Qpsmtpd::Plugin;
5 5
 package Qpsmtpd::Plugin;
6 6
 
7 7
 use strict;
8  
-use Test::More;
  8
+use warnings;
  9
+
9 10
 use Qpsmtpd::Constants;
  11
+use Test::More;
10 12
 
11 13
 sub register_tests {
12 14
     # Virtual base method - implement in plugin
15  t/config.t
@@ -5,12 +5,17 @@ use strict;
5 5
 use lib 't';
6 6
 use_ok('Test::Qpsmtpd');
7 7
 
  8
+my @mes;
  9
+
8 10
 BEGIN { # need this to happen before anything else
9 11
     my $cwd = `pwd`;
10 12
     chomp($cwd);
11  
-    open my $me_config, '>', "./config.sample/me";
12  
-    print $me_config "some.host.example.org";
13  
-    close $me_config;
  13
+    @mes = qw{ ./config.sample/me ./t/config/me };
  14
+    foreach my $f ( @mes ) {
  15
+        open my $me_config, '>', $f;
  16
+        print $me_config "some.host.example.org";
  17
+        close $me_config;
  18
+    };
14 19
 }
15 20
 
16 21
 ok(my ($smtpd, $conn) = Test::Qpsmtpd->new_conn(), "get new connection");
@@ -22,6 +27,8 @@ is($smtpd->config('me'), 'some.host.example.org', 'config("me")');
22 27
 my $relayclients = join ",", sort $smtpd->config('relayclients');
23 28
 is($relayclients, '127.0.0.1,192.168.', 'config("relayclients") are trimmed');
24 29
 
25  
-unlink "./config.sample/me";
  30
+foreach my $f ( @mes ) {
  31
+    unlink $f if -f $f;
  32
+};
26 33
 
27 34
 
4  t/config/badhelo
... ...
@@ -0,0 +1,4 @@
  1
+# these domains never uses their domain when greeting us, so reject transactions
  2
+aol.com
  3
+yahoo.com
  4
+
9  t/config/badrcptto
... ...
@@ -0,0 +1,9 @@
  1
+######## entries used for testing ###
  2
+bad@example.com
  3
+@bad.example.com
  4
+########    Example patterns   #######
  5
+# Format is pattern\s+Response
  6
+# Don't forget to anchor the pattern if required
  7
+!       Sorry, bang paths not accepted here
  8
+@.*@    Sorry, multiple at signs not accepted here
  9
+%       Sorry, percent hack not accepted here 
1  t/config/dnsbl_zones
... ...
@@ -0,0 +1 @@
  1
+zen.spamhaus.org
2  t/config/flat_auth_pw
... ...
@@ -0,0 +1,2 @@
  1
+good@example.com:good_pass
  2
+bad@example.com:bad_pass
6  t/config/invalid_resolvable_fromhost
... ...
@@ -0,0 +1,6 @@
  1
+# include full network block including mask
  2
+127.0.0.0/8 
  3
+0.0.0.0/8 
  4
+224.0.0.0/4
  5
+169.254.0.0/16 
  6
+10.0.0.0/8 
94  t/config/plugins
... ...
@@ -0,0 +1,94 @@
  1
+#
  2
+#  Example configuration file for plugins
  3
+#
  4
+
  5
+# enable this to get configuration via http; see perldoc
  6
+# plugins/http_config for details.
  7
+#   http_config http://localhost/~smtpd/config/  http://www.example.com/smtp.pl?config=
  8
+
  9
+# hosts_allow does not work with the tcpserver deployment model!
  10
+#   perldoc plugins/hosts_allow for an alternative.
  11
+#
  12
+# The hosts_allow module must be loaded if you want the -m / --max-from-ip /
  13
+# my $MAXCONNIP = 5; # max simultaneous connections from one IP
  14
+# settings... without this it will NOT refuse more than $MAXCONNIP connections
  15
+# from one IP!
  16
+hosts_allow
  17
+
  18
+# information plugins
  19
+ident/geoip
  20
+#ident/p0f /tmp/.p0f_socket version 3
  21
+connection_time
  22
+
  23
+# enable to accept MAIL FROM:/RCPT TO: addresses without surrounding <>
  24
+dont_require_anglebrackets
  25
+
  26
+# enable to reject MAIL FROM:/RCPT TO: parameters if client helo was HELO
  27
+# (strict RFC 821)... this is not used in EHLO ...
  28
+parse_addr_withhelo
  29
+
  30
+quit_fortune
  31
+# tls should load before count_unrecognized_commands
  32
+#tls
  33
+check_earlytalker
  34
+count_unrecognized_commands 4
  35
+check_relay
  36
+
  37
+require_resolvable_fromhost
  38
+
  39
+rhsbl
  40
+dnsbl
  41
+check_badmailfrom
  42
+check_badrcptto
  43
+check_spamhelo
  44
+
  45
+sender_permitted_from
  46
+greylisting p0f genre,windows
  47
+
  48
+auth/auth_checkpassword checkpw /usr/local/vpopmail/bin/vchkpw true /usr/bin/true
  49
+auth/auth_vpopmail
  50
+auth/auth_vpopmaild
  51
+auth/auth_vpopmail_sql
  52
+auth/auth_flat_file
  53
+auth/authdeny
  54
+
  55
+# this plugin needs to run after all other "rcpt" plugins
  56
+rcpt_ok
  57
+
  58
+check_basicheaders days 5 reject_type temp
  59
+domainkeys
  60
+
  61
+# content filters
  62
+virus/klez_filter
  63
+
  64
+
  65
+# You can run the spamassassin plugin with options.  See perldoc
  66
+# plugins/spamassassin for details.
  67
+#
  68
+spamassassin
  69
+
  70
+# rejects mails with a SA score higher than 20 and munges the subject
  71
+# of the score is higher than 10.
  72
+#
  73
+#   spamassassin reject_threshold 20 munge_subject_threshold 10
  74
+
  75
+# dspam must run after spamassassin for the learn_from_sa feature to work
  76
+dspam learn_from_sa 7 reject 1
  77
+
  78
+# run the clamav virus checking plugin
  79
+virus/clamav
  80
+
  81
+# You must enable a queue plugin - see the options in plugins/queue/ - for example:
  82
+
  83
+# queue to a maildir
  84
+# queue/maildir /home/spamtrap/mail
  85
+
  86
+# queue the mail with qmail-queue
  87
+queue/qmail-queue
  88
+
  89
+
  90
+# If you need to run the same plugin multiple times, you can do
  91
+# something like the following
  92
+#    check_relay
  93
+#    check_relay:0 somearg
  94
+#    check_relay:1 someotherarg
1  t/config/rcpthosts
... ...
@@ -0,0 +1 @@
  1
+localhost
5  t/config/relayclients
... ...
@@ -0,0 +1,5 @@
  1
+# Format is IP, or IP part with trailing dot
  2
+# e.g. "127.0.0.1", or "192.168."
  3
+127.0.0.1 
  4
+# leading/trailing whitespace is ignored
  5
+ 192.168. 
8  t/plugin_tests.t
@@ -7,3 +7,11 @@ my $qp = Test::Qpsmtpd->new();
7 7
 
8 8
 $qp->run_plugin_tests();
9 9
 
  10
+foreach my $file ( 
  11
+        "./t/config/greylist.dbm",
  12
+        "./t/config/greylist.dbm.lock"
  13
+        ) {
  14
+    next if ! -f $file;
  15
+    unlink $file;
  16
+};
  17
+
2  t/plugin_tests/auth/auth_vpopmail
@@ -23,7 +23,7 @@ sub test_auth_vpopmail {
23 23
 
24 24
     if ( ! $self->test_vpopmail_module ) {
25 25
         warn "vpopmail plugin not configured\n";
26  
-        foreach ( 0..2) { ok( 1, "test_auth_vpopmail, skipped") };
  26
+        foreach ( 0..2) { ok( 1, "skipped") };
27 27
         return;
28 28
     };
29 29
 
13  t/plugin_tests/auth/auth_vpopmail_sql
@@ -6,6 +6,11 @@ use warnings;
6 6
 sub register_tests {
7 7
     my $self = shift;
8 8
 
  9
+    eval 'use DBI';
  10
+    if ( $@ ) {
  11
+        warn "skipping auth_vpopmail_sql tests, is DBI installed?\n";
  12
+        return;
  13
+    };
9 14
     $self->register_test("auth_vpopmail_sql", 3);
10 15
 }
11 16
 
@@ -15,7 +20,7 @@ sub auth_vpopmail_sql {
15 20
 
16 21
     my $dbh = $self->get_db_handle() or do {
17 22
             foreach ( 0..2 ) {
18  
-                ok( 1, "auth_vpopmail_sql, skipped (no DB)" );
  23
+                ok( 1, "skipped (no DB)" );
19 24
             };
20 25
             return;
21 26
         };
@@ -24,11 +29,11 @@ sub auth_vpopmail_sql {
24 29
     my $vuser = $self->get_vpopmail_user( $dbh, 'postmaster@example.com' );
25 30
     if ( ! $vuser || ! $vuser->{pw_passwd} ) {
26 31
         foreach ( 0..1 ) {
27  
-            ok( 1, "auth_vpopmail_sql, no example.com domain" );
  32
+            ok( 1, "no example.com domain" );
28 33
         };
29 34
         return;
30 35
     };
31  
-    ok( ref $vuser, "auth_vpopmail_sql, found example.com domain" );
  36
+    ok( ref $vuser, "found example.com domain" );
32 37
 
33 38
     ok( $self->auth_vmysql(
34 39
             $self->qp->transaction,
@@ -38,6 +43,6 @@ sub auth_vpopmail_sql {
38 43
             $vuser->{pw_passwd},
39 44
             $ticket,
40 45
         ),
41  
-        "auth_vpopmail_sql, postmaster"
  46
+        "postmaster"
42 47
     );
43 48
 }
17  t/plugin_tests/check_badmailfrom
@@ -11,7 +11,7 @@ sub register_tests {
11 11
     $self->register_test("test_badmailfrom_is_immune", 5);
12 12
     $self->register_test("test_badmailfrom_match", 7);
13 13
     $self->register_test("test_badmailfrom_hook_mail", 4);
14  
-    $self->register_test("test_badmailfrom_hook_rcpt", 2);
  14
+    $self->register_test("test_badmailfrom_rcpt_handler", 2);
15 15
 }
16 16
 
17 17
 sub test_badmailfrom_is_immune {
@@ -50,29 +50,26 @@ sub test_badmailfrom_hook_mail {
50 50
     $transaction->sender($address);
51 51
 
52 52
     $self->{_badmailfrom_config} = ['matt@test.net','matt@test.com'];
53  
-    $transaction->notes('badmailfrom', '');
  53
+    $self->connection->notes('badmailfrom', '');
54 54
     my ($r) = $self->hook_mail( $transaction, $address );
55 55
     ok( $r == 909, "badmailfrom hook_mail");
56  
-    ok( $transaction->notes('badmailfrom') eq 'Your envelope sender is in my badmailfrom list', 
57  
-        "badmailfrom hook_mail: default reason");
  56
+    cmp_ok( $self->connection->notes('naughty'), 'eq', 'Your envelope sender is in my badmailfrom list', "default reason");
58 57
 
59 58
     $self->{_badmailfrom_config} = ['matt@test.net','matt@test.com Yer a spammin bastert'];
60  
-    $transaction->notes('badmailfrom', '');
  59
+    $self->connection->notes('badmailfrom', '');
61 60
     ($r) = $self->hook_mail( $transaction, $address );
62 61
     ok( $r == 909, "badmailfrom hook_mail");
63  
-    ok( $transaction->notes('badmailfrom') eq 'Yer a spammin bastert', 
64  
-        "badmailfrom hook_mail: custom reason");
65  
-
  62
+    cmp_ok( $self->connection->notes('naughty'), 'eq', 'Yer a spammin bastert', "custom reason");
66 63
 };
67 64
 
68  
-sub test_badmailfrom_hook_rcpt {
  65
+sub test_badmailfrom_rcpt_handler {
69 66
     my $self = shift;
70 67
 
71 68
     my $transaction = $self->qp->transaction;
72 69
 
73 70
     $transaction->notes('badmailfrom', 'Yer a spammin bastart. Be gon wit yuh.' );
74 71
 
75  
-    my ($code,$note) = $self->hook_rcpt( $transaction );
  72
+    my ($code,$note) = $self->rcpt_handler( $transaction );
76 73
 
77 74
     ok( $code == 901, 'badmailfrom hook hit');
78 75
     ok( $note, $note );
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.