~ubuntu-branches/ubuntu/utopic/spamassassin/utopic-proposed

« back to all changes in this revision

Viewing changes to lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm

  • Committer: Bazaar Package Importer
  • Author(s): Noah Meyerhans
  • Date: 2010-01-26 22:53:12 UTC
  • mfrom: (1.1.13 upstream) (5.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100126225312-wkftb10idc1kz2aq
Tags: 3.3.0-1
* New upstream version.
* Switch to dpkg-source 3.0 (quilt) format

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
 
36
36
=over 4
37
37
 
 
38
=item skip_uribl_checks ( 0 | 1 )   (default: 0)
 
39
 
 
40
Turning on the skip_uribl_checks setting will disable the URIDNSBL plugin.
 
41
 
 
42
By default, SpamAssassin will run URI DNSBL checks. Individual URI blocklists
 
43
may be disabled selectively by setting a score of a corresponding rule to 0
 
44
or through the uridnsbl_skip_domain parameter.
 
45
 
 
46
See also a related configuration parameter skip_rbl_checks,
 
47
which controls the DNSEval plugin (documented in the Conf man page).
 
48
 
 
49
=back
 
50
 
 
51
=over 4
 
52
 
38
53
=item uridnsbl_skip_domain domain1 domain2 ...
39
54
 
40
55
Specify a domain, or a number of domains, which should be skipped for the
60
75
 body            URIBL_SBLXBL    eval:check_uridnsbl('URIBL_SBLXBL')
61
76
 describe        URIBL_SBLXBL    Contains a URL listed in the SBL/XBL blocklist
62
77
 
 
78
=item uridnssub NAME_OF_RULE dnsbl_zone lookuptype subtest
 
79
 
 
80
Specify a DNSBL-style domain lookup with a sub-test.  C<NAME_OF_RULE> is the
 
81
name of the rule to be used, C<dnsbl_zone> is the zone to look up IPs in,
 
82
and C<lookuptype> is the type of lookup (B<TXT> or B<A>).
 
83
 
 
84
C<subtest> is the sub-test to run against the returned data.  The sub-test may
 
85
either be an IPv4 dotted address for DNSBLs that return multiple A records or a
 
86
non-negative decimal number to specify a bitmask for DNSBLs that return a
 
87
single A record containing a bitmask of results.
 
88
 
 
89
Note that, as with C<uridnsbl>, you must also define a body-eval rule calling
 
90
C<check_uridnsbl()> to use this.
 
91
 
 
92
Example:
 
93
 
 
94
  uridnssub   URIBL_DNSBL_4    dnsbl.example.org.   A    127.0.0.4
 
95
  uridnssub   URIBL_DNSBL_8    dnsbl.example.org.   A    8
 
96
 
63
97
=item urirhsbl NAME_OF_RULE rhsbl_zone lookuptype
64
98
 
65
99
Specify a RHSBL-style domain lookup.  C<NAME_OF_RULE> is the name of the rule
74
108
C<bar.com.uriblzone.net>, and C<foo.bar.co.uk> will look up
75
109
C<bar.co.uk.uriblzone.net>.
76
110
 
77
 
If a URI consists IP address instead of a hostname, the IP address is looked
78
 
up (using the standard reversed quads method) in each C<rhsbl_zone>.
 
111
If an URI consists of an IP address instead of a hostname, the IP address is
 
112
looked up (using the standard reversed quads method) in each C<rhsbl_zone>.
79
113
 
80
114
Example:
81
115
 
100
134
  urirhssub   URIBL_RHSBL_4    rhsbl.example.org.   A    127.0.0.4
101
135
  urirhssub   URIBL_RHSBL_8    rhsbl.example.org.   A    8
102
136
 
 
137
=item urinsrhsbl NAME_OF_RULE rhsbl_zone lookuptype
 
138
 
 
139
Perform a RHSBL-style domain lookup against the contents of the NS records
 
140
for each URI.  In other words, a URI using the domain C<foo.com> will cause
 
141
an NS lookup to take place; assuming that domain has an NS of C<ns0.bar.com>,
 
142
that will cause a lookup of C<bar.com.uriblzone.net>.  Note that hostnames
 
143
are stripped from both the domain used in the URI, and the domain in the
 
144
lookup.
 
145
 
 
146
C<NAME_OF_RULE> is the name of the rule to be used, C<rhsbl_zone> is the zone
 
147
to look up domain names in, and C<lookuptype> is the type of lookup (B<TXT> or
 
148
B<A>).
 
149
 
 
150
Note that, as with C<urirhsbl>, you must also define a body-eval rule calling
 
151
C<check_uridnsbl()> to use this.
 
152
 
 
153
=item urinsrhssub NAME_OF_RULE rhsbl_zone lookuptype subtest
 
154
 
 
155
Specify a RHSBL-style domain-NS lookup, as above, with a sub-test.
 
156
C<NAME_OF_RULE> is the name of the rule to be used, C<rhsbl_zone> is the zone
 
157
to look up domain names in, and C<lookuptype> is the type of lookup (B<TXT> or
 
158
B<A>).  C<subtest> is the sub-test to run against the returned data; see
 
159
<urirhssub>.
 
160
 
 
161
Note that, as with C<urirhsbl>, you must also define a body-eval rule calling
 
162
C<check_uridnsbl()> to use this.
 
163
 
 
164
=item urifullnsrhsbl NAME_OF_RULE rhsbl_zone lookuptype
 
165
 
 
166
Perform a RHSBL-style domain lookup against the contents of the NS records for
 
167
each URI.  In other words, a URI using the domain C<foo.com> will cause an NS
 
168
lookup to take place; assuming that domain has an NS of C<ns0.bar.com>, that
 
169
will cause a lookup of C<ns0.bar.com.uriblzone.net>.  Note that hostnames are
 
170
stripped from the domain used in the URI.
 
171
 
 
172
C<NAME_OF_RULE> is the name of the rule to be used, C<rhsbl_zone> is the zone
 
173
to look up domain names in, and C<lookuptype> is the type of lookup (B<TXT> or
 
174
B<A>).
 
175
 
 
176
Note that, as with C<urirhsbl>, you must also define a body-eval rule calling
 
177
C<check_uridnsbl()> to use this.
 
178
 
 
179
=item urifullnsrhssub NAME_OF_RULE rhsbl_zone lookuptype subtest
 
180
 
 
181
Specify a RHSBL-style domain-NS lookup, as above, with a sub-test.
 
182
C<NAME_OF_RULE> is the name of the rule to be used, C<rhsbl_zone> is the zone
 
183
to look up domain names in, and C<lookuptype> is the type of lookup (B<TXT> or
 
184
B<A>).  C<subtest> is the sub-test to run against the returned data; see
 
185
<urirhssub>.
 
186
 
 
187
Note that, as with C<urirhsbl>, you must also define a body-eval rule calling
 
188
C<check_uridnsbl()> to use this.
 
189
 
103
190
=back
104
191
 
105
192
=head1 ADMINISTRATOR SETTINGS
124
211
use Mail::SpamAssassin::Plugin;
125
212
use Mail::SpamAssassin::Constants qw(:ip);
126
213
use Mail::SpamAssassin::Util;
 
214
use Mail::SpamAssassin::Util::RegistrarBoundaries;
127
215
use Mail::SpamAssassin::Logger;
128
216
use strict;
129
217
use warnings;
130
218
use bytes;
 
219
use re 'taint';
131
220
 
132
221
use vars qw(@ISA);
133
222
@ISA = qw(Mail::SpamAssassin::Plugin);
167
256
  my ($self, $opts) = @_;
168
257
  my $scanner = $opts->{permsgstatus};
169
258
 
 
259
  return 0  if $scanner->{main}->{conf}->{skip_uribl_checks};
 
260
 
170
261
  if (!$scanner->is_dns_available()) {
171
262
    $self->{dns_not_available} = 1;
172
 
    return;
 
263
    return 0;
173
264
  } else {
174
265
    # due to re-testing dns may become available after being unavailable
175
266
    # DOS: I don't think dns_not_available is even used anymore
182
273
 
183
274
  # only hit DNSBLs for active rules (defined and score != 0)
184
275
  $scanner->{'uridnsbl_active_rules_rhsbl'} = { };
 
276
  $scanner->{'uridnsbl_active_rules_nsrhsbl'} = { };
 
277
  $scanner->{'uridnsbl_active_rules_fullnsrhsbl'} = { };
185
278
  $scanner->{'uridnsbl_active_rules_revipbl'} = { };
186
279
 
187
280
  foreach my $rulename (keys %{$scanner->{conf}->{uridnsbls}}) {
190
283
    my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
191
284
    if ($rulecf->{is_rhsbl}) {
192
285
      $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename} = 1;
 
286
    } elsif ($rulecf->{is_fullnsrhsbl}) {
 
287
      $scanner->{uridnsbl_active_rules_fullnsrhsbl}->{$rulename} = 1;
 
288
    } elsif ($rulecf->{is_nsrhsbl}) {
 
289
      $scanner->{uridnsbl_active_rules_nsrhsbl}->{$rulename} = 1;
193
290
    } else {
194
291
      $scanner->{uridnsbl_active_rules_revipbl}->{$rulename} = 1;
195
292
    }
200
297
  # don't keep dereferencing this
201
298
  my $skip_domains = $scanner->{main}->{conf}->{uridnsbl_skip_domains};
202
299
 
203
 
  # list of arrays to use in order
204
 
  my @uri_ordered = ();
 
300
  # list of hashes to use in order
 
301
  my @uri_ordered;
205
302
 
206
303
  # Generate the full list of html-parsed domains.
207
304
  my $uris = $scanner->get_uri_detail_list();
255
352
 
256
353
  # at this point, @uri_ordered is an ordered array of uri hashes
257
354
 
258
 
  my %domlist = ();
 
355
  my %domlist;
259
356
  my $umd = $scanner->{main}->{conf}->{uridnsbl_max_domains};
260
357
  while (keys %domlist < $umd && @uri_ordered) {
261
358
    my $array = shift @uri_ordered;
292
389
 
293
390
sub set_config {
294
391
  my($self, $conf) = @_;
295
 
  my @cmds = ();
 
392
  my @cmds;
 
393
 
 
394
  push(@cmds, {
 
395
    setting => 'skip_uribl_checks',
 
396
    default => 0,
 
397
    type => $Mail::SpamAssassin::Conf::CONF_TYPE_BOOL,
 
398
  });
296
399
 
297
400
  push(@cmds, {
298
401
    setting => 'uridnsbl_max_domains',
325
428
  });
326
429
 
327
430
  push (@cmds, {
 
431
    setting => 'uridnssub',
 
432
    is_priv => 1,
 
433
    code => sub {
 
434
      my ($self, $key, $value, $line) = @_;
 
435
      if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\d{1,10}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) {
 
436
        my $rulename = $1;
 
437
        my $zone = $2;
 
438
        my $type = $3;
 
439
        my $subrule = $4;
 
440
        $self->{uridnsbls}->{$rulename} = {
 
441
         zone => $zone, type => $type,
 
442
          is_rhsbl => 0, is_subrule => 1
 
443
        };
 
444
        $self->{uridnsbl_subs}->{$zone} ||= { };
 
445
        push (@{$self->{uridnsbl_subs}->{$zone}->{$subrule}->{rulenames}}, $rulename);
 
446
      }
 
447
      elsif ($value =~ /^$/) {
 
448
        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
 
449
      }
 
450
      else {
 
451
        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
 
452
      }
 
453
    }
 
454
  });
 
455
 
 
456
  push (@cmds, {
328
457
    setting => 'urirhsbl',
329
458
    is_priv => 1,
330
459
    code => sub {
374
503
  });
375
504
 
376
505
  push (@cmds, {
 
506
    setting => 'urinsrhsbl',
 
507
    is_priv => 1,
 
508
    code => sub {
 
509
      my ($self, $key, $value, $line) = @_;
 
510
      if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/) {
 
511
        my $rulename = $1;
 
512
        my $zone = $2;
 
513
        my $type = $3;
 
514
        $self->{uridnsbls}->{$rulename} = {
 
515
          zone => $zone, type => $type,
 
516
          is_nsrhsbl => 1
 
517
        };
 
518
      }
 
519
      elsif ($value =~ /^$/) {
 
520
        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
 
521
      }
 
522
      else {
 
523
        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
 
524
      }
 
525
    }
 
526
  });
 
527
 
 
528
  push (@cmds, {
 
529
    setting => 'urinsrhssub',
 
530
    is_priv => 1,
 
531
    code => sub {
 
532
      my ($self, $key, $value, $line) = @_;
 
533
      if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\d{1,10}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) {
 
534
        my $rulename = $1;
 
535
        my $zone = $2;
 
536
        my $type = $3;
 
537
        my $subrule = $4;
 
538
        $self->{uridnsbls}->{$rulename} = {
 
539
          zone => $zone, type => $type,
 
540
          is_nsrhsbl => 1, is_subrule => 1
 
541
        };
 
542
        $self->{uridnsbl_subs}->{$zone} ||= { };
 
543
        push (@{$self->{uridnsbl_subs}->{$zone}->{$subrule}->{rulenames}}, $rulename);
 
544
      }
 
545
      elsif ($value =~ /^$/) {
 
546
        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
 
547
      }
 
548
      else {
 
549
        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
 
550
      }
 
551
    }
 
552
  });
 
553
 
 
554
  push (@cmds, {
 
555
    setting => 'urifullnsrhsbl',
 
556
    is_priv => 1,
 
557
    code => sub {
 
558
      my ($self, $key, $value, $line) = @_;
 
559
      if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/) {
 
560
        my $rulename = $1;
 
561
        my $zone = $2;
 
562
        my $type = $3;
 
563
        $self->{uridnsbls}->{$rulename} = {
 
564
          zone => $zone, type => $type,
 
565
          is_fullnsrhsbl => 1
 
566
        };
 
567
      }
 
568
      elsif ($value =~ /^$/) {
 
569
        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
 
570
      }
 
571
      else {
 
572
        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
 
573
      }
 
574
    }
 
575
  });
 
576
 
 
577
  push (@cmds, {
 
578
    setting => 'urifullnsrhssub',
 
579
    is_priv => 1,
 
580
    code => sub {
 
581
      my ($self, $key, $value, $line) = @_;
 
582
      if ($value =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\d{1,10}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) {
 
583
        my $rulename = $1;
 
584
        my $zone = $2;
 
585
        my $type = $3;
 
586
        my $subrule = $4;
 
587
        $self->{uridnsbls}->{$rulename} = {
 
588
          zone => $zone, type => $type,
 
589
          is_fullnsrhsbl => 1, is_subrule => 1
 
590
        };
 
591
        $self->{uridnsbl_subs}->{$zone} ||= { };
 
592
        push (@{$self->{uridnsbl_subs}->{$zone}->{$subrule}->{rulenames}}, $rulename);
 
593
      }
 
594
      elsif ($value =~ /^$/) {
 
595
        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
 
596
      }
 
597
      else {
 
598
        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
 
599
      }
 
600
    }
 
601
  });
 
602
 
 
603
  push (@cmds, {
377
604
    setting => 'uridnsbl_skip_domain',
378
605
    default => {},
 
606
    type => $Mail::SpamAssassin::Conf::CONF_TYPE_HASH_KEY_VALUE,
379
607
    code => sub {
380
608
      my ($self, $key, $value, $line) = @_;
381
609
      if ($value =~ /^$/) {
414
642
  $scanner->{uridnsbl_seen_domain}->{$dom} = 1;
415
643
  $self->log_dns_result("querying domain $dom");
416
644
 
417
 
  my $obj = {
418
 
    querystart => time,
419
 
    dom => $dom
420
 
  };
 
645
  my $obj = { dom => $dom };
421
646
 
422
647
  my $single_dnsbl = 0;
423
648
  if ($dom =~ /^\d+\.\d+\.\d+\.\d+$/) {
437
662
    $single_dnsbl = 1;
438
663
  }
439
664
 
 
665
  my $rhsblrules = $scanner->{uridnsbl_active_rules_rhsbl};
 
666
  my $nsrhsblrules = $scanner->{uridnsbl_active_rules_nsrhsbl};
 
667
  my $fullnsrhsblrules = $scanner->{uridnsbl_active_rules_fullnsrhsbl};
 
668
  my $reviprules = $scanner->{uridnsbl_active_rules_revipbl};
 
669
 
440
670
  if ($single_dnsbl) {
441
671
    # look up the domain in the RHSBL subset
442
 
    my $cf = $scanner->{uridnsbl_active_rules_rhsbl};
443
 
    foreach my $rulename (keys %{$cf}) {
 
672
    foreach my $rulename (keys %{$rhsblrules}) {
444
673
      my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
445
674
      $self->lookup_single_dnsbl($scanner, $obj, $rulename,
446
675
                                 $dom, $rulecf->{zone}, $rulecf->{type});
449
678
      $scanner->register_async_rule_start($rulename);
450
679
    }
451
680
 
452
 
    # perform NS, A lookups to look up the domain in the non-RHSBL subset
453
 
    if ($dom !~ /^\d+\.\d+\.\d+\.\d+$/) {
 
681
    # perform NS, A lookups to look up the domain in the non-RHSBL subset,
 
682
    # but only if there are active reverse-IP-URIBL rules
 
683
    if ($dom !~ /^\d+\.\d+\.\d+\.\d+$/ && 
 
684
                (scalar keys %{$reviprules} ||
 
685
                  scalar keys %{$nsrhsblrules} ||
 
686
                  scalar keys %{$fullnsrhsblrules}))
 
687
    {
454
688
      $self->lookup_domain_ns($scanner, $obj, $dom);
455
689
    }
456
690
  }
458
692
  # note that these rules are now underway.   important: unless the
459
693
  # rule hits, in the current design, these will not be considered
460
694
  # "finished" until harvest_dnsbl_queries() completes
461
 
  my $cf = $scanner->{uridnsbl_active_rules_revipbl};
462
 
  foreach my $rulename (keys %{$cf}) {
 
695
  foreach my $rulename (keys %{$reviprules}) {
463
696
    $scanner->register_async_rule_start($rulename);
464
697
  }
465
698
}
487
720
 
488
721
  my $IPV4_ADDRESS = IPV4_ADDRESS;
489
722
  my $IP_PRIVATE = IP_PRIVATE;
 
723
  my $nsrhsblrules = $scanner->{uridnsbl_active_rules_nsrhsbl};
 
724
  my $fullnsrhsblrules = $scanner->{uridnsbl_active_rules_fullnsrhsbl};
490
725
 
491
726
  foreach my $rr (@answer) {
492
727
    my $str = $rr->string;
495
730
 
496
731
    if ($str =~ /IN\s+NS\s+(\S+)/) {
497
732
      my $nsmatch = $1;
 
733
      my $nsrhblstr = $nsmatch;
 
734
      my $fullnsrhblstr = $nsmatch;
 
735
      $fullnsrhblstr =~ s/\.$//;
498
736
 
499
737
      if ($nsmatch =~ /^\d+\.\d+\.\d+\.\d+\.?$/) {
500
738
        $nsmatch =~ s/\.$//;
502
740
        if ($nsmatch =~ /^$IPV4_ADDRESS$/ && $nsmatch !~ /^$IP_PRIVATE$/) {
503
741
          $self->lookup_dnsbl_for_ip($scanner, $ent->{obj}, $nsmatch);
504
742
        }
 
743
        $nsrhblstr = $nsmatch;
505
744
      }
506
745
      else {
507
746
        $self->lookup_a_record($scanner, $ent->{obj}, $nsmatch);
 
747
        $nsrhblstr = Mail::SpamAssassin::Util::RegistrarBoundaries::trim_domain($nsmatch);
 
748
      }
 
749
 
 
750
      foreach my $rulename (keys %{$nsrhsblrules}) {
 
751
        my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
 
752
        $self->lookup_single_dnsbl($scanner, $ent->{obj}, $rulename,
 
753
                                  $nsrhblstr, $rulecf->{zone}, $rulecf->{type});
 
754
 
 
755
        $scanner->register_async_rule_start($rulename);
 
756
      }
 
757
 
 
758
      foreach my $rulename (keys %{$fullnsrhsblrules}) {
 
759
        my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename};
 
760
        $self->lookup_single_dnsbl($scanner, $ent->{obj}, $rulename,
 
761
                                  $fullnsrhblstr, $rulecf->{zone}, $rulecf->{type});
 
762
 
 
763
        $scanner->register_async_rule_start($rulename);
508
764
      }
509
765
    }
510
766
  }
576
832
  my ($self, $scanner, $ent, $dnsblip) = @_;
577
833
 
578
834
  my $conf = $scanner->{conf};
579
 
  my @subtests = ();
 
835
  my @subtests;
580
836
  my $rulename = $ent->{rulename};
581
837
  my $rulecf = $conf->{uridnsbls}->{$rulename};
582
838
 
636
892
  $scanner->{uridnsbl_hits}->{$rulename}->{$dom} = 1;
637
893
 
638
894
  if ($scanner->{uridnsbl_active_rules_revipbl}->{$rulename}
 
895
    || $scanner->{uridnsbl_active_rules_nsrhsbl}->{$rulename}
 
896
    || $scanner->{uridnsbl_active_rules_fullnsrhsbl}->{$rulename}
639
897
    || $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename})
640
898
  {
641
899
    # TODO: this needs to handle multiple domain hits per rule
666
924
      }
667
925
    }
668
926
  };
669
 
  $scanner->{async}->start_lookup($ent);
 
927
  $scanner->{async}->start_lookup($ent, $scanner->{master_deadline});
670
928
  return $ent;
671
929
}
672
930