Filename | /usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Plugin/VBounce.pm |
Statements | Executed 25 statements in 1.67ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 67µs | 269µs | new | Mail::SpamAssassin::Plugin::VBounce::
1 | 1 | 1 | 36µs | 36µs | BEGIN@30 | Mail::SpamAssassin::Plugin::VBounce::
1 | 1 | 1 | 28µs | 134µs | set_config | Mail::SpamAssassin::Plugin::VBounce::
1 | 1 | 1 | 23µs | 33µs | BEGIN@32 | Mail::SpamAssassin::Plugin::VBounce::
1 | 1 | 1 | 22µs | 181µs | BEGIN@31 | Mail::SpamAssassin::Plugin::VBounce::
1 | 1 | 1 | 22µs | 52µs | BEGIN@33 | Mail::SpamAssassin::Plugin::VBounce::
1 | 1 | 1 | 19µs | 80µs | BEGIN@34 | Mail::SpamAssassin::Plugin::VBounce::
0 | 0 | 0 | 0s | 0s | _relay_is_in_list | Mail::SpamAssassin::Plugin::VBounce::
0 | 0 | 0 | 0s | 0s | _relay_is_in_whitelist_bounce_relays | Mail::SpamAssassin::Plugin::VBounce::
0 | 0 | 0 | 0s | 0s | check_whitelist_bounce_relays | Mail::SpamAssassin::Plugin::VBounce::
0 | 0 | 0 | 0s | 0s | have_any_bounce_relays | Mail::SpamAssassin::Plugin::VBounce::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # <@LICENSE> | ||||
2 | # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
3 | # contributor license agreements. See the NOTICE file distributed with | ||||
4 | # this work for additional information regarding copyright ownership. | ||||
5 | # The ASF licenses this file to you under the Apache License, Version 2.0 | ||||
6 | # (the "License"); you may not use this file except in compliance with | ||||
7 | # the License. You may obtain a copy of the License at: | ||||
8 | # | ||||
9 | # http://www.apache.org/licenses/LICENSE-2.0 | ||||
10 | # | ||||
11 | # Unless required by applicable law or agreed to in writing, software | ||||
12 | # distributed under the License is distributed on an "AS IS" BASIS, | ||||
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
14 | # See the License for the specific language governing permissions and | ||||
15 | # limitations under the License. | ||||
16 | # </@LICENSE> | ||||
17 | |||||
18 | =head1 NAME | ||||
19 | |||||
20 | Mail::SpamAssassin::Plugin::VBounce - aid in rescuing genuine bounces | ||||
21 | |||||
22 | =head1 SYNOPSIS | ||||
23 | |||||
24 | loadplugin Mail::SpamAssassin::Plugin::VBounce [/path/to/VBounce.pm] | ||||
25 | |||||
26 | =cut | ||||
27 | |||||
28 | package Mail::SpamAssassin::Plugin::VBounce; | ||||
29 | |||||
30 | 2 | 64µs | 1 | 36µs | # spent 36µs within Mail::SpamAssassin::Plugin::VBounce::BEGIN@30 which was called:
# once (36µs+0s) by Mail::SpamAssassin::PluginHandler::load_plugin at line 30 # spent 36µs making 1 call to Mail::SpamAssassin::Plugin::VBounce::BEGIN@30 |
31 | 2 | 57µs | 2 | 341µs | # spent 181µs (22+159) within Mail::SpamAssassin::Plugin::VBounce::BEGIN@31 which was called:
# once (22µs+159µs) by Mail::SpamAssassin::PluginHandler::load_plugin at line 31 # spent 181µs making 1 call to Mail::SpamAssassin::Plugin::VBounce::BEGIN@31
# spent 159µs making 1 call to Exporter::import |
32 | 2 | 63µs | 2 | 43µs | # spent 33µs (23+10) within Mail::SpamAssassin::Plugin::VBounce::BEGIN@32 which was called:
# once (23µs+10µs) by Mail::SpamAssassin::PluginHandler::load_plugin at line 32 # spent 33µs making 1 call to Mail::SpamAssassin::Plugin::VBounce::BEGIN@32
# spent 10µs making 1 call to strict::import |
33 | 2 | 57µs | 2 | 83µs | # spent 52µs (22+30) within Mail::SpamAssassin::Plugin::VBounce::BEGIN@33 which was called:
# once (22µs+30µs) by Mail::SpamAssassin::PluginHandler::load_plugin at line 33 # spent 52µs making 1 call to Mail::SpamAssassin::Plugin::VBounce::BEGIN@33
# spent 30µs making 1 call to warnings::import |
34 | 2 | 1.33ms | 2 | 141µs | # spent 80µs (19+61) within Mail::SpamAssassin::Plugin::VBounce::BEGIN@34 which was called:
# once (19µs+61µs) by Mail::SpamAssassin::PluginHandler::load_plugin at line 34 # spent 80µs making 1 call to Mail::SpamAssassin::Plugin::VBounce::BEGIN@34
# spent 61µs making 1 call to re::import |
35 | |||||
36 | 1 | 13µs | our @ISA = qw(Mail::SpamAssassin::Plugin); | ||
37 | |||||
38 | # spent 269µs (67+202) within Mail::SpamAssassin::Plugin::VBounce::new which was called:
# once (67µs+202µs) by Mail::SpamAssassin::PluginHandler::load_plugin at line 1 of (eval 107)[Mail/SpamAssassin/PluginHandler.pm:129] | ||||
39 | 1 | 2µs | my $class = shift; | ||
40 | 1 | 2µs | my $mailsaobject = shift; | ||
41 | |||||
42 | 1 | 2µs | $class = ref($class) || $class; | ||
43 | 1 | 10µs | 1 | 19µs | my $self = $class->SUPER::new($mailsaobject); # spent 19µs making 1 call to Mail::SpamAssassin::Plugin::new |
44 | 1 | 2µs | bless ($self, $class); | ||
45 | |||||
46 | 1 | 10µs | 1 | 30µs | $self->register_eval_rule("have_any_bounce_relays"); # spent 30µs making 1 call to Mail::SpamAssassin::Plugin::register_eval_rule |
47 | 1 | 6µs | 1 | 20µs | $self->register_eval_rule("check_whitelist_bounce_relays"); # spent 20µs making 1 call to Mail::SpamAssassin::Plugin::register_eval_rule |
48 | |||||
49 | 1 | 10µs | 1 | 134µs | $self->set_config($mailsaobject->{conf}); # spent 134µs making 1 call to Mail::SpamAssassin::Plugin::VBounce::set_config |
50 | |||||
51 | 1 | 10µs | return $self; | ||
52 | } | ||||
53 | |||||
54 | # spent 134µs (28+106) within Mail::SpamAssassin::Plugin::VBounce::set_config which was called:
# once (28µs+106µs) by Mail::SpamAssassin::Plugin::VBounce::new at line 49 | ||||
55 | 1 | 2µs | my($self, $conf) = @_; | ||
56 | 1 | 2µs | my @cmds; | ||
57 | |||||
58 | =head1 USER PREFERENCES | ||||
59 | |||||
60 | The following options can be used in both site-wide (C<local.cf>) and | ||||
61 | user-specific (C<user_prefs>) configuration files to customize how | ||||
62 | SpamAssassin handles incoming email messages. | ||||
63 | |||||
64 | =over 4 | ||||
65 | |||||
66 | =item whitelist_bounce_relays hostname [hostname2 ...] | ||||
67 | |||||
68 | This is used to 'rescue' legitimate bounce messages that were generated in | ||||
69 | response to mail you really *did* send. List the MTA relays that your outbound | ||||
70 | mail is delivered through. If a bounce message is found, and it contains one | ||||
71 | of these hostnames in a 'Received' header, it will not be marked as a blowback | ||||
72 | virus-bounce. | ||||
73 | |||||
74 | The hostnames can be file-glob-style patterns, so C<relay*.isp.com> will work. | ||||
75 | Specifically, C<*> and C<?> are allowed, but all other metacharacters are not. | ||||
76 | Regular expressions are not used for security reasons. | ||||
77 | |||||
78 | Multiple addresses per line, separated by spaces, is OK. Multiple | ||||
79 | C<whitelist_bounce_relays> lines are also OK. | ||||
80 | |||||
81 | =back | ||||
82 | |||||
83 | =cut | ||||
84 | |||||
85 | 1 | 5µs | push (@cmds, { | ||
86 | setting => 'whitelist_bounce_relays', | ||||
87 | type => $Mail::SpamAssassin::Conf::CONF_TYPE_ADDRLIST | ||||
88 | }); | ||||
89 | |||||
90 | 1 | 17µs | 1 | 106µs | $conf->{parser}->register_commands(\@cmds); # spent 106µs making 1 call to Mail::SpamAssassin::Conf::Parser::register_commands |
91 | } | ||||
92 | |||||
93 | sub have_any_bounce_relays { | ||||
94 | my ($self, $pms) = @_; | ||||
95 | return $pms->{conf}->{whitelist_bounce_relays} && | ||||
96 | %{$pms->{conf}->{whitelist_bounce_relays}} ? 1 : 0; | ||||
97 | } | ||||
98 | |||||
99 | sub check_whitelist_bounce_relays { | ||||
100 | my ($self, $pms) = @_; | ||||
101 | |||||
102 | return 0 if !$self->have_any_bounce_relays($pms); | ||||
103 | |||||
104 | my $body = $pms->get_decoded_stripped_body_text_array(); | ||||
105 | my $res; | ||||
106 | |||||
107 | # catch lines like: | ||||
108 | # Received: by dogma.boxhost.net (Postfix, from userid 1007) | ||||
109 | |||||
110 | # check the plain-text body, first | ||||
111 | foreach my $line (@{$body}) { | ||||
112 | next unless ($line =~ /^[> ]*Received:/i); | ||||
113 | while ($line =~ / (\S+\.\S+) /g) { | ||||
114 | return 1 if $self->_relay_is_in_whitelist_bounce_relays($pms, $1); | ||||
115 | } | ||||
116 | } | ||||
117 | |||||
118 | # now check any "message/anything" attachment MIME parts, too. | ||||
119 | # don't use the more efficient find_parts() method until bug 5331 is | ||||
120 | # fixed, otherwise we'll miss some messages due to their MIME structure | ||||
121 | |||||
122 | my $pristine = $pms->{msg}->get_pristine_body(); | ||||
123 | |||||
124 | # triage, avoids expensive loop through large mail with attachments | ||||
125 | return 0 if $pristine !~ /Received:/i; | ||||
126 | |||||
127 | my $found_received = 0; | ||||
128 | my $fullhdr = ''; | ||||
129 | foreach my $line ($pristine =~ /^(.*)$/gm) { | ||||
130 | if (!defined $line) { return 0; } | ||||
131 | |||||
132 | # don't bother until we see a line with "Received:" in it | ||||
133 | if (!$found_received) { | ||||
134 | next unless ($line =~ /^[> ]*Received:/i); | ||||
135 | $found_received = 1; | ||||
136 | } | ||||
137 | |||||
138 | if ($line =~ /^\s/) { # bug 5912, deal with multiline | ||||
139 | $fullhdr .= $line; | ||||
140 | } else { | ||||
141 | $fullhdr = $line; | ||||
142 | } | ||||
143 | |||||
144 | next unless ($fullhdr =~ /^[> ]*Received:/i); | ||||
145 | while ($fullhdr =~ /\s(\S+\.\S+)\s/gs) { | ||||
146 | return 1 if $self->_relay_is_in_whitelist_bounce_relays($pms, $1); | ||||
147 | } | ||||
148 | } | ||||
149 | |||||
150 | return 0; | ||||
151 | } | ||||
152 | |||||
153 | sub _relay_is_in_whitelist_bounce_relays { | ||||
154 | my ($self, $pms, $relay) = @_; | ||||
155 | return 1 if $self->_relay_is_in_list( | ||||
156 | $pms->{conf}->{whitelist_bounce_relays}, $pms, $relay); | ||||
157 | dbg("rules: relay $relay doesn't match any whitelist"); | ||||
158 | |||||
159 | return 0; | ||||
160 | } | ||||
161 | |||||
162 | sub _relay_is_in_list { | ||||
163 | my ($self, $list, $pms, $relay) = @_; | ||||
164 | $relay = lc $relay; | ||||
165 | |||||
166 | if (defined $list->{$relay}) { return 1; } | ||||
167 | |||||
168 | foreach my $regexp (values %{$list}) { | ||||
169 | if ($relay =~ qr/$regexp/i) { | ||||
170 | dbg("rules: relay $relay matches regexp: $regexp"); | ||||
171 | return 1; | ||||
172 | } | ||||
173 | } | ||||
174 | |||||
175 | return 0; | ||||
176 | } | ||||
177 | |||||
178 | 1 | 8µs | 1; |