check for AA flag
authorHeiko Schlittermann (JUMPER) <hs@schlittermann.de>
Tue, 30 Dec 2014 14:40:45 +0100
changeset 5 2e27cfdf85ea
parent 4 ebada07bb701
child 6 eac6751d5bff
check for AA flag Make sure that we compare the authoritive answers with the outside worlds view.
Build.PL
plugins/check_dns-serial
t/10-minimal.t
--- a/Build.PL	Tue Dec 30 12:24:43 2014 +0100
+++ b/Build.PL	Tue Dec 30 14:40:45 2014 +0100
@@ -13,7 +13,7 @@
     license  => 'perl',
     requires => {
         perl       => '5.14.2',
-        'Net::DNS' => '0.74',
+        'Net::DNS' => '0.66',
     },
     test_requires => {
         'Test::Exception' => '0.32',
--- a/plugins/check_dns-serial	Tue Dec 30 12:24:43 2014 +0100
+++ b/plugins/check_dns-serial	Tue Dec 30 14:40:45 2014 +0100
@@ -44,8 +44,8 @@
 use Getopt::Long qw(GetOptionsFromArray);
 use Net::DNS;
 use Pod::Usage;
+use Smart::Comments;
 
-my %resolver;
 sub uniq { my %h; @h{@_} = (); return keys %h; }
 
 # return a list of the zones known to the local
@@ -94,26 +94,30 @@
 }
 
 # return a list of "official" nameservers
-sub get_ns {
-    my ($nameserver) = map { /^\@(.*)/ } $_[0] =~ /^\@/ ? shift : '@8.8.8.8';
-    my ($domain) = @_;
+sub ns {
+    my $domain = shift;
+    ### assert: @_ % 2 == 0
+    my %resflags = (nameservers => [qw/8.8.8.8/], @_);
+    my $aa = delete $resflags{aa};
+    my $nameservers = $resflags{nameservers};
     my @ns;
 
-    my $r = $resolver{$nameserver} //=
-      Net::DNS::Resolver->new(nameservers => [$nameserver]);
-    my $q = $r->query($domain, 'NS') or die $r->errorstring, "\@$nameserver\n";
+    my $r = Net::DNS::Resolver->new(%resflags);
+    my $q = $r->query($domain, 'NS') or die $r->errorstring, "\@@$nameservers\n";
+
+    die "no aa @@$nameservers\n" if $aa and not $q->header->aa;
     push @ns, map { $_->nsdname } grep { $_->type eq 'NS' } $q->answer;
 
     return sort @ns;
 }
 
-sub get_serial {
-    my ($nameserver) = map { /^\@(.*)/ } $_[0] =~ /^\@/ ? shift : '@8.8.8.8';
-    my ($domain) = shift;
+sub serial {
+    my $domain = shift;
+    my %resflags = (nameservers => [qw/8.8.8.8/], @_);
+    my $nameservers = $resflags{nameservers};
 
-    my $r = $resolver{$nameserver} //=
-      Net::DNS::Resolver->new(nameservers => [$nameserver]);
-    my $q = $r->query($domain, 'SOA') or die $r->errorstring, "\@$nameserver\n";
+    my $r = Net::DNS::Resolver->new(%resflags);
+    my $q = $r->query($domain, 'SOA') or die $r->errorstring, "\@@$nameservers\n";
     return (map { $_->serial } grep { $_->type eq 'SOA' } $q->answer)[0];
 }
 
@@ -127,10 +131,10 @@
 # CRITICAL - if the serial cannot be found at one of the sources
 
 sub ns_ok {
-    my ($reference, $domain) = @_;
+    my ($domain, $reference) = @_;
 
-    my @our = sort eval { get_ns($reference, $domain) };
-    my @their = sort +get_ns($domain);
+    my @our = sort +ns($domain, nameservers => [$reference], aa => 1);
+    my @their = sort +ns($domain);
 
     {
         local $" = "\0";
@@ -148,8 +152,6 @@
 
     GetOptionsFromArray(
         \@argv,
-## Please see file perltidy.ERR
-## Please see file perltidy.ERR
         'reference=s' => \$opt_reference,
         'progress!'   => \$opt_progress,
         'h|help'      => sub { pod2usage(-verbose => 1, -exit => 0) },
@@ -168,7 +170,7 @@
     my (@OK, %CRITICAL);
     foreach my $domain (@domains) {
         print STDERR "$domain " if $opt_progress;
-        eval { ns_ok('@212.80.235.130', $domain) };
+        eval { ns_ok($domain, $opt_reference) };
         if ($@) { $CRITICAL{$domain} = $@ }
         else    { push @OK, $domain }
         say STDERR $@ ? 'not ok' : 'ok' if $opt_progress;
--- a/t/10-minimal.t	Tue Dec 30 12:24:43 2014 +0100
+++ b/t/10-minimal.t	Tue Dec 30 14:40:45 2014 +0100
@@ -14,7 +14,10 @@
 $tmp->flush;
 
 sub dig_serial { (split " ", `dig +short SOA @_`)[2] }
-sub dig_ns { sort map { /(\S+?)\.?$/ } `dig +short NS @_` }
+
+sub dig_ns {
+    sort map { /(\S+?)\.?$/ } `dig +short NS @_`;
+}
 
 # we require it, it's not a normal module
 require_ok 'blib/nagios/plugins/ius/check_dns-serial'
@@ -31,23 +34,28 @@
 
 for (qw(heise.de schlittermann.de google.com debian.org example.org)) {
 
-        subtest $_ => sub {
+    subtest $_ => sub {
 
-            # get_ns should return the NS from public dns servers
-            is_deeply [get_ns($_)], [dig_ns($_)] => "ns \@default";
-            is_deeply [get_ns('@8.8.4.4', $_)], [dig_ns('@8.8.4.4', $_)] => "ns \@8.8.4.4";
-            is get_serial('@8.8.8.8', $_), dig_serial('@8.8.8.8', $_) => 'serial';
-        };
+        throws_ok { ns($_, nameservers => [qw/8.8.8.8/], aa => 1) }
+        qr/no aa/ => 'not authoritive @8.8.8.8';
+        is_deeply [ns($_)], [dig_ns($_)] => "ns \@default";
+        is_deeply [ns($_, nameservers => [qw/8.8.4.4/])],
+          [dig_ns('@8.8.4.4', $_)] => "ns \@8.8.4.4";
+        is serial($_, nameservers => [qw/8.8.8.8/]),
+          dig_serial('@8.8.8.8', $_) => 'serial';
+    };
 
 }
 
 # ns for some domain we're not the master for, should be refused
-throws_ok { get_ns('@212.80.235.130', 'heise.de') } qr/^REFUSED/ => 'throws on refused query';
-throws_ok { get_ns('safasdfasdfrandomadsfefvddeas') } qr/^NXDOMAIN/ => 'throws on nx domain';
+throws_ok { ns('example.org', nameservers => [qw/f.nic.de a.nic.de b.nic.de/]) }
+qr/^REFUSED/ => 'throws on refused query';
+throws_ok { ns('safasdfasdfrandomadsfefvddeas') }
+qr/^NXDOMAIN/ => 'throws on nx domain';
 
-ok ns_ok('@212.80.235.130', 'schlittermann.de') => 'ns for schlittermann.de';
-throws_ok { ns_ok('@212.80.235.130', 'heise.de') } qr/differ/ => 'ns for heise.de';
-
+ok ns_ok('schlittermann.de', '212.80.235.130') => 'ns_ok for schlittermann.de';
+throws_ok { ns_ok('heise.de', '212.80.235.130') } qr/no aa|differ|REFUSED/ => 'ns_ok for heise.de';
+throws_ok { ns_ok('heise.de', '8.8.8.8') } qr/no aa|differ|REFUSED/ => 'ns_ok for heise.de';
 
 # serial