← Index
NYTProf Performance Profile   « line view »
For /usr/local/bin/sa-learn
  Run on Sun Nov 5 02:36:06 2017
Reported on Sun Nov 5 02:56:19 2017

Filename/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Dns.pm
StatementsExecuted 29083 statements in 283ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
242451711.12s1.12sMail::SpamAssassin::PerMsgStatus::::CORE:match Mail::SpamAssassin::PerMsgStatus::CORE:match (opcode)
842621202ms260msMail::SpamAssassin::PerMsgStatus::::register_async_rule_start Mail::SpamAssassin::PerMsgStatus::register_async_rule_start
1181617188.4ms88.4msMail::SpamAssassin::PerMsgStatus::::CORE:subst Mail::SpamAssassin::PerMsgStatus::CORE:subst (opcode)
131226128.0ms28.0msMail::SpamAssassin::PerMsgStatus::::CORE:regcomp Mail::SpamAssassin::PerMsgStatus::CORE:regcomp (opcode)
4682215.7ms29.7msMail::SpamAssassin::PerMsgStatus::::is_dns_available Mail::SpamAssassin::PerMsgStatus::is_dns_available
11110.1ms38.7msMail::SpamAssassin::PerMsgStatus::::BEGIN@35 Mail::SpamAssassin::PerMsgStatus::BEGIN@35
1872417.93ms7.93msMail::SpamAssassin::PerMsgStatus::::CORE:qr Mail::SpamAssassin::PerMsgStatus::CORE:qr (opcode)
1114.11ms151msMail::SpamAssassin::PerMsgStatus::::BEGIN@74 Mail::SpamAssassin::PerMsgStatus::BEGIN@74
11164µs72µsMail::SpamAssassin::PerMsgStatus::::clear_resolver Mail::SpamAssassin::PerMsgStatus::clear_resolver
11141µs48µsMail::SpamAssassin::Message::Metadata::::BEGIN@18Mail::SpamAssassin::Message::Metadata::BEGIN@18
11135µs40µsMail::SpamAssassin::PerMsgStatus::::BEGIN@25 Mail::SpamAssassin::PerMsgStatus::BEGIN@25
11134µs91µsMail::SpamAssassin::PerMsgStatus::::BEGIN@86 Mail::SpamAssassin::PerMsgStatus::BEGIN@86
11132µs38µsMail::SpamAssassin::PerMsgStatus::::BEGIN@23 Mail::SpamAssassin::PerMsgStatus::BEGIN@23
11130µs746µsMail::SpamAssassin::PerMsgStatus::::BEGIN@36 Mail::SpamAssassin::PerMsgStatus::BEGIN@36
11126µs188µsMail::SpamAssassin::PerMsgStatus::::BEGIN@32 Mail::SpamAssassin::PerMsgStatus::BEGIN@32
11125µs251µsMail::SpamAssassin::PerMsgStatus::::BEGIN@38 Mail::SpamAssassin::PerMsgStatus::BEGIN@38
11123µs2.28msMail::SpamAssassin::PerMsgStatus::::load_resolver Mail::SpamAssassin::PerMsgStatus::load_resolver
11122µs114µsMail::SpamAssassin::PerMsgStatus::::BEGIN@26 Mail::SpamAssassin::PerMsgStatus::BEGIN@26
11121µs21µsMail::SpamAssassin::PerMsgStatus::::BEGIN@34 Mail::SpamAssassin::PerMsgStatus::BEGIN@34
11119µs622µsMail::SpamAssassin::PerMsgStatus::::BEGIN@31 Mail::SpamAssassin::PerMsgStatus::BEGIN@31
11119µs49µsMail::SpamAssassin::PerMsgStatus::::BEGIN@24 Mail::SpamAssassin::PerMsgStatus::BEGIN@24
11119µs19µsMail::SpamAssassin::PerMsgStatus::::BEGIN@28 Mail::SpamAssassin::PerMsgStatus::BEGIN@28
11118µs18µsMail::SpamAssassin::PerMsgStatus::::BEGIN@30 Mail::SpamAssassin::PerMsgStatus::BEGIN@30
11112µs12µsMail::SpamAssassin::PerMsgStatus::::BEGIN@29 Mail::SpamAssassin::PerMsgStatus::BEGIN@29
0000s0sMail::SpamAssassin::PerMsgStatus::::__ANON__[:120] Mail::SpamAssassin::PerMsgStatus::__ANON__[:120]
0000s0sMail::SpamAssassin::PerMsgStatus::::__ANON__[:160] Mail::SpamAssassin::PerMsgStatus::__ANON__[:160]
0000s0sMail::SpamAssassin::PerMsgStatus::::check_for_from_dns Mail::SpamAssassin::PerMsgStatus::check_for_from_dns
0000s0sMail::SpamAssassin::PerMsgStatus::::cleanup_kids Mail::SpamAssassin::PerMsgStatus::cleanup_kids
0000s0sMail::SpamAssassin::PerMsgStatus::::dnsbl_hit Mail::SpamAssassin::PerMsgStatus::dnsbl_hit
0000s0sMail::SpamAssassin::PerMsgStatus::::dnsbl_uri Mail::SpamAssassin::PerMsgStatus::dnsbl_uri
0000s0sMail::SpamAssassin::PerMsgStatus::::do_dns_lookup Mail::SpamAssassin::PerMsgStatus::do_dns_lookup
0000s0sMail::SpamAssassin::PerMsgStatus::::do_rbl_lookup Mail::SpamAssassin::PerMsgStatus::do_rbl_lookup
0000s0sMail::SpamAssassin::PerMsgStatus::::enter_helper_run_mode Mail::SpamAssassin::PerMsgStatus::enter_helper_run_mode
0000s0sMail::SpamAssassin::PerMsgStatus::::harvest_completed_queries Mail::SpamAssassin::PerMsgStatus::harvest_completed_queries
0000s0sMail::SpamAssassin::PerMsgStatus::::harvest_dnsbl_queries Mail::SpamAssassin::PerMsgStatus::harvest_dnsbl_queries
0000s0sMail::SpamAssassin::PerMsgStatus::::harvest_until_rule_completes Mail::SpamAssassin::PerMsgStatus::harvest_until_rule_completes
0000s0sMail::SpamAssassin::PerMsgStatus::::is_rule_complete Mail::SpamAssassin::PerMsgStatus::is_rule_complete
0000s0sMail::SpamAssassin::PerMsgStatus::::leave_helper_run_mode Mail::SpamAssassin::PerMsgStatus::leave_helper_run_mode
0000s0sMail::SpamAssassin::PerMsgStatus::::lookup_ns Mail::SpamAssassin::PerMsgStatus::lookup_ns
0000s0sMail::SpamAssassin::PerMsgStatus::::mark_all_async_rules_complete Mail::SpamAssassin::PerMsgStatus::mark_all_async_rules_complete
0000s0sMail::SpamAssassin::PerMsgStatus::::process_dnsbl_result Mail::SpamAssassin::PerMsgStatus::process_dnsbl_result
0000s0sMail::SpamAssassin::PerMsgStatus::::process_dnsbl_set Mail::SpamAssassin::PerMsgStatus::process_dnsbl_set
0000s0sMail::SpamAssassin::PerMsgStatus::::rbl_finish Mail::SpamAssassin::PerMsgStatus::rbl_finish
0000s0sMail::SpamAssassin::PerMsgStatus::::register_async_rule_finish Mail::SpamAssassin::PerMsgStatus::register_async_rule_finish
0000s0sMail::SpamAssassin::PerMsgStatus::::register_rbl_subtest Mail::SpamAssassin::PerMsgStatus::register_rbl_subtest
0000s0sMail::SpamAssassin::PerMsgStatus::::server_failed_to_respond_for_domain Mail::SpamAssassin::PerMsgStatus::server_failed_to_respond_for_domain
0000s0sMail::SpamAssassin::PerMsgStatus::::set_rbl_tag_data Mail::SpamAssassin::PerMsgStatus::set_rbl_tag_data
0000s0sMail::SpamAssassin::PerMsgStatus::::set_server_failed_to_respond_for_domain Mail::SpamAssassin::PerMsgStatus::set_server_failed_to_respond_for_domain
Call graph for these subroutines as a Graphviz dot language file.
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
182102µs256µs
# spent 48µs (41+7) within Mail::SpamAssassin::Message::Metadata::BEGIN@18 which was called: # once (41µs+7µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 18
use strict; # make Test::Perl::Critic happy
# spent 48µs making 1 call to Mail::SpamAssassin::Message::Metadata::BEGIN@18 # spent 8µs making 1 call to strict::import
19package Mail::SpamAssassin::Dns; 1;
20
21package Mail::SpamAssassin::PerMsgStatus;
22
23274µs244µs
# spent 38µs (32+6) within Mail::SpamAssassin::PerMsgStatus::BEGIN@23 which was called: # once (32µs+6µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 23
use strict;
# spent 38µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@23 # spent 6µs making 1 call to strict::import
24276µs279µs
# spent 49µs (19+30) within Mail::SpamAssassin::PerMsgStatus::BEGIN@24 which was called: # once (19µs+30µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 24
use warnings;
# spent 49µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@24 # spent 30µs making 1 call to warnings::import
25263µs244µs
# spent 40µs (35+5) within Mail::SpamAssassin::PerMsgStatus::BEGIN@25 which was called: # once (35µs+5µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 25
use bytes;
# spent 40µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@25 # spent 5µs making 1 call to bytes::import
26270µs2206µs
# spent 114µs (22+92) within Mail::SpamAssassin::PerMsgStatus::BEGIN@26 which was called: # once (22µs+92µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 26
use re 'taint';
# spent 114µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@26 # spent 92µs making 1 call to re::import
27
28256µs119µs
# spent 19µs within Mail::SpamAssassin::PerMsgStatus::BEGIN@28 which was called: # once (19µs+0s) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 28
use Mail::SpamAssassin::Conf;
# spent 19µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@28
29264µs112µs
# spent 12µs within Mail::SpamAssassin::PerMsgStatus::BEGIN@29 which was called: # once (12µs+0s) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 29
use Mail::SpamAssassin::PerMsgStatus;
# spent 12µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@29
30265µs118µs
# spent 18µs within Mail::SpamAssassin::PerMsgStatus::BEGIN@30 which was called: # once (18µs+0s) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 30
use Mail::SpamAssassin::AsyncLoop;
# spent 18µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@30
31275µs21.22ms
# spent 622µs (19+603) within Mail::SpamAssassin::PerMsgStatus::BEGIN@31 which was called: # once (19µs+603µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 31
use Mail::SpamAssassin::Constants qw(:ip);
# spent 622µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@31 # spent 603µs making 1 call to Exporter::import
32275µs2349µs
# spent 188µs (26+162) within Mail::SpamAssassin::PerMsgStatus::BEGIN@32 which was called: # once (26µs+162µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 32
use Mail::SpamAssassin::Util qw(untaint_var am_running_on_windows);
# spent 188µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@32 # spent 162µs making 1 call to Exporter::import
33
34280µs121µs
# spent 21µs within Mail::SpamAssassin::PerMsgStatus::BEGIN@34 which was called: # once (21µs+0s) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 34
use File::Spec;
# spent 21µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@34
352374µs243.9ms
# spent 38.7ms (10.1+28.7) within Mail::SpamAssassin::PerMsgStatus::BEGIN@35 which was called: # once (10.1ms+28.7ms) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 35
use IO::Socket;
# spent 38.7ms making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@35 # spent 5.11ms making 1 call to IO::Socket::import
36297µs21.46ms
# spent 746µs (30+716) within Mail::SpamAssassin::PerMsgStatus::BEGIN@36 which was called: # once (30µs+716µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 36
use POSIX ":sys_wait_h";
# spent 746µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@36 # spent 716µs making 1 call to POSIX::import
37
3812µs
# spent 251µs (25+226) within Mail::SpamAssassin::PerMsgStatus::BEGIN@38 which was called: # once (25µs+226µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 40
use vars qw{
39 $KNOWN_BAD_DIALUP_RANGES @EXISTING_DOMAINS $IS_DNS_AVAILABLE $LAST_DNS_CHECK
401195µs2476µs};
# spent 251µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@38 # spent 226µs making 1 call to vars::import
41
42# use very well-connected domains (fast DNS response, many DNS servers,
43# geographical distribution is a plus, TTL of at least 3600s)
44110µs@EXISTING_DOMAINS = qw{
45 adelphia.net
46 akamai.com
47 apache.org
48 cingular.com
49 colorado.edu
50 comcast.net
51 doubleclick.com
52 ebay.com
53 gmx.net
54 google.com
55 intel.com
56 kernel.org
57 linux.org
58 mit.edu
59 motorola.com
60 msn.com
61 sourceforge.net
62 sun.com
63 w3.org
64 yahoo.com
65};
66
6712µs$IS_DNS_AVAILABLE = undef;
68
69#Removed $VERSION per BUG 6422
70#$VERSION = 'bogus'; # avoid CPAN.pm picking up razor ver
71
72###########################################################################
73
74
# spent 151ms (4.11+147) within Mail::SpamAssassin::PerMsgStatus::BEGIN@74 which was called: # once (4.11ms+147ms) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 97
BEGIN {
75 # some trickery. Load these modules right here, if possible; that way, if
76 # the module exists, we'll get it loaded now. Very useful to avoid attempted
77 # loads later (which will happen). If we do a fork(), we could wind up
78 # attempting to load these modules in *every* subprocess.
79 #
80# # We turn off strict and warnings, because Net::DNS and Razor both contain
81# # crud that -w complains about (perl 5.6.0). Not that this seems to work,
82# # mind ;)
83# no strict;
84# local ($^W) = 0;
85
862139µs2149µs
# spent 91µs (34+58) within Mail::SpamAssassin::PerMsgStatus::BEGIN@86 which was called: # once (34µs+58µs) by Mail::SpamAssassin::Message::Metadata::BEGIN@49 at line 86
no warnings;
# spent 91µs making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@86 # spent 58µs making 1 call to warnings::unimport
8717µs eval {
881322µs require Net::DNS;
8913µs require Net::DNS::Resolver;
90 };
9114µs eval {
9214µs require MIME::Base64;
93 };
94116µs eval {
9513µs require IO::Socket::UNIX;
96 };
9717.05ms1151ms};
# spent 151ms making 1 call to Mail::SpamAssassin::PerMsgStatus::BEGIN@74
98
99###########################################################################
100
101sub do_rbl_lookup {
102 my ($self, $rule, $set, $type, $host, $subtest) = @_;
103
104 $host =~ s/\.\z//s; # strip a redundant trailing dot
105 my $key = "dns:$type:$host";
106 my $existing_ent = $self->{async}->get_lookup($key);
107
108 # only make a specific query once
109 if (!$existing_ent) {
110 my $ent = {
111 key => $key,
112 zone => $host, # serves to fetch other per-zone settings
113 type => "DNSBL-".$type,
114 sets => [ ], # filled in below
115 rules => [ ], # filled in below
116 # id is filled in after we send the query below
117 };
118 $existing_ent = $self->{async}->bgsend_and_start_lookup(
119 $host, $type, undef, $ent,
120 sub { my($ent, $pkt) = @_; $self->process_dnsbl_result($ent, $pkt) },
121 master_deadline => $self->{master_deadline} );
122 }
123
124 if ($existing_ent) {
125 # always add set
126 push @{$existing_ent->{sets}}, $set;
127
128 # sometimes match or always match
129 if (defined $subtest) {
130 $self->{dnspost}->{$set}->{$subtest} = $rule;
131 } else {
132 push @{$existing_ent->{rules}}, $rule;
133 }
134
135 $self->{rule_to_rblkey}->{$rule} = $key;
136 }
137}
138
139# TODO: these are constant so they should only be added once at startup
140sub register_rbl_subtest {
141 my ($self, $rule, $set, $subtest) = @_;
142 $self->{dnspost}->{$set}->{$subtest} = $rule;
143}
144
145sub do_dns_lookup {
146 my ($self, $rule, $type, $host) = @_;
147
148 $host =~ s/\.\z//s; # strip a redundant trailing dot
149 my $key = "dns:$type:$host";
150
151 my $ent = {
152 key => $key,
153 zone => $host, # serves to fetch other per-zone settings
154 type => "DNSBL-".$type,
155 rules => [ $rule ],
156 # id is filled in after we send the query below
157 };
158 $ent = $self->{async}->bgsend_and_start_lookup(
159 $host, $type, undef, $ent,
160 sub { my($ent, $pkt) = @_; $self->process_dnsbl_result($ent, $pkt) },
161 master_deadline => $self->{master_deadline} );
162 $ent;
163}
164
165###########################################################################
166
167sub dnsbl_hit {
168 my ($self, $rule, $question, $answer) = @_;
169
170 my $log = "";
171 if (substr($rule, 0, 2) eq "__") {
172 # don't bother with meta rules
173 } elsif ($answer->type eq 'TXT') {
174 # txtdata returns a non- zone-file-format encoded result, unlike rdatastr;
175 # avoid space-separated RDATA <character-string> fields if possible,
176 # txtdata provides a list of strings in a list context since Net::DNS 0.69
177 $log = join('',$answer->txtdata);
178 local $1;
179 $log =~ s{ (?<! [<(\[] ) (https? : // \S+)}{<$1>}xgi;
180 } else { # assuming $answer->type eq 'A'
181 local($1,$2,$3,$4,$5);
182 if ($question->string =~ m/^((?:[0-9a-fA-F]\.){32})(\S+\w)/) {
183 $log = ' listed in ' . lc($2);
184 my $ipv6addr = join('', reverse split(/\./, lc $1));
185 $ipv6addr =~ s/\G(....)/$1:/g; chop $ipv6addr;
186 $ipv6addr =~ s/:0{1,3}/:/g;
187 $log = $ipv6addr . $log;
188 } elsif ($question->string =~ m/^(\d+)\.(\d+)\.(\d+)\.(\d+)\.(\S+\w)/) {
189 $log = "$4.$3.$2.$1 listed in " . lc($5);
190 } else {
191 $log = 'listed in ' . $question->string;
192 }
193 }
194
195 # TODO: this may result in some log messages appearing under the
196 # wrong rules, since we could see this sequence: { test one hits,
197 # test one's message is logged, test two hits, test one fires again
198 # on another IP, test one's message is logged for that other IP --
199 # but under test two's heading }. Right now though it's better
200 # than just not logging at all.
201
202 $self->{already_logged} ||= { };
203 if ($log && !$self->{already_logged}->{$log}) {
204 $self->test_log($log);
205 $self->{already_logged}->{$log} = 1;
206 }
207
208 if (!$self->{tests_already_hit}->{$rule}) {
209 $self->got_hit($rule, "RBL: ", ruletype => "dnsbl");
210 }
211}
212
213sub dnsbl_uri {
214 my ($self, $question, $answer) = @_;
215
216 my $qname = $question->qname;
217
218 # txtdata returns a non- zone-file-format encoded result, unlike rdatastr;
219 # avoid space-separated RDATA <character-string> fields if possible,
220 # txtdata provides a list of strings in a list context since Net::DNS 0.69
221 #
222 my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? join('',$answer->txtdata)
223 : $answer->rdatastr;
224 if (defined $qname && defined $rdatastr) {
225 my $qclass = $question->qclass;
226 my $qtype = $question->qtype;
227 my @vals;
228 push(@vals, "class=$qclass") if $qclass ne "IN";
229 push(@vals, "type=$qtype") if $qtype ne "A";
230 my $uri = "dns:$qname" . (@vals ? "?" . join(";", @vals) : "");
231 push @{ $self->{dnsuri}->{$uri} }, $rdatastr;
232
233 dbg("dns: hit <$uri> $rdatastr");
234 }
235}
236
237# called as a completion routine to bgsend by DnsResolver::poll_responses;
238# returns 1 on successful packet processing
239sub process_dnsbl_result {
240 my ($self, $ent, $pkt) = @_;
241
242 return if !$pkt;
243 my $question = ($pkt->question)[0];
244 return if !$question;
245
246 my $sets = $ent->{sets} || [];
247 my $rules = $ent->{rules};
248
249 # NO_DNS_FOR_FROM
250 if ($self->{sender_host} &&
251 # fishy, qname should have been "RFC 1035 zone format" -decoded first
252 lc($question->qname) eq lc($self->{sender_host}) &&
253 $question->qtype =~ /^(?:A|MX)$/ &&
254 $pkt->header->rcode =~ /^(?:NXDOMAIN|SERVFAIL)$/ &&
255 ++$self->{sender_host_fail} == 2)
256 {
257 for my $rule (@{$rules}) {
258 $self->got_hit($rule, "DNS: ", ruletype => "dns");
259 }
260 }
261
262 # DNSBL tests are here
263 foreach my $answer ($pkt->answer) {
264 next if !$answer;
265 # track all responses
266 $self->dnsbl_uri($question, $answer);
267 my $answ_type = $answer->type;
268 # TODO: there are some CNAME returns that might be useful
269 next if ($answ_type ne 'A' && $answ_type ne 'TXT');
270 # skip any A record that isn't on 127/8
271 next if ($answ_type eq 'A' && $answer->rdatastr !~ /^127\./);
272 for my $rule (@{$rules}) {
273 $self->dnsbl_hit($rule, $question, $answer);
274 }
275 for my $set (@{$sets}) {
276 if ($self->{dnspost}->{$set}) {
277 $self->process_dnsbl_set($set, $question, $answer);
278 }
279 }
280 }
281 return 1;
282}
283
284sub process_dnsbl_set {
285 my ($self, $set, $question, $answer) = @_;
286
287 # txtdata returns a non- zone-file-format encoded result, unlike rdatastr;
288 # avoid space-separated RDATA <character-string> fields if possible,
289 # txtdata provides a list of strings in a list context since Net::DNS 0.69
290 #
291 my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? join('',$answer->txtdata)
292 : $answer->rdatastr;
293
294 while (my ($subtest, $rule) = each %{ $self->{dnspost}->{$set} }) {
295 next if $self->{tests_already_hit}->{$rule};
296
297 if ($subtest =~ /^\d+\.\d+\.\d+\.\d+$/) {
298 # test for exact equality, not a regexp (an IPv4 address)
299 $self->dnsbl_hit($rule, $question, $answer) if $subtest eq $rdatastr;
300 }
301 # senderbase
302 elsif ($subtest =~ s/^sb://) {
303 # SB rules are not available to users
304 if ($self->{conf}->{user_defined_rules}->{$rule}) {
305 dbg("dns: skipping rule '$rule': not supported when user-defined");
306 next;
307 }
308
309 $rdatastr =~ s/^\d+-//;
310 my %sb = ($rdatastr =~ m/(?:^|\|)(\d+)=([^|]+)/g);
311 my $undef = 0;
312 while ($subtest =~ m/\bS(\d+)\b/g) {
313 if (!defined $sb{$1}) {
314 $undef = 1;
315 last;
316 }
317 $subtest =~ s/\bS(\d+)\b/\$sb{$1}/;
318 }
319
320 # untaint. (bug 3325)
321 $subtest = untaint_var($subtest);
322
323 $self->got_hit($rule, "SenderBase: ", ruletype => "dnsbl") if !$undef && eval $subtest;
324 }
325 # bitmask
326 elsif ($subtest =~ /^\d+$/) {
327 # Bug 6803: response should be within 127.0.0.0/8, ignore otherwise
328 if ($rdatastr =~ m/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ &&
329 Mail::SpamAssassin::Util::my_inet_aton($rdatastr) & $subtest)
330 {
331 $self->dnsbl_hit($rule, $question, $answer);
332 }
333 }
334 # regular expression
335 else {
336 my $test = qr/$subtest/;
337 if ($rdatastr =~ /$test/) {
338 $self->dnsbl_hit($rule, $question, $answer);
339 }
340 }
341 }
342}
343
344sub harvest_until_rule_completes {
345 my ($self, $rule) = @_;
346
347 dbg("dns: harvest_until_rule_completes");
348 my $result = 0;
349
350 for (my $first=1; ; $first=0) {
351 # complete_lookups() may call completed_callback(), which may
352 # call start_lookup() again (like in Plugin::URIDNSBL)
353 my ($alldone,$anydone) =
354 $self->{async}->complete_lookups($first ? 0 : 1.0, 1);
355
356 $result = 1 if $self->is_rule_complete($rule);
357 last if $result || $alldone;
358
359 dbg("dns: harvest_until_rule_completes - check_tick");
360 $self->{main}->call_plugins ("check_tick", { permsgstatus => $self });
361 }
362
363 return $result;
364}
365
366sub harvest_dnsbl_queries {
367 my ($self) = @_;
368
369 dbg("dns: harvest_dnsbl_queries");
370
371 for (my $first=1; ; $first=0) {
372 # complete_lookups() may call completed_callback(), which may
373 # call start_lookup() again (like in Plugin::URIDNSBL)
374
375 # the first time around we specify a 0 timeout, which gives
376 # complete_lookups a chance to ripe any available results and
377 # abort overdue requests, without needlessly waiting for more
378
379 my ($alldone,$anydone) =
380 $self->{async}->complete_lookups($first ? 0 : 1.0, 1);
381
382 last if $alldone;
383
384 dbg("dns: harvest_dnsbl_queries - check_tick");
385 $self->{main}->call_plugins ("check_tick", { permsgstatus => $self });
386 }
387
388 # explicitly abort anything left
389 $self->{async}->abort_remaining_lookups();
390 $self->{async}->log_lookups_timing();
391 $self->mark_all_async_rules_complete();
392 1;
393}
394
395# collect and process whatever DNS responses have already arrived,
396# don't waste time waiting for more, don't poll too often.
397# don't abort any queries even if overdue,
398sub harvest_completed_queries {
399 my ($self) = @_;
400
401 # don't bother collecting responses too often
402 my $last_poll_time = $self->{async}->last_poll_responses_time();
403 return if defined $last_poll_time && time - $last_poll_time < 0.1;
404
405 my ($alldone,$anydone) = $self->{async}->complete_lookups(0, 0);
406 if ($anydone) {
407 dbg("dns: harvested completed queries");
408# $self->{main}->call_plugins ("check_tick", { permsgstatus => $self });
409 }
410}
411
412sub set_rbl_tag_data {
413 my ($self) = @_;
414
415 # DNS URIs
416 my $rbl_tag = $self->{tag_data}->{RBL}; # just in case, should be empty
417 $rbl_tag = '' if !defined $rbl_tag;
418 while (my ($dnsuri, $answers) = each %{ $self->{dnsuri} }) {
419 # when parsing, look for elements of \".*?\" or \S+ with ", " as separator
420 $rbl_tag .= "<$dnsuri>" . " [" . join(", ", @{ $answers }) . "]\n";
421 }
422 if (defined $rbl_tag && $rbl_tag ne '') {
423 chomp $rbl_tag;
424 $self->set_tag('RBL', $rbl_tag);
425 }
426}
427
428###########################################################################
429
430sub rbl_finish {
431 my ($self) = @_;
432
433 $self->set_rbl_tag_data();
434
435 delete $self->{dnspost};
436 delete $self->{dnsuri};
437}
438
439###########################################################################
440
441
# spent 2.28ms (23µs+2.26) within Mail::SpamAssassin::PerMsgStatus::load_resolver which was called: # once (23µs+2.26ms) by Mail::SpamAssassin::PerMsgStatus::is_dns_available at line 529
sub load_resolver {
44212µs my ($self) = @_;
44314µs $self->{resolver} = $self->{main}->{resolver};
444117µs12.26ms return $self->{resolver}->load_resolver();
# spent 2.26ms making 1 call to Mail::SpamAssassin::DnsResolver::load_resolver
445}
446
447
# spent 72µs (64+8) within Mail::SpamAssassin::PerMsgStatus::clear_resolver which was called: # once (64µs+8µs) by Mail::SpamAssassin::PerMsgStatus::is_dns_available at line 528
sub clear_resolver {
44812µs my ($self) = @_;
449114µs18µs dbg("dns: clear_resolver");
# spent 8µs making 1 call to Mail::SpamAssassin::Logger::dbg
450135µs $self->{main}->{resolver}->{res} = undef;
451111µs return 0;
452}
453
454sub lookup_ns {
455 my ($self, $dom) = @_;
456
457 return unless $self->load_resolver();
458 return if ($self->server_failed_to_respond_for_domain ($dom));
459
460 my $nsrecords;
461 dbg("dns: looking up NS for '$dom'");
462
463 eval {
464 my $query = $self->{resolver}->send($dom, 'NS');
465 my @nses;
466 if ($query) {
467 foreach my $rr ($query->answer) {
468 if ($rr->type eq "NS") { push (@nses, $rr->nsdname); }
469 }
470 }
471 $nsrecords = [ @nses ];
472 1;
473 } or do {
474 my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
475 dbg("dns: NS lookup failed horribly, perhaps bad resolv.conf setting? (%s)", $eval_stat);
476 return;
477 };
478
479 $nsrecords;
480}
481
482
# spent 29.7ms (15.7+14.0) within Mail::SpamAssassin::PerMsgStatus::is_dns_available which was called 468 times, avg 63µs/call: # 234 times (8.26ms+12.0ms) by Mail::SpamAssassin::Plugin::AskDNS::extract_metadata at line 370 of Mail/SpamAssassin/Plugin/AskDNS.pm, avg 87µs/call # 234 times (7.45ms+1.97ms) by Mail::SpamAssassin::Plugin::URIDNSBL::parsed_metadata at line 345 of Mail/SpamAssassin/Plugin/URIDNSBL.pm, avg 40µs/call
sub is_dns_available {
4834681.03ms my ($self) = @_;
4844682.06ms my $dnsopt = $self->{conf}->{dns_available};
4854681.38ms my $dnsint = $self->{conf}->{dns_test_interval} || 600;
486468907µs my @domains;
487
4884681.25ms $LAST_DNS_CHECK ||= 0;
4894687.73ms4683.46ms my $diff = time() - $LAST_DNS_CHECK;
# spent 3.46ms making 468 calls to Time::HiRes::time, avg 7µs/call
490
491 # undef $IS_DNS_AVAILABLE if we should be testing for
492 # working DNS and our check interval time has passed
4934681.11ms if ($dnsopt eq "test" && $diff > $dnsint) {
494 $IS_DNS_AVAILABLE = undef;
495 dbg("dns: is_dns_available() last checked %.1f seconds ago; re-checking",
496 $diff);
497 }
498
49946812.0ms return $IS_DNS_AVAILABLE if (defined $IS_DNS_AVAILABLE);
500113µs14µs $LAST_DNS_CHECK = time();
# spent 4µs making 1 call to Time::HiRes::time
501
50212µs $IS_DNS_AVAILABLE = 0;
50312µs if ($dnsopt eq "no") {
504 dbg("dns: dns_available set to no in config file, skipping test");
505 return $IS_DNS_AVAILABLE;
506 }
507
508 # Even if "dns_available" is explicitly set to "yes", we want to ignore
509 # DNS if we're only supposed to be looking at local tests.
51013µs goto done if ($self->{main}->{local_tests_only});
511
512 # Check version numbers - runtime check only
51314µs if (defined $Net::DNS::VERSION) {
514114µs18.17ms if (am_running_on_windows()) {
# spent 8.17ms making 1 call to Mail::SpamAssassin::Util::am_running_on_windows
515 if ($Net::DNS::VERSION < 0.46) {
516 warn("dns: Net::DNS version is $Net::DNS::VERSION, but need 0.46 for Win32");
517 return $IS_DNS_AVAILABLE;
518 }
519 }
520 else {
52113µs if ($Net::DNS::VERSION < 0.34) {
522 warn("dns: Net::DNS version is $Net::DNS::VERSION, but need 0.34");
523 return $IS_DNS_AVAILABLE;
524 }
525 }
526 }
527
528110µs172µs $self->clear_resolver();
# spent 72µs making 1 call to Mail::SpamAssassin::PerMsgStatus::clear_resolver
529112µs12.28ms goto done unless $self->load_resolver();
# spent 2.28ms making 1 call to Mail::SpamAssassin::PerMsgStatus::load_resolver
530
53113µs if ($dnsopt eq "yes") {
532 # optionally shuffle the list of nameservers to distribute the load
53313µs if ($self->{conf}->{dns_options}->{rotate}) {
534 my @nameservers = $self->{resolver}->available_nameservers();
535 Mail::SpamAssassin::Util::fisher_yates_shuffle(\@nameservers);
536 dbg("dns: shuffled NS list: " . join(", ", @nameservers));
537 $self->{resolver}->available_nameservers(@nameservers);
538 }
53912µs $IS_DNS_AVAILABLE = 1;
54016µs16µs dbg("dns: dns_available set to yes in config file, skipping test");
# spent 6µs making 1 call to Mail::SpamAssassin::Logger::dbg
541112µs return $IS_DNS_AVAILABLE;
542 }
543
544 if ($dnsopt =~ /^test:\s*(\S.*)$/) {
545 @domains = split (/\s+/, $1);
546 dbg("dns: looking up NS records for user specified domains: %s",
547 join(", ", @domains));
548 } else {
549 @domains = @EXISTING_DOMAINS;
550 dbg("dns: looking up NS records for built-in domains");
551 }
552
553 # do the test with a full set of configured nameservers
554 my @nameservers = $self->{resolver}->configured_nameservers();
555
556 # optionally shuffle the list of nameservers to distribute the load
557 if ($self->{conf}->{dns_options}->{rotate}) {
558 Mail::SpamAssassin::Util::fisher_yates_shuffle(\@nameservers);
559 dbg("dns: shuffled NS list, testing: " . join(", ", @nameservers));
560 } else {
561 dbg("dns: testing resolver nameservers: " . join(", ", @nameservers));
562 }
563
564 # Try the different nameservers here and collect a list of working servers
565 my @good_nameservers;
566 foreach my $ns (@nameservers) {
567 $self->{resolver}->available_nameservers($ns); # try just this one
568 for (my $retry = 3; $retry > 0 && @domains; $retry--) {
569 my $domain = splice(@domains, rand(@domains), 1);
570 dbg("dns: trying ($retry) $domain, server $ns ...");
571 my $result = $self->lookup_ns($domain);
572 $self->{resolver}->finish_socket();
573 if (!$result) {
574 dbg("dns: NS lookup of $domain using $ns failed horribly, ".
575 "may not be a valid nameserver");
576 last;
577 } elsif (!@$result) {
578 dbg("dns: NS lookup of $domain using $ns failed, no results found");
579 } else {
580 dbg("dns: NS lookup of $domain using $ns succeeded => DNS available".
581 " (set dns_available to override)");
582 push(@good_nameservers, $ns);
583 last;
584 }
585 }
586 }
587
588 if (!@good_nameservers) {
589 dbg("dns: all NS queries failed => DNS unavailable ".
590 "(set dns_available to override)");
591 } else {
592 $IS_DNS_AVAILABLE = 1;
593 dbg("dns: NS list: ".join(", ", @good_nameservers));
594 $self->{resolver}->available_nameservers(@good_nameservers);
595 }
596
597done:
598 # jm: leaving this in!
599 dbg("dns: is DNS available? " . $IS_DNS_AVAILABLE);
600 return $IS_DNS_AVAILABLE;
601}
602
603###########################################################################
604
605sub server_failed_to_respond_for_domain {
606 my ($self, $dom) = @_;
607 if ($self->{dns_server_too_slow}->{$dom}) {
608 dbg("dns: server for '$dom' failed to reply previously, not asking again");
609 return 1;
610 }
611 return 0;
612}
613
614sub set_server_failed_to_respond_for_domain {
615 my ($self, $dom) = @_;
616 dbg("dns: server for '$dom' failed to reply, marking as bad");
617 $self->{dns_server_too_slow}->{$dom} = 1;
618}
619
620###########################################################################
621
622sub enter_helper_run_mode {
623 my ($self) = @_;
624
625 dbg("dns: entering helper-app run mode");
626 $self->{old_slash} = $/; # Razor pollutes this
627 %{$self->{old_env}} = ();
628 if ( %ENV ) {
629 # undefined values in %ENV can result due to autovivification elsewhere,
630 # this prevents later possible warnings when we restore %ENV
631 while (my ($key, $value) = each %ENV) {
632 $self->{old_env}->{$key} = $value if defined $value;
633 }
634 }
635
636 Mail::SpamAssassin::Util::clean_path_in_taint_mode();
637
638 my $newhome;
639 if ($self->{main}->{home_dir_for_helpers}) {
640 $newhome = $self->{main}->{home_dir_for_helpers};
641 } else {
642 # use spamd -u user's home dir
643 $newhome = (Mail::SpamAssassin::Util::portable_getpwuid ($>))[7];
644 }
645
646 if ($newhome) {
647 $ENV{'HOME'} = Mail::SpamAssassin::Util::untaint_file_path ($newhome);
648 }
649
650 # enforce SIGCHLD as DEFAULT; IGNORE causes spurious kernel warnings
651 # on Red Hat NPTL kernels (bug 1536), and some users of the
652 # Mail::SpamAssassin modules set SIGCHLD to be a fatal signal
653 # for some reason! (bug 3507)
654 $self->{old_sigchld_handler} = $SIG{CHLD};
655 $SIG{CHLD} = 'DEFAULT';
656}
657
658sub leave_helper_run_mode {
659 my ($self) = @_;
660
661 dbg("dns: leaving helper-app run mode");
662 $/ = $self->{old_slash};
663 %ENV = %{$self->{old_env}};
664
665 if (defined $self->{old_sigchld_handler}) {
666 $SIG{CHLD} = $self->{old_sigchld_handler};
667 } else {
668 # if SIGCHLD has never been explicitly set, it's returned as undef.
669 # however, when *setting* SIGCHLD, using undef(%) or assigning to an
670 # undef value produces annoying 'Use of uninitialized value in scalar
671 # assignment' warnings. That's silly. workaround:
672 $SIG{CHLD} = 'DEFAULT';
673 }
674}
675
676# note: this must be called before leave_helper_run_mode() is called,
677# as the SIGCHLD signal must be set to DEFAULT for it to work.
678sub cleanup_kids {
679 my ($self, $pid) = @_;
680
681 if ($SIG{CHLD} && $SIG{CHLD} ne 'IGNORE') { # running from spamd
682 waitpid ($pid, 0);
683 }
684}
685
686###########################################################################
687
688
# spent 260ms (202+58.2) within Mail::SpamAssassin::PerMsgStatus::register_async_rule_start which was called 8426 times, avg 31µs/call: # 8043 times (193ms+55.6ms) by Mail::SpamAssassin::Plugin::URIDNSBL::query_hosts_or_domains at line 877 of Mail/SpamAssassin/Plugin/URIDNSBL.pm, avg 31µs/call # 383 times (8.92ms+2.58ms) by Mail::SpamAssassin::Plugin::URIDNSBL::query_hosts_or_domains at line 892 of Mail/SpamAssassin/Plugin/URIDNSBL.pm, avg 30µs/call
sub register_async_rule_start {
689842617.9ms my ($self, $rule) = @_;
690842663.1ms842658.2ms dbg("dns: $rule lookup start");
# spent 58.2ms making 8426 calls to Mail::SpamAssassin::Logger::dbg, avg 7µs/call
6918426166ms $self->{rule_to_rblkey}->{$rule} = '*ASYNC_START';
692}
693
694sub register_async_rule_finish {
695 my ($self, $rule) = @_;
696 dbg("dns: $rule lookup finished");
697 delete $self->{rule_to_rblkey}->{$rule};
698}
699
700sub mark_all_async_rules_complete {
701 my ($self) = @_;
702 $self->{rule_to_rblkey} = { };
703}
704
705sub is_rule_complete {
706 my ($self, $rule) = @_;
707
708 my $key = $self->{rule_to_rblkey}->{$rule};
709 if (!defined $key) {
710 # dbg("dns: $rule lookup complete, not in list");
711 return 1;
712 }
713
714 if ($key eq '*ASYNC_START') {
715 dbg("dns: $rule lookup not yet complete");
716 return 0; # not yet complete
717 }
718
719 my $ent = $self->{async}->get_lookup($key);
720 if (!defined $ent) {
721 dbg("dns: $rule lookup complete, $key no longer pending");
722 return 1;
723 }
724
725 dbg("dns: $rule lookup not yet complete");
726 return 0; # not yet complete
727}
728
729###########################################################################
730
731# interface called by SPF plugin
732sub check_for_from_dns {
733 my ($self, $pms) = @_;
734 if (defined $pms->{sender_host_fail}) {
735 return ($pms->{sender_host_fail} == 2); # both MX and A need to fail
736 }
737}
738
739113µs1;
 
# spent 1.12s within Mail::SpamAssassin::PerMsgStatus::CORE:match which was called 24245 times, avg 46µs/call: # 9338 times (836ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2378 of Mail/SpamAssassin/PerMsgStatus.pm, avg 90µs/call # 2294 times (5.51ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2383 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 2276 times (8.85ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2391 of Mail/SpamAssassin/PerMsgStatus.pm, avg 4µs/call # 2276 times (6.36ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2408 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 2274 times (8.55ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2418 of Mail/SpamAssassin/PerMsgStatus.pm, avg 4µs/call # 1912 times (98.3ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2435 of Mail/SpamAssassin/PerMsgStatus.pm, avg 51µs/call # 1742 times (4.78ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2392 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 468 times (1.17ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 2013 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 360 times (1.72ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2411 of Mail/SpamAssassin/PerMsgStatus.pm, avg 5µs/call # 360 times (843µs+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2410 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 234 times (147ms+0s) by Mail::SpamAssassin::PerMsgStatus::get_envelope_from at line 2887 of Mail/SpamAssassin/PerMsgStatus.pm, avg 628µs/call # 234 times (2.20ms+0s) by Mail::SpamAssassin::PerMsgStatus::extract_message_metadata at line 1725 of Mail/SpamAssassin/PerMsgStatus.pm, avg 9µs/call # 234 times (1.76ms+0s) by Mail::SpamAssassin::PerMsgStatus::extract_message_metadata at line 1732 of Mail/SpamAssassin/PerMsgStatus.pm, avg 8µs/call # 234 times (572µs+0s) by Mail::SpamAssassin::PerMsgStatus::get_envelope_from at line 2846 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 5 times (27µs+0s) by Mail::SpamAssassin::PerMsgStatus::get_envelope_from at line 2848 of Mail/SpamAssassin/PerMsgStatus.pm, avg 5µs/call # 3 times (20µs+0s) by Mail::SpamAssassin::PerMsgStatus::all_to_addrs at line 3120 of Mail/SpamAssassin/PerMsgStatus.pm, avg 7µs/call # once (2µs+0s) by Mail::SpamAssassin::PerMsgStatus::all_to_addrs at line 3105 of Mail/SpamAssassin/PerMsgStatus.pm
sub Mail::SpamAssassin::PerMsgStatus::CORE:match; # opcode
# spent 7.93ms within Mail::SpamAssassin::PerMsgStatus::CORE:qr which was called 1872 times, avg 4µs/call: # 468 times (2.59ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2132 of Mail/SpamAssassin/PerMsgStatus.pm, avg 6µs/call # 468 times (1.81ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2134 of Mail/SpamAssassin/PerMsgStatus.pm, avg 4µs/call # 468 times (1.79ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2136 of Mail/SpamAssassin/PerMsgStatus.pm, avg 4µs/call # 468 times (1.74ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2133 of Mail/SpamAssassin/PerMsgStatus.pm, avg 4µs/call
sub Mail::SpamAssassin::PerMsgStatus::CORE:qr; # opcode
# spent 28.0ms within Mail::SpamAssassin::PerMsgStatus::CORE:regcomp which was called 13122 times, avg 2µs/call: # 9338 times (15.5ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2378 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 1912 times (3.52ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2435 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 468 times (3.47ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2136 of Mail/SpamAssassin/PerMsgStatus.pm, avg 7µs/call # 468 times (3.47ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2132 of Mail/SpamAssassin/PerMsgStatus.pm, avg 7µs/call # 468 times (1.03ms+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2134 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 468 times (965µs+0s) by Mail::SpamAssassin::PerMsgStatus::_tbirdurire at line 2133 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call
sub Mail::SpamAssassin::PerMsgStatus::CORE:regcomp; # opcode
# spent 88.4ms within Mail::SpamAssassin::PerMsgStatus::CORE:subst which was called 11816 times, avg 7µs/call: # 2294 times (40.2ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2381 of Mail/SpamAssassin/PerMsgStatus.pm, avg 18µs/call # 2294 times (6.21ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2380 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 1404 times (11.2ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 1902 of Mail/SpamAssassin/PerMsgStatus.pm, avg 8µs/call # 1404 times (3.01ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 1903 of Mail/SpamAssassin/PerMsgStatus.pm, avg 2µs/call # 468 times (4.64ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 1995 of Mail/SpamAssassin/PerMsgStatus.pm, avg 10µs/call # 468 times (4.19ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 2018 of Mail/SpamAssassin/PerMsgStatus.pm, avg 9µs/call # 468 times (2.37ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 2014 of Mail/SpamAssassin/PerMsgStatus.pm, avg 5µs/call # 468 times (2.26ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 1997 of Mail/SpamAssassin/PerMsgStatus.pm, avg 5µs/call # 468 times (1.97ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 1996 of Mail/SpamAssassin/PerMsgStatus.pm, avg 4µs/call # 468 times (1.34ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 1994 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 468 times (1.34ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 2020 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 468 times (1.19ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get at line 2011 of Mail/SpamAssassin/PerMsgStatus.pm, avg 3µs/call # 234 times (4.84ms+0s) by Mail::SpamAssassin::PerMsgStatus::get_envelope_from at line 2899 of Mail/SpamAssassin/PerMsgStatus.pm, avg 21µs/call # 234 times (1.49ms+0s) by Mail::SpamAssassin::PerMsgStatus::get_envelope_from at line 2897 of Mail/SpamAssassin/PerMsgStatus.pm, avg 6µs/call # 206 times (2.08ms+0s) by Mail::SpamAssassin::PerMsgStatus::_get_parsed_uri_list at line 2428 of Mail/SpamAssassin/PerMsgStatus.pm, avg 10µs/call # once (13µs+0s) by Mail::SpamAssassin::PerMsgStatus::all_to_addrs at line 3115 of Mail/SpamAssassin/PerMsgStatus.pm # once (8µs+0s) by Mail::SpamAssassin::PerMsgStatus::all_to_addrs at line 3114 of Mail/SpamAssassin/PerMsgStatus.pm
sub Mail::SpamAssassin::PerMsgStatus::CORE:subst; # opcode