/[Apache-SVN]/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm
ViewVC logotype

Contents of /spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 571893 - (show annotations)
Sat Sep 1 23:16:38 2007 UTC (2 years, 2 months ago) by mmartinec
File size: 20015 byte(s)
Removed hundred of assignments of an empty list or hash to a
just created empty array or hash. Explanation: operator 'my' brings
to life scalars with an undefined value, lists with no elements,
and hashes with no keys. The following assignments are thus redundant:
my $x=undef; my @x=(); my %x=();  Interestingly noone does the first,
but there were about 100 cases of second and third. Even as a stylistic
measure I don't think it counts, as it was not used systematically,
and only in minority of cases.


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 URIDNSBL - look up URLs against DNS blocklists
21
22 =head1 SYNOPSIS
23
24 loadplugin Mail::SpamAssassin::Plugin::URIDNSBL
25 uridnsbl URIBL_SBLXBL sbl-xbl.spamhaus.org. TXT
26
27 =head1 DESCRIPTION
28
29 This works by analysing message text and HTML for URLs, extracting the
30 domain names from those, querying their NS records in DNS, resolving
31 the hostnames used therein, and querying various DNS blocklists for
32 those IP addresses. This is quite effective.
33
34 =head1 USER SETTINGS
35
36 =over 4
37
38 =item uridnsbl_skip_domain domain1 domain2 ...
39
40 Specify a domain, or a number of domains, which should be skipped for the
41 URIBL checks. This is very useful to specify very common domains which are
42 not going to be listed in URIBLs.
43
44 =back
45
46 =head1 RULE DEFINITIONS AND PRIVILEGED SETTINGS
47
48 =over 4
49
50 =item uridnsbl NAME_OF_RULE dnsbl_zone lookuptype
51
52 Specify a lookup. C<NAME_OF_RULE> is the name of the rule to be
53 used, C<dnsbl_zone> is the zone to look up IPs in, and C<lookuptype>
54 is the type of lookup (B<TXT> or B<A>). Note that you must also
55 define a body-eval rule calling C<check_uridnsbl()> to use this.
56
57 Example:
58
59 uridnsbl URIBL_SBLXBL sbl-xbl.spamhaus.org. TXT
60 body URIBL_SBLXBL eval:check_uridnsbl('URIBL_SBLXBL')
61 describe URIBL_SBLXBL Contains a URL listed in the SBL/XBL blocklist
62
63 =item urirhsbl NAME_OF_RULE rhsbl_zone lookuptype
64
65 Specify a RHSBL-style domain lookup. C<NAME_OF_RULE> is the name of the rule
66 to be used, C<rhsbl_zone> is the zone to look up domain names in, and
67 C<lookuptype> is the type of lookup (B<TXT> or B<A>). Note that you must also
68 define a body-eval rule calling C<check_uridnsbl()> to use this.
69
70 An RHSBL zone is one where the domain name is looked up, as a string; e.g. a
71 URI using the domain C<foo.com> will cause a lookup of
72 C<foo.com.uriblzone.net>. Note that hostnames are stripped from the domain
73 used in the URIBL lookup, so the domain C<foo.bar.com> will look up
74 C<bar.com.uriblzone.net>, and C<foo.bar.co.uk> will look up
75 C<bar.co.uk.uriblzone.net>.
76
77 If an URI consists of an IP address instead of a hostname, the IP address is
78 looked up (using the standard reversed quads method) in each C<rhsbl_zone>.
79
80 Example:
81
82 urirhsbl URIBL_RHSBL rhsbl.example.org. TXT
83
84 =item urirhssub NAME_OF_RULE rhsbl_zone lookuptype subtest
85
86 Specify a RHSBL-style domain lookup with a sub-test. C<NAME_OF_RULE> is the
87 name of the rule to be used, C<rhsbl_zone> is the zone to look up domain names
88 in, and C<lookuptype> is the type of lookup (B<TXT> or B<A>).
89
90 C<subtest> is the sub-test to run against the returned data. The sub-test may
91 either be an IPv4 dotted address for RHSBLs that return multiple A records or a
92 non-negative decimal number to specify a bitmask for RHSBLs that return a
93 single A record containing a bitmask of results.
94
95 Note that, as with C<urirhsbl>, you must also define a body-eval rule calling
96 C<check_uridnsbl()> to use this.
97
98 Example:
99
100 urirhssub URIBL_RHSBL_4 rhsbl.example.org. A 127.0.0.4
101 urirhssub URIBL_RHSBL_8 rhsbl.example.org. A 8
102
103 =back
104
105 =head1 ADMINISTRATOR SETTINGS
106
107 =over 4
108
109 =item uridnsbl_max_domains N (default: 20)
110
111 The maximum number of domains to look up.
112
113 =back
114
115 =head1 NOTES
116
117 The C<uridnsbl_timeout> option has been obsoleted by the C<rbl_timeout>
118 option. See the C<Mail::SpamAssassin::Conf> POD for details on C<rbl_timeout>.
119
120 =cut
121
122 package Mail::SpamAssassin::Plugin::URIDNSBL;
123
124 use Mail::SpamAssassin::Plugin;
125 use Mail::SpamAssassin::Constants qw(:ip);
126 use Mail::SpamAssassin::Util;
127 use Mail::SpamAssassin::Logger;
128 use strict;
129 use warnings;
130 use bytes;
131
132 use vars qw(@ISA);
133 @ISA = qw(Mail::SpamAssassin::Plugin);
134
135 use constant LOG_COMPLETION_TIMES => 0;
136
137 # constructor
138 sub new {
139 my $class = shift;
140 my $samain = shift;
141
142 # some boilerplate...
143 $class = ref($class) || $class;
144 my $self = $class->SUPER::new($samain);
145 bless ($self, $class);
146
147 # this can be effectively global, at least in each process, safely
148
149 $self->{finished} = { };
150
151 $self->register_eval_rule ("check_uridnsbl");
152 $self->set_config($samain->{conf});
153
154 return $self;
155 }
156
157 # this is just a placeholder; in fact the results are dealt with later
158 sub check_uridnsbl {
159 return 0;
160 }
161
162 # ---------------------------------------------------------------------------
163
164 # once the metadata is parsed, we can access the URI list. So start off
165 # the lookups here!
166 sub parsed_metadata {
167 my ($self, $opts) = @_;
168 my $scanner = $opts->{permsgstatus};
169
170 if (!$scanner->is_dns_available()) {
171 $self->{dns_not_available} = 1;
172 return;
173 } else {
174 # due to re-testing dns may become available after being unavailable
175 # DOS: I don't think dns_not_available is even used anymore
176 $self->{dns_not_available} = 0;
177 }
178
179 $scanner->{'uridnsbl_activerules'} = { };
180 $scanner->{'uridnsbl_hits'} = { };
181 $scanner->{'uridnsbl_seen_domain'} = { };
182
183 # only hit DNSBLs for active rules (defined and score != 0)
184 $scanner->{'uridnsbl_active_rules_rhsbl'} = { };
185 $scanner->{'uridnsbl_active_rules_revipbl'} = { };
186
187 foreach my $rulename (keys %{$scanner->{conf}->{uridnsbls}}) {
188 next unless ($scanner->{conf}->is_rule_active('body_evals',$rulename));
189
190 my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
191 if ($rulecf->{is_rhsbl}) {
192 $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename} = 1;
193 } else {
194 $scanner->{uridnsbl_active_rules_revipbl}->{$rulename} = 1;
195 }
196 }
197
198 # get all domains in message
199
200 # don't keep dereferencing this
201 my $skip_domains = $scanner->{main}->{conf}->{uridnsbl_skip_domains};
202
203 # list of arrays to use in order
204 my @uri_ordered;
205
206 # Generate the full list of html-parsed domains.
207 my $uris = $scanner->get_uri_detail_list();
208
209 # go from uri => info to uri_ordered
210 # 0: a
211 # 1: form
212 # 2: img
213 # 3: !a_empty
214 # 4: parsed
215 # 5: a_empty
216 while (my($uri, $info) = each %{$uris}) {
217 # we want to skip mailto: uris
218 next if ($uri =~ /^mailto:/);
219
220 # no domains were found via this uri, so skip
221 next unless ($info->{domains});
222
223 my $entry = 3;
224
225 if ($info->{types}->{a}) {
226 $entry = 5;
227
228 # determine a vs a_empty
229 foreach my $at (@{$info->{anchor_text}}) {
230 if (length $at) {
231 $entry = 0;
232 last;
233 }
234 }
235 }
236 elsif ($info->{types}->{form}) {
237 $entry = 1;
238 }
239 elsif ($info->{types}->{img}) {
240 $entry = 2;
241 }
242 elsif ($info->{types}->{parsed} && (keys %{$info->{types}} == 1)) {
243 $entry = 4;
244 }
245
246 # take the usable domains and add to the ordered list
247 foreach ( keys %{ $info->{domains} } ) {
248 if (exists $skip_domains->{$_}) {
249 dbg("uridnsbl: domain $_ in skip list");
250 next;
251 }
252 $uri_ordered[$entry]->{$_} = 1;
253 }
254 }
255
256 # at this point, @uri_ordered is an ordered array of uri hashes
257
258 my %domlist;
259 my $umd = $scanner->{main}->{conf}->{uridnsbl_max_domains};
260 while (keys %domlist < $umd && @uri_ordered) {
261 my $array = shift @uri_ordered;
262 next unless $array;
263
264 # run through and find the new domains in this grouping
265 my @domains = grep(!$domlist{$_}, keys %{$array});
266 next unless @domains;
267
268 # the new domains are all useful, just add them in
269 if (keys(%domlist) + @domains <= $umd) {
270 foreach (@domains) {
271 $domlist{$_} = 1;
272 }
273 }
274 else {
275 # trim down to a limited number - pick randomly
276 my $i;
277 while (@domains && keys %domlist < $umd) {
278 my $r = int rand (scalar @domains);
279 $domlist{splice (@domains, $r, 1)} = 1;
280 }
281 }
282 }
283
284 # and query
285 dbg("uridnsbl: domains to query: ".join(' ',keys %domlist));
286 foreach my $dom (keys %domlist) {
287 $self->query_domain ($scanner, $dom);
288 }
289
290 return 1;
291 }
292
293 sub set_config {
294 my($self, $conf) = @_;
295 my @cmds;
296
297 push(@cmds, {
298 setting => 'uridnsbl_max_domains',
299 is_admin => 1,
300 default => 20,
301 type => $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
302 });
303
304 push (@cmds, {
305 setting => 'uridnsbl',
306 is_priv => 1,
307 code => sub {
308 my ($self, $key, $value, $line) = @_;
309 if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/) {
310 my $rulename = $1;
311 my $zone = $2;
312 my $type = $3;
313 $self->{uridnsbls}->{$rulename} = {
314 zone => $zone, type => $type,
315 is_rhsbl => 0
316 };
317 }
318 elsif ($value =~ /^$/) {
319 return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
320 }
321 else {
322 return $Mail::SpamAssassin::Conf::INVALID_VALUE;
323 }
324 }
325 });
326
327 push (@cmds, {
328 setting => 'urirhsbl',
329 is_priv => 1,
330 code => sub {
331 my ($self, $key, $value, $line) = @_;
332 if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/) {
333 my $rulename = $1;
334 my $zone = $2;
335 my $type = $3;
336 $self->{uridnsbls}->{$rulename} = {
337 zone => $zone, type => $type,
338 is_rhsbl => 1
339 };
340 }
341 elsif ($value =~ /^$/) {
342 return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
343 }
344 else {
345 return $Mail::SpamAssassin::Conf::INVALID_VALUE;
346 }
347 }
348 });
349
350 push (@cmds, {
351 setting => 'urirhssub',
352 is_priv => 1,
353 code => sub {
354 my ($self, $key, $value, $line) = @_;
355 if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\d{1,10}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) {
356 my $rulename = $1;
357 my $zone = $2;
358 my $type = $3;
359 my $subrule = $4;
360 $self->{uridnsbls}->{$rulename} = {
361 zone => $zone, type => $type,
362 is_rhsbl => 1, is_subrule => 1
363 };
364 $self->{uridnsbl_subs}->{$zone} ||= { };
365 push (@{$self->{uridnsbl_subs}->{$zone}->{$subrule}->{rulenames}}, $rulename);
366 }
367 elsif ($value =~ /^$/) {
368 return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
369 }
370 else {
371 return $Mail::SpamAssassin::Conf::INVALID_VALUE;
372 }
373 }
374 });
375
376 push (@cmds, {
377 setting => 'uridnsbl_skip_domain',
378 default => {},
379 code => sub {
380 my ($self, $key, $value, $line) = @_;
381 if ($value =~ /^$/) {
382 return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
383 }
384 foreach my $domain (split(/\s+/, $value)) {
385 $self->{uridnsbl_skip_domains}->{lc $domain} = 1;
386 }
387 }
388 });
389
390 # obsolete
391 push(@cmds, {
392 setting => 'uridnsbl_timeout',
393 code => sub {
394 # not a lint_warn(), since it's pretty harmless and we don't want
395 # to break stuff like sa-update
396 warn("config: 'uridnsbl_timeout' is obsolete, use 'rbl_timeout' instead");
397 return 0;
398 }
399 });
400
401 $conf->{parser}->register_commands(\@cmds);
402 }
403
404 # ---------------------------------------------------------------------------
405
406 sub query_domain {
407 my ($self, $scanner, $dom) = @_;
408
409 #warn "uridnsbl: domain $dom\n";
410 #return;
411
412 $dom = lc $dom;
413 return if $scanner->{uridnsbl_seen_domain}->{$dom};
414 $scanner->{uridnsbl_seen_domain}->{$dom} = 1;
415 $self->log_dns_result("querying domain $dom");
416
417 my $obj = { dom => $dom };
418
419 my $single_dnsbl = 0;
420 if ($dom =~ /^\d+\.\d+\.\d+\.\d+$/) {
421 my $IPV4_ADDRESS = IPV4_ADDRESS;
422 my $IP_PRIVATE = IP_PRIVATE;
423 # only look up the IP if it is public and valid
424 if ($dom =~ /^$IPV4_ADDRESS$/ && $dom !~ /^$IP_PRIVATE$/) {
425 $self->lookup_dnsbl_for_ip($scanner, $obj, $dom);
426 # and check the IP in RHSBLs too
427 if ($dom =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
428 $dom = "$4.$3.$2.$1";
429 $single_dnsbl = 1;
430 }
431 }
432 }
433 else {
434 $single_dnsbl = 1;
435 }
436
437 if ($single_dnsbl) {
438 # look up the domain in the RHSBL subset
439 my $cf = $scanner->{uridnsbl_active_rules_rhsbl};
440 foreach my $rulename (keys %{$cf}) {
441 my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
442 $self->lookup_single_dnsbl($scanner, $obj, $rulename,
443 $dom, $rulecf->{zone}, $rulecf->{type});
444
445 # see comment below
446 $scanner->register_async_rule_start($rulename);
447 }
448
449 # perform NS, A lookups to look up the domain in the non-RHSBL subset
450 if ($dom !~ /^\d+\.\d+\.\d+\.\d+$/) {
451 $self->lookup_domain_ns($scanner, $obj, $dom);
452 }
453 }
454
455 # note that these rules are now underway. important: unless the
456 # rule hits, in the current design, these will not be considered
457 # "finished" until harvest_dnsbl_queries() completes
458 my $cf = $scanner->{uridnsbl_active_rules_revipbl};
459 foreach my $rulename (keys %{$cf}) {
460 $scanner->register_async_rule_start($rulename);
461 }
462 }
463
464 # ---------------------------------------------------------------------------
465
466 sub lookup_domain_ns {
467 my ($self, $scanner, $obj, $dom) = @_;
468
469 my $key = "NS:".$dom;
470 return if $scanner->{async}->get_lookup($key);
471
472 # dig $dom ns
473 my $ent = $self->start_lookup($scanner, 'NS',
474 $self->res_bgsend($scanner, $dom, 'NS', $key),
475 $key);
476 $ent->{obj} = $obj;
477 }
478
479 sub complete_ns_lookup {
480 my ($self, $scanner, $ent, $dom) = @_;
481
482 my $packet = $ent->{response_packet};
483 my @answer = $packet->answer;
484
485 my $IPV4_ADDRESS = IPV4_ADDRESS;
486 my $IP_PRIVATE = IP_PRIVATE;
487
488 foreach my $rr (@answer) {
489 my $str = $rr->string;
490 next unless (defined($str) && defined($dom));
491 $self->log_dns_result ("NSs for $dom: $str");
492
493 if ($str =~ /IN\s+NS\s+(\S+)/) {
494 my $nsmatch = $1;
495
496 if ($nsmatch =~ /^\d+\.\d+\.\d+\.\d+\.?$/) {
497 $nsmatch =~ s/\.$//;
498 # only look up the IP if it is public and valid
499 if ($nsmatch =~ /^$IPV4_ADDRESS$/ && $nsmatch !~ /^$IP_PRIVATE$/) {
500 $self->lookup_dnsbl_for_ip($scanner, $ent->{obj}, $nsmatch);
501 }
502 }
503 else {
504 $self->lookup_a_record($scanner, $ent->{obj}, $nsmatch);
505 }
506 }
507 }
508 }
509
510 # ---------------------------------------------------------------------------
511
512 sub lookup_a_record {
513 my ($self, $scanner, $obj, $hname) = @_;
514
515 my $key = "A:".$hname;
516 return if $scanner->{async}->get_lookup($key);
517
518 # dig $hname a
519 my $ent = $self->start_lookup($scanner, 'A',
520 $self->res_bgsend($scanner, $hname, 'A', $key),
521 $key);
522 $ent->{obj} = $obj;
523 }
524
525 sub complete_a_lookup {
526 my ($self, $scanner, $ent, $hname) = @_;
527
528 foreach my $rr ($ent->{response_packet}->answer) {
529 my $str = $rr->string;
530 $self->log_dns_result ("A for NS $hname: $str");
531
532 if ($str =~ /IN\s+A\s+(\S+)/) {
533 $self->lookup_dnsbl_for_ip($scanner, $ent->{obj}, $1);
534 }
535 }
536 }
537
538 # ---------------------------------------------------------------------------
539
540 sub lookup_dnsbl_for_ip {
541 my ($self, $scanner, $obj, $ip) = @_;
542
543 $ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
544 my $revip = "$4.$3.$2.$1";
545
546 my $cf = $scanner->{uridnsbl_active_rules_revipbl};
547 foreach my $rulename (keys %{$cf}) {
548 my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
549 $self->lookup_single_dnsbl($scanner, $obj, $rulename,
550 $revip, $rulecf->{zone}, $rulecf->{type});
551 }
552 }
553
554 sub lookup_single_dnsbl {
555 my ($self, $scanner, $obj, $rulename, $lookupstr, $dnsbl, $qtype) = @_;
556
557 my $key = "DNSBL:".$dnsbl.":".$lookupstr;
558 return if $scanner->{async}->get_lookup($key);
559 my $item = $lookupstr.".".$dnsbl;
560
561 # dig $ip txt
562 my $ent = $self->start_lookup($scanner, 'DNSBL',
563 $self->res_bgsend($scanner, $item, $qtype, $key),
564 $key);
565 $ent->{obj} = $obj;
566 $ent->{rulename} = $rulename;
567 $ent->{zone} = $dnsbl;
568 }
569
570 sub complete_dnsbl_lookup {
571 my ($self, $scanner, $ent, $dnsblip) = @_;
572
573 my $conf = $scanner->{conf};
574 my @subtests;
575 my $rulename = $ent->{rulename};
576 my $rulecf = $conf->{uridnsbls}->{$rulename};
577
578 my $packet = $ent->{response_packet};
579 my @answer = $packet->answer;
580
581 my $uridnsbl_subs = $conf->{uridnsbl_subs}->{$ent->{zone}};
582 foreach my $rr (@answer)
583 {
584 next if ($rr->type ne 'A' && $rr->type ne 'TXT');
585
586 my $rdatastr = $rr->rdatastr;
587 my $dom = $ent->{obj}->{dom};
588
589 if (!$rulecf->{is_subrule}) {
590 # this zone is a simple rule, not a set of subrules
591 # skip any A record that isn't on 127/8
592 if ($rr->type eq 'A' && $rr->rdatastr !~ /^127\./) {
593 warn("uridnsbl: bogus rr for domain=$dom, rule=$rulename, id=" .
594 $packet->header->id." rr=".$rr->string);
595 next;
596 }
597 $self->got_dnsbl_hit($scanner, $ent, $rdatastr, $dom, $rulename);
598 }
599 else {
600 foreach my $subtest (keys (%{$uridnsbl_subs}))
601 {
602 if ($subtest eq $rdatastr) {
603 foreach my $subrulename (@{$uridnsbl_subs->{$subtest}->{rulenames}}) {
604 $self->got_dnsbl_hit($scanner, $ent, $rdatastr, $dom, $subrulename);
605 }
606 }
607 # bitmask
608 elsif ($subtest =~ /^\d+$/) {
609 if ($rdatastr =~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ &&
610 Mail::SpamAssassin::Util::my_inet_aton($rdatastr) & $subtest)
611 {
612 foreach my $subrulename (@{$uridnsbl_subs->{$subtest}->{rulenames}}) {
613 $self->got_dnsbl_hit($scanner, $ent, $rdatastr, $dom, $subrulename);
614 }
615 }
616 }
617 }
618 }
619 }
620 }
621
622 sub got_dnsbl_hit {
623 my ($self, $scanner, $ent, $str, $dom, $rulename) = @_;
624
625 $str =~ s/\s+/ /gs; # long whitespace => short
626 dbg("uridnsbl: domain \"$dom\" listed ($rulename): $str");
627
628 if (!defined $scanner->{uridnsbl_hits}->{$rulename}) {
629 $scanner->{uridnsbl_hits}->{$rulename} = { };
630 };
631 $scanner->{uridnsbl_hits}->{$rulename}->{$dom} = 1;
632
633 if ($scanner->{uridnsbl_active_rules_revipbl}->{$rulename}
634 || $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename})
635 {
636 # TODO: this needs to handle multiple domain hits per rule
637 $scanner->clear_test_state();
638 my $uris = join (' ', keys %{$scanner->{uridnsbl_hits}->{$rulename}});
639 $scanner->test_log ("URIs: $uris");
640 $scanner->got_hit ($rulename, "");
641
642 # note that this rule has completed (since it got at least 1 hit)
643 $scanner->register_async_rule_finish($rulename);
644 }
645 }
646
647 # ---------------------------------------------------------------------------
648
649 sub start_lookup {
650 my ($self, $scanner, $type, $id, $key) = @_;
651
652 my $ent = {
653 key => $key,
654 timeout => $scanner->{conf}->{rbl_timeout},
655 type => "URI-".$type,
656 id => $id,
657 completed_callback => sub {
658 my $ent = shift;
659 $self->completed_lookup_callback ($scanner, $ent);
660 }
661 };
662 $scanner->{async}->start_lookup($ent);
663 return $ent;
664 }
665
666 sub completed_lookup_callback {
667 my ($self, $scanner, $ent) = @_;
668 my $type = $ent->{type};
669 my $key = $ent->{key};
670 $key =~ /:(\S+?)$/; my $val = $1;
671
672 if ($type eq 'URI-NS') {
673 $self->complete_ns_lookup ($scanner, $ent, $val);
674 }
675 elsif ($type eq 'URI-A') {
676 $self->complete_a_lookup ($scanner, $ent, $val);
677 }
678 elsif ($type eq 'URI-DNSBL') {
679 $self->complete_dnsbl_lookup ($scanner, $ent, $val);
680 }
681 }
682
683 # ---------------------------------------------------------------------------
684
685 sub res_bgsend {
686 my ($self, $scanner, $host, $type, $key) = @_;
687
688 return $self->{main}->{resolver}->bgsend($host, $type, undef, sub {
689 my ($pkt, $id, $timestamp) = @_;
690 $scanner->{async}->set_response_packet($id, $pkt, $key, $timestamp);
691 });
692 }
693
694 sub log_dns_result {
695 #my $self = shift;
696 #Mail::SpamAssassin::dbg("uridnsbl: ".join (' ', @_));
697 }
698
699 # ---------------------------------------------------------------------------
700
701 1;

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2