Filename | /usr/local/lib/perl5/site_perl/Mail/SpamAssassin/NetSet.pm |
Statements | Executed 264 statements in 6.05ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 4.62ms | 20.1ms | BEGIN@35 | Mail::SpamAssassin::NetSet::
4 | 2 | 1 | 808µs | 6.39ms | add_cidr | Mail::SpamAssassin::NetSet::
2 | 1 | 1 | 234µs | 1.65ms | _convert_ipv4_cidr_to_ipv6 | Mail::SpamAssassin::NetSet::
3 | 1 | 1 | 116µs | 240µs | new | Mail::SpamAssassin::NetSet::
4 | 1 | 1 | 107µs | 232µs | _nets_contains_network | Mail::SpamAssassin::NetSet::
18 | 7 | 1 | 84µs | 304µs | CORE:match (opcode) | Mail::SpamAssassin::NetSet::
4 | 1 | 1 | 71µs | 1.62ms | is_net_declared | Mail::SpamAssassin::NetSet::
16 | 4 | 1 | 68µs | 68µs | CORE:subst (opcode) | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 41µs | 49µs | BEGIN@21 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 36µs | 432µs | BEGIN@26 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 28µs | 157µs | BEGIN@29 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 27µs | 799µs | BEGIN@25 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 26µs | 59µs | BEGIN@22 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 25µs | 91µs | BEGIN@24 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 24µs | 31µs | BEGIN@23 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 21µs | 198µs | BEGIN@31 | Mail::SpamAssassin::NetSet::
1 | 1 | 1 | 20µs | 76µs | BEGIN@28 | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | DESTROY | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | __ANON__[:332] | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | clone | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | contains_ip | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | contains_net | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | ditch_cache | Mail::SpamAssassin::NetSet::
0 | 0 | 0 | 0s | 0s | get_num_nets | Mail::SpamAssassin::NetSet::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # Mail::SpamAssassin::NetSet - object to manipulate CIDR net IP addrs | ||||
2 | # <@LICENSE> | ||||
3 | # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
4 | # contributor license agreements. See the NOTICE file distributed with | ||||
5 | # this work for additional information regarding copyright ownership. | ||||
6 | # The ASF licenses this file to you under the Apache License, Version 2.0 | ||||
7 | # (the "License"); you may not use this file except in compliance with | ||||
8 | # the License. You may obtain a copy of the License at: | ||||
9 | # | ||||
10 | # http://www.apache.org/licenses/LICENSE-2.0 | ||||
11 | # | ||||
12 | # Unless required by applicable law or agreed to in writing, software | ||||
13 | # distributed under the License is distributed on an "AS IS" BASIS, | ||||
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
15 | # See the License for the specific language governing permissions and | ||||
16 | # limitations under the License. | ||||
17 | # </@LICENSE> | ||||
18 | |||||
19 | package Mail::SpamAssassin::NetSet; | ||||
20 | |||||
21 | 2 | 61µs | 2 | 58µs | # spent 49µs (41+9) within Mail::SpamAssassin::NetSet::BEGIN@21 which was called:
# once (41µs+9µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 21 # spent 49µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@21
# spent 9µs making 1 call to strict::import |
22 | 2 | 54µs | 2 | 91µs | # spent 59µs (26+32) within Mail::SpamAssassin::NetSet::BEGIN@22 which was called:
# once (26µs+32µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 22 # spent 59µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@22
# spent 32µs making 1 call to warnings::import |
23 | 2 | 57µs | 2 | 37µs | # spent 31µs (24+7) within Mail::SpamAssassin::NetSet::BEGIN@23 which was called:
# once (24µs+7µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 23 # spent 31µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@23
# spent 7µs making 1 call to bytes::import |
24 | 2 | 64µs | 2 | 157µs | # spent 91µs (25+66) within Mail::SpamAssassin::NetSet::BEGIN@24 which was called:
# once (25µs+66µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 24 # spent 91µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@24
# spent 66µs making 1 call to re::import |
25 | 2 | 69µs | 2 | 1.57ms | # spent 799µs (27+772) within Mail::SpamAssassin::NetSet::BEGIN@25 which was called:
# once (27µs+772µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 25 # spent 799µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@25
# spent 772µs making 1 call to Time::HiRes::import |
26 | 3 | 99µs | 3 | 827µs | # spent 432µs (36+396) within Mail::SpamAssassin::NetSet::BEGIN@26 which was called:
# once (36µs+396µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 26 # spent 432µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@26
# spent 377µs making 1 call to NetAddr::IP::import
# spent 19µs making 1 call to UNIVERSAL::VERSION |
27 | |||||
28 | 2 | 54µs | 2 | 131µs | # spent 76µs (20+56) within Mail::SpamAssassin::NetSet::BEGIN@28 which was called:
# once (20µs+56µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 28 # spent 76µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@28
# spent 56µs making 1 call to Exporter::import |
29 | 2 | 70µs | 2 | 286µs | # spent 157µs (28+129) within Mail::SpamAssassin::NetSet::BEGIN@29 which was called:
# once (28µs+129µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 29 # spent 157µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@29
# spent 129µs making 1 call to Exporter::import |
30 | |||||
31 | 1 | 2µs | # spent 198µs (21+177) within Mail::SpamAssassin::NetSet::BEGIN@31 which was called:
# once (21µs+177µs) by Mail::SpamAssassin::Conf::BEGIN@86 at line 33 | ||
32 | @ISA $TESTCODE $NUMTESTS $have_patricia | ||||
33 | 1 | 118µs | 2 | 375µs | }; # spent 198µs making 1 call to Mail::SpamAssassin::NetSet::BEGIN@31
# spent 177µs making 1 call to vars::import |
34 | |||||
35 | # spent 20.1ms (4.62+15.5) within Mail::SpamAssassin::NetSet::BEGIN@35 which was called:
# once (4.62ms+15.5ms) by Mail::SpamAssassin::Conf::BEGIN@86 at line 42 | ||||
36 | 1 | 11µs | eval { | ||
37 | 1 | 288µs | require Net::Patricia; | ||
38 | 1 | 34µs | 1 | 16µs | Net::Patricia->VERSION(1.16); # need AF_INET6 support # spent 16µs making 1 call to version::_VERSION |
39 | 1 | 10µs | 1 | 118µs | import Net::Patricia; # spent 118µs making 1 call to Exporter::import |
40 | 1 | 3µs | $have_patricia = 1; | ||
41 | }; | ||||
42 | 1 | 3.62ms | 1 | 20.1ms | } # spent 20.1ms making 1 call to Mail::SpamAssassin::NetSet::BEGIN@35 |
43 | |||||
44 | ########################################################################### | ||||
45 | |||||
46 | # spent 240µs (116+124) within Mail::SpamAssassin::NetSet::new which was called 3 times, avg 80µs/call:
# 3 times (116µs+124µs) by Mail::SpamAssassin::Conf::new_netset at line 5096 of Mail/SpamAssassin/Conf.pm, avg 80µs/call | ||||
47 | 3 | 6µs | my ($class,$netset_name) = @_; | ||
48 | 3 | 7µs | $class = ref($class) || $class; | ||
49 | |||||
50 | 3 | 6µs | $netset_name = '' if !defined $netset_name; # object name for debugging | ||
51 | 3 | 16µs | my $self = { | ||
52 | name => $netset_name, num_nets => 0, | ||||
53 | cache_hits => 0, cache_attempts => 0, | ||||
54 | }; | ||||
55 | 3 | 68µs | 6 | 124µs | $self->{pt} = Net::Patricia->new(&AF_INET6) if $have_patricia; # spent 113µs making 3 calls to Net::Patricia::new, avg 38µs/call
# spent 11µs making 3 calls to Socket::AF_INET6, avg 4µs/call |
56 | |||||
57 | 3 | 6µs | bless $self, $class; | ||
58 | 3 | 20µs | $self; | ||
59 | } | ||||
60 | |||||
61 | ########################################################################### | ||||
62 | |||||
63 | sub DESTROY { | ||||
64 | my($self) = shift; | ||||
65 | if (exists $self->{cache}) { | ||||
66 | local($@, $!, $_); # protect outer layers from a potential surprise | ||||
67 | my($hits, $attempts) = ($self->{cache_hits}, $self->{cache_attempts}); | ||||
68 | dbg("netset: cache %s hits/attempts: %d/%d, %.1f %%", | ||||
69 | $self->{name}, $hits, $attempts, 100*$hits/$attempts) if $attempts > 0; | ||||
70 | } | ||||
71 | } | ||||
72 | |||||
73 | ########################################################################### | ||||
74 | |||||
75 | # spent 6.39ms (808µs+5.58) within Mail::SpamAssassin::NetSet::add_cidr which was called 4 times, avg 1.60ms/call:
# 2 times (519µs+4.21ms) by Mail::SpamAssassin::Conf::new_netset at line 5098 of Mail/SpamAssassin/Conf.pm, avg 2.36ms/call
# 2 times (288µs+1.37ms) by Mail::SpamAssassin::Conf::new_netset at line 5099 of Mail/SpamAssassin/Conf.pm, avg 831µs/call | ||||
76 | 4 | 12µs | my ($self, @nets) = @_; | ||
77 | |||||
78 | 4 | 14µs | $self->{nets} ||= [ ]; | ||
79 | 4 | 7µs | my $numadded = 0; | ||
80 | 4 | 9µs | delete $self->{cache}; # invalidate cache (in case of late additions) | ||
81 | |||||
82 | 4 | 14µs | foreach my $cidr_orig (@nets) { | ||
83 | 4 | 8µs | my $cidr = $cidr_orig; # leave original unchanged, useful for logging | ||
84 | |||||
85 | # recognizes syntax: | ||||
86 | # [IPaddr%scope]/len or IPaddr%scope/len or IPv4addr/mask | ||||
87 | # optionally prefixed by a '!' to indicate negation (exclusion); | ||||
88 | # the %scope (i.e. interface), /len or /mask are optional | ||||
89 | |||||
90 | 4 | 24µs | local($1,$2,$3,$4); | ||
91 | 4 | 54µs | 4 | 23µs | $cidr =~ s/^\s+//; # spent 23µs making 4 calls to Mail::SpamAssassin::NetSet::CORE:subst, avg 6µs/call |
92 | 4 | 40µs | 4 | 10µs | my $exclude = ($cidr =~ s/^!\s*//) ? 1 : 0; # spent 10µs making 4 calls to Mail::SpamAssassin::NetSet::CORE:subst, avg 2µs/call |
93 | |||||
94 | 4 | 6µs | my $masklen; # netmask or a prefix length | ||
95 | 4 | 56µs | 4 | 28µs | $masklen = $1 if $cidr =~ s{ / (.*) \z }{}xs; # spent 28µs making 4 calls to Mail::SpamAssassin::NetSet::CORE:subst, avg 7µs/call |
96 | |||||
97 | # discard optional brackets | ||||
98 | 4 | 36µs | 4 | 11µs | $cidr = $1 if $cidr =~ /^ \[ ( [^\]]* ) \] \z/xs; # spent 11µs making 4 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 3µs/call |
99 | |||||
100 | 4 | 6µs | my $scope; | ||
101 | # IPv6 Scoped Address (RFC 4007, RFC 6874, RFC 3986 "unreserved" charset) | ||||
102 | 4 | 30µs | 4 | 8µs | if ($cidr =~ s/ % ( [A-Z0-9._~-]* ) \z //xsi) { # scope <zone_id> ? # spent 8µs making 4 calls to Mail::SpamAssassin::NetSet::CORE:subst, avg 2µs/call |
103 | $scope = $1; # interface specification | ||||
104 | # discard interface specification, currently just ignored | ||||
105 | info("netset: ignoring interface scope '%%%s' in IP address %s", | ||||
106 | $scope, $cidr_orig); | ||||
107 | } | ||||
108 | |||||
109 | 4 | 7µs | my $is_ip4 = 0; | ||
110 | 4 | 38µs | 4 | 12µs | if ($cidr =~ /^ \d+ (\. | \z) /x) { # looks like an IPv4 address # spent 12µs making 4 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 3µs/call |
111 | 2 | 29µs | 2 | 13µs | if ($cidr =~ /^ (\d+) \. (\d+) \. (\d+) \. (\d+) \z/x) { # spent 13µs making 2 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 7µs/call |
112 | # also strips leading zeroes, not liked by inet_pton | ||||
113 | 2 | 30µs | $cidr = sprintf('%d.%d.%d.%d', $1,$2,$3,$4); | ||
114 | 2 | 4µs | $masklen = 32 if !defined $masklen; | ||
115 | } elsif ($cidr =~ /^ (\d+) \. (\d+) \. (\d+) \.? \z/x) { | ||||
116 | $cidr = sprintf('%d.%d.%d.0', $1,$2,$3); | ||||
117 | $masklen = 24 if !defined $masklen; | ||||
118 | } elsif ($cidr =~ /^ (\d+) \. (\d+) \.? \z/x) { | ||||
119 | $cidr = sprintf('%d.%d.0.0', $1,$2); | ||||
120 | $masklen = 16 if !defined $masklen; | ||||
121 | } elsif ($cidr =~ /^ (\d+) \.? \z/x) { | ||||
122 | $cidr = sprintf('%d.0.0.0', $1); | ||||
123 | $masklen = 8 if !defined $masklen; | ||||
124 | } else { | ||||
125 | warn "netset: illegal IPv4 address given: '$cidr_orig'\n"; | ||||
126 | next; | ||||
127 | } | ||||
128 | 2 | 4µs | $is_ip4 = 1; | ||
129 | } | ||||
130 | |||||
131 | 4 | 27µs | if ($self->{pt}) { | ||
132 | 4 | 10µs | if (defined $masklen) { | ||
133 | 2 | 30µs | 2 | 9µs | $masklen =~ /^\d{1,3}\z/ # spent 9µs making 2 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 5µs/call |
134 | or die "Network mask not supported, use a CIDR syntax: '$cidr_orig'"; | ||||
135 | } | ||||
136 | 4 | 8µs | my $key = $cidr; | ||
137 | 4 | 7µs | my $prefix_len = $masklen; | ||
138 | 4 | 10µs | if ($is_ip4) { | ||
139 | 2 | 8µs | $key = '::ffff:' . $key; # turn it into an IPv4-mapped IPv6 addresses | ||
140 | 2 | 6µs | $prefix_len += 96 if defined $prefix_len; | ||
141 | } | ||||
142 | 4 | 8µs | $prefix_len = 128 if !defined $prefix_len; | ||
143 | 4 | 9µs | $key .= '/' . $prefix_len; | ||
144 | # dbg("netset: add_cidr (patricia trie) %s => %s", | ||||
145 | # $cidr_orig, $exclude ? '!'.$key : $key); | ||||
146 | 4 | 16µs | defined eval { | ||
147 | 4 | 42µs | 4 | 696µs | $self->{pt}->add_string($key, $exclude ? '!'.$key : $key) # spent 696µs making 4 calls to Net::Patricia::add_string, avg 174µs/call |
148 | } or warn "netset: illegal IP address given (patricia trie): ". | ||||
149 | "'$key': $@\n"; | ||||
150 | } | ||||
151 | |||||
152 | 4 | 11µs | $cidr .= '/' . $masklen if defined $masklen; | ||
153 | |||||
154 | 4 | 40µs | 4 | 36µs | my $ip = NetAddr::IP->new($cidr); # spent 36µs making 4 calls to NetAddr::IP::Lite::new, avg 9µs/call |
155 | 4 | 7µs | if (!defined $ip) { | ||
156 | warn "netset: illegal IP address given: '$cidr_orig'\n"; | ||||
157 | next; | ||||
158 | } | ||||
159 | # dbg("netset: add_cidr %s => %s => %s", $cidr_orig, $cidr, $ip); | ||||
160 | |||||
161 | # if this is an IPv4 address, create an IPv6 representation, too | ||||
162 | 4 | 7µs | my ($ip4, $ip6); | ||
163 | 4 | 13µs | if ($is_ip4) { | ||
164 | 2 | 4µs | $ip4 = $ip; | ||
165 | 2 | 17µs | 2 | 1.65ms | $ip6 = $self->_convert_ipv4_cidr_to_ipv6($cidr); # spent 1.65ms making 2 calls to Mail::SpamAssassin::NetSet::_convert_ipv4_cidr_to_ipv6, avg 827µs/call |
166 | } else { | ||||
167 | 2 | 3µs | $ip6 = $ip; | ||
168 | } | ||||
169 | |||||
170 | # bug 5931: this is O(n^2). bad if there are lots of nets. There are good | ||||
171 | # reasons to keep it for linting purposes, though, so don't start skipping | ||||
172 | # it until we have over 200 nets in our list | ||||
173 | 8 | 30µs | if (scalar @{$self->{nets}} < 200) { | ||
174 | 4 | 29µs | 4 | 1.62ms | next if ($self->is_net_declared($ip4, $ip6, $exclude, 0)); # spent 1.62ms making 4 calls to Mail::SpamAssassin::NetSet::is_net_declared, avg 405µs/call |
175 | } | ||||
176 | |||||
177 | # note: it appears a NetAddr::IP object takes up about 279 bytes | ||||
178 | 8 | 47µs | push @{$self->{nets}}, { | ||
179 | exclude => $exclude, | ||||
180 | ip4 => $ip4, | ||||
181 | ip6 => $ip6, | ||||
182 | as_string => $cidr_orig, | ||||
183 | }; | ||||
184 | 4 | 29µs | $numadded++; | ||
185 | } | ||||
186 | |||||
187 | 4 | 8µs | $self->{num_nets} += $numadded; | ||
188 | 4 | 28µs | $numadded; | ||
189 | } | ||||
190 | |||||
191 | sub get_num_nets { | ||||
192 | my ($self) = @_; | ||||
193 | return $self->{num_nets}; | ||||
194 | } | ||||
195 | |||||
196 | # spent 1.65ms (234µs+1.42) within Mail::SpamAssassin::NetSet::_convert_ipv4_cidr_to_ipv6 which was called 2 times, avg 827µs/call:
# 2 times (234µs+1.42ms) by Mail::SpamAssassin::NetSet::add_cidr at line 165, avg 827µs/call | ||||
197 | 2 | 5µs | my ($self, $cidr) = @_; | ||
198 | |||||
199 | # only do this for IPv4 addresses | ||||
200 | 2 | 21µs | 2 | 7µs | return unless $cidr =~ /^\d+[.\/]/; # spent 7µs making 2 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 4µs/call |
201 | |||||
202 | 2 | 18µs | 2 | 6µs | if ($cidr !~ /\//) { # no mask # spent 6µs making 2 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 3µs/call |
203 | return NetAddr::IP->new6("::ffff:".$cidr); | ||||
204 | } | ||||
205 | |||||
206 | # else we have a CIDR mask specified. use new6() to do this | ||||
207 | # | ||||
208 | 2 | 123µs | 4 | 36µs | my $ip6 = ""+(NetAddr::IP->new6($cidr)); # spent 19µs making 2 calls to NetAddr::IP::Lite::plus, avg 10µs/call
# spent 17µs making 2 calls to NetAddr::IP::Lite::new6, avg 9µs/call |
209 | # 127.0.0.1 -> 0:0:0:0:0:0:7F00:0001/128 | ||||
210 | # 127/8 -> 0:0:0:0:0:0:7F00:0/104 | ||||
211 | |||||
212 | # now, move that from 0:0:0:0:0:0: space to 0:0:0:0:0:ffff: space | ||||
213 | 2 | 36µs | 4 | 467µs | if (!defined $ip6 || $ip6 !~ /^0:0:0:0:0:0:(.*)$/) { # spent 246µs making 2 calls to Mail::SpamAssassin::NetSet::CORE:match, avg 123µs/call
# spent 221µs making 2 calls to NetAddr::IP::Lite::__ANON__[NetAddr/IP/Lite.pm:238], avg 110µs/call |
214 | warn "oops! unparseable IPv6 address for $cidr: $ip6"; | ||||
215 | return; | ||||
216 | } | ||||
217 | |||||
218 | 2 | 36µs | 2 | 14µs | return NetAddr::IP->new6("::ffff:$1"); # spent 14µs making 2 calls to NetAddr::IP::Lite::new6, avg 7µs/call |
219 | } | ||||
220 | |||||
221 | # spent 232µs (107+125) within Mail::SpamAssassin::NetSet::_nets_contains_network which was called 4 times, avg 58µs/call:
# 4 times (107µs+125µs) by Mail::SpamAssassin::NetSet::is_net_declared at line 246, avg 58µs/call | ||||
222 | 4 | 8µs | my ($self, $net4, $net6, $exclude, $quiet, $netname, $declared) = @_; | ||
223 | |||||
224 | 4 | 8µs | return 0 unless (defined $self->{nets}); | ||
225 | |||||
226 | 8 | 30µs | foreach my $net (@{$self->{nets}}) { | ||
227 | # check to see if the new network is contained by the old network | ||||
228 | 2 | 5µs | my $in4 = defined $net4 && defined $net->{ip4} && $net->{ip4}->contains($net4); | ||
229 | 2 | 22µs | 2 | 125µs | my $in6 = defined $net6 && defined $net->{ip6} && $net->{ip6}->contains($net6); # spent 125µs making 2 calls to NetAddr::IP::Lite::contains, avg 62µs/call |
230 | 2 | 7µs | if ($in4 || $in6) { | ||
231 | warn sprintf("netset: cannot %s %s as it has already been %s\n", | ||||
232 | $exclude ? "exclude" : "include", | ||||
233 | $netname, | ||||
234 | $net->{exclude} ? "excluded" : "included") unless $quiet; | ||||
235 | # a network that matches an excluded network isn't contained by "nets" | ||||
236 | # return 0 if we're not just looking to see if the network was declared | ||||
237 | return 0 if (!$declared && $net->{exclude}); | ||||
238 | return 1; | ||||
239 | } | ||||
240 | } | ||||
241 | 4 | 26µs | return 0; | ||
242 | } | ||||
243 | |||||
244 | # spent 1.62ms (71µs+1.55) within Mail::SpamAssassin::NetSet::is_net_declared which was called 4 times, avg 405µs/call:
# 4 times (71µs+1.55ms) by Mail::SpamAssassin::NetSet::add_cidr at line 174, avg 405µs/call | ||||
245 | 4 | 9µs | my ($self, $net4, $net6, $exclude, $quiet) = @_; | ||
246 | 4 | 57µs | 6 | 1.55ms | return $self->_nets_contains_network($net4, $net6, $exclude, # spent 1.32ms making 2 calls to NetAddr::IP::Lite::__ANON__[NetAddr/IP/Lite.pm:238], avg 659µs/call
# spent 232µs making 4 calls to Mail::SpamAssassin::NetSet::_nets_contains_network, avg 58µs/call |
247 | $quiet, $net4 || $net6, 1); | ||||
248 | } | ||||
249 | |||||
250 | sub contains_ip { | ||||
251 | my ($self, $ip) = @_; | ||||
252 | my $result = 0; | ||||
253 | |||||
254 | if (!$self->{num_nets}) { return 0 } | ||||
255 | |||||
256 | $self->{cache_attempts}++; | ||||
257 | if ($self->{cache} && exists $self->{cache}{$ip}) { | ||||
258 | dbg("netset: %s cached lookup on %s, %d networks, result: %s", | ||||
259 | $self->{name}, $ip, $self->{num_nets}, $self->{cache}{$ip}); | ||||
260 | $self->{cache_hits}++; | ||||
261 | return $self->{cache}{$ip}; | ||||
262 | |||||
263 | } elsif ($self->{pt}) { | ||||
264 | # do a quick lookup on a Patricia Trie | ||||
265 | my $t0 = time; | ||||
266 | local($1,$2,$3,$4); local $_ = $ip; | ||||
267 | $_ = $1 if /^ \[ ( [^\]]* ) \] \z/xs; # discard optional brackets | ||||
268 | s/%[A-Z0-9:._-]+\z//si; # discard interface specification | ||||
269 | if (m{^ (\d+) \. (\d+) \. (\d+) \. (\d+) \z}x) { | ||||
270 | $_ = sprintf('::ffff:%d.%d.%d.%d', $1,$2,$3,$4); | ||||
271 | } else { | ||||
272 | s/^IPv6://si; # discard optional 'IPv6:' prefix | ||||
273 | } | ||||
274 | eval { $result = $self->{pt}->match_string($_); 1 } or undef $result; | ||||
275 | $result = defined $result && $result !~ /^!/ ? 1 : 0; | ||||
276 | dbg("netset: %s patricia lookup on %s, %d networks, result: %s, %.3f ms", | ||||
277 | $self->{name}, $ip, $self->{num_nets}, $result, 1000*(time - $t0)); | ||||
278 | } else { | ||||
279 | # do a sequential search on a list of NetAddr::IP objects | ||||
280 | my $t0 = time; | ||||
281 | my ($ip4, $ip6); | ||||
282 | if ($ip =~ /^\d+\./) { | ||||
283 | $ip4 = NetAddr::IP->new($ip); | ||||
284 | $ip6 = $self->_convert_ipv4_cidr_to_ipv6($ip); | ||||
285 | } else { | ||||
286 | $ip6 = NetAddr::IP->new($ip); | ||||
287 | } | ||||
288 | foreach my $net (@{$self->{nets}}) { | ||||
289 | if ((defined $ip4 && defined $net->{ip4} && $net->{ip4}->contains($ip4)) | ||||
290 | || (defined $ip6 && defined $net->{ip6} && $net->{ip6}->contains($ip6))){ | ||||
291 | $result = !$net->{exclude}; | ||||
292 | last; | ||||
293 | } | ||||
294 | } | ||||
295 | dbg("netset: %s lookup on %s, %d networks, result: %s, %.3f ms", | ||||
296 | $self->{name}, $ip, $self->{num_nets}, $result, 1000*(time - $t0)); | ||||
297 | } | ||||
298 | |||||
299 | $self->{cache}{$ip} = $result; | ||||
300 | return $result; | ||||
301 | } | ||||
302 | |||||
303 | sub contains_net { | ||||
304 | my ($self, $net) = @_; | ||||
305 | my $exclude = $net->{exclude}; | ||||
306 | my $net4 = $net->{ip4}; | ||||
307 | my $net6 = $net->{ip6}; | ||||
308 | return $self->_nets_contains_network($net4, $net6, $exclude, 1, "", 0); | ||||
309 | } | ||||
310 | |||||
311 | sub ditch_cache { | ||||
312 | my ($self) = @_; | ||||
313 | if (exists $self->{cache}) { | ||||
314 | dbg("netset: ditch cache on %s", $self->{name}); | ||||
315 | delete $self->{cache}; | ||||
316 | } | ||||
317 | } | ||||
318 | |||||
319 | sub clone { | ||||
320 | my ($self) = @_; | ||||
321 | my $dup = Mail::SpamAssassin::NetSet->new($self->{name}); | ||||
322 | if ($self->{nets}) { | ||||
323 | @{$dup->{nets}} = @{$self->{nets}}; | ||||
324 | } | ||||
325 | if ($self->{pt}) { | ||||
326 | my $dup_pt = $dup->{pt}; | ||||
327 | $self->{pt}->climb(sub { | ||||
328 | my $key = $_[0]; $key =~ s/^!//; | ||||
329 | defined eval { $dup_pt->add_string($key, $_[0]) } | ||||
330 | or die "Adding a network $_[0] to a patricia trie failed: $@"; | ||||
331 | 1; | ||||
332 | }); | ||||
333 | } | ||||
334 | $dup->{num_nets} = $self->{num_nets}; | ||||
335 | return $dup; | ||||
336 | } | ||||
337 | |||||
338 | ########################################################################### | ||||
339 | |||||
340 | 1 | 8µs | 1; | ||
# spent 304µs (84+221) within Mail::SpamAssassin::NetSet::CORE:match which was called 18 times, avg 17µs/call:
# 4 times (12µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 110, avg 3µs/call
# 4 times (11µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 98, avg 3µs/call
# 2 times (25µs+221µs) by Mail::SpamAssassin::NetSet::_convert_ipv4_cidr_to_ipv6 at line 213, avg 123µs/call
# 2 times (13µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 111, avg 7µs/call
# 2 times (9µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 133, avg 5µs/call
# 2 times (7µs+0s) by Mail::SpamAssassin::NetSet::_convert_ipv4_cidr_to_ipv6 at line 200, avg 4µs/call
# 2 times (6µs+0s) by Mail::SpamAssassin::NetSet::_convert_ipv4_cidr_to_ipv6 at line 202, avg 3µs/call | |||||
# spent 68µs within Mail::SpamAssassin::NetSet::CORE:subst which was called 16 times, avg 4µs/call:
# 4 times (28µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 95, avg 7µs/call
# 4 times (23µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 91, avg 6µs/call
# 4 times (10µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 92, avg 2µs/call
# 4 times (8µs+0s) by Mail::SpamAssassin::NetSet::add_cidr at line 102, avg 2µs/call |