dsa-check-zone-rrsig-expiration: document -r and -s in help output
[mirror/dsa-nagios.git] / dsa-nagios-checks / checks / dsa-check-zone-rrsig-expiration
index a915c4b..7250c7c 100755 (executable)
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.
 
+# Copyright (c) 2010 Peter Palfrader <peter@palfrader.org>
+# - various fixes and cleanups
+# - do more than one zone
+# Copyright (c) 2012 Peter Palfrader <peter@palfrader.org>
+#  - add -s option to configure udp packet size.  default changed from 4k to 1k
+# Copyright (c) 2013 Peter Palfrader <peter@palfrader.org>
+#  - add -r option to override initial refs.
+# Copyright (c) 2014 Peter Palfrader <peter@palfrader.org>
+#  - Do not ask for RRSIG directly, instead ask for SOA with dnssec data
+
+
 # usage
 #
 # define command {
@@ -71,18 +82,33 @@ use Time::HiRes qw ( gettimeofday tv_interval);
 use Time::Local;
 use List::Util qw ( shuffle );
 
-my %opts = (t=>30);
-getopts('Z:dt:', \%opts);
-usage() unless $opts{Z};
+sub convert_time {
+       my $in = shift;
+       my ($ticks, $unit) = ($in =~ /^(\d+)([smhdw]?)$/);
+
+       if ($unit eq 's' || $unit eq '') { }
+       elsif ($unit eq 'm') { $ticks *= 60; }
+       elsif ($unit eq 'h') { $ticks *= 60*60; }
+       elsif ($unit eq 'd') { $ticks *= 60*60*24; }
+       elsif ($unit eq 'w') { $ticks *= 60*60*24*7; }
+       else { die "Invalid unit '$unit' in '$in'\n" }
+       return $ticks;
+}
+
+my %opts = (t=>30, s=>1024);
+getopts('hdt:c:w:s:r:', \%opts);
+usage() unless scalar @ARGV == 1;
 usage() if $opts{h};
-my $zone = $opts{Z};
-$zone =~ s/^zone\.//;
+my $zone = $ARGV[0];
 
 my $data;
 my $start;
 my $stop;
-my $CRIT_DAYS = 3;
-my $WARN_DAYS = 7;
+my $CRIT = 3 * 3600*24;
+my $WARN = 7 * 3600*24;
+
+$CRIT = convert_time($opts{c}) if defined $opts{c};
+$WARN = convert_time($opts{w}) if defined $opts{w};
 
 my @refs = qw (
 a.root-servers.net
@@ -99,6 +125,7 @@ k.root-servers.net
 l.root-servers.net
 m.root-servers.net
 );
+@refs = split(/\s*,\s*/, $opts{r}) if (defined $opts{r});
 
 $start = [gettimeofday()];
 do_recursion();
@@ -112,25 +139,28 @@ sub do_recursion {
        do {
                print STDERR "\nRECURSE\n" if $opts{d};
                my $pkt;
+               my $prettyrefs = (scalar @refs) ? join(", ", @refs) : "empty set(!?)";
                foreach my $ns (shuffle @refs) {
-                       print STDERR "sending query for $zone RRSIG to $ns\n" if $opts{d};
+                       print STDERR "sending query for $zone NS to $ns\n" if $opts{d};
                        $res->nameserver($ns);
                        $res->udp_timeout($opts{t});
-                       $res->udppacketsize(4096);
-                       $pkt = $res->send($zone, 'RRSIG');
+                       $res->udppacketsize($opts{s});
+                       $pkt = $res->send($zone, 'NS');
                        last if $pkt;
                }
-               critical("No response to seed query") unless $pkt;
+               critical("No response to seed query for $zone from $prettyrefs.") unless $pkt;
                critical($pkt->header->rcode . " from " . $pkt->answerfrom)
                        unless ($pkt->header->rcode eq 'NOERROR');
                @refs = ();
-               foreach my $rr ($pkt->authority) {
+               foreach my $rr ($pkt->authority, $pkt->answer) {
                        print STDERR $rr->string, "\n" if $opts{d};
-                       push (@refs, $rr->nsdname);
+                       push (@refs, $rr->nsdname) if $rr->type eq 'NS';
                        next unless lc($rr->name) eq lc($zone);
                        add_nslist_to_data($pkt);
+                       #print STDERR "Adding for $zone: ", $pkt->string, "\n" if $opts{d};
                        $done = 1;
                }
+               critical("No new references after querying for $zone NS from $prettyrefs.  Packet was ".$pkt->string) unless (scalar @refs);
        } while (! $done);
 }
 
@@ -141,11 +171,11 @@ sub do_queries {
                $n = 0;
                foreach my $ns (keys %$data) {
                        next if $data->{$ns}->{done};
-                       print STDERR "\nQUERY $ns\n" if $opts{d};
+                       print STDERR "\nQUERY \@$ns SOA $zone\n" if $opts{d};
 
-                       my $pkt = send_query($zone, 'RRSIG', $ns);
+                       my $pkt = send_query($zone, 'SOA', $ns);
                        add_nslist_to_data($pkt);
-                       $data->{$ns}->{queries}->{RRSIG} = $pkt;
+                       $data->{$ns}->{queries}->{SOA} = $pkt;
 
                        print STDERR "done with $ns\n" if $opts{d};
                        $data->{$ns}->{done} = 1;
@@ -160,7 +190,7 @@ sub do_analyze {
        my %MAX_EXP_BY_TYPE;
        foreach my $ns (keys %$data) {
                print STDERR "\nANALYZE $ns\n" if $opts{d};
-               my $pkt = $data->{$ns}->{queries}->{RRSIG};
+               my $pkt = $data->{$ns}->{queries}->{SOA};
                critical("No response from $ns") unless $pkt;
                print STDERR $pkt->string if $opts{d};
                critical($pkt->header->rcode . " from $ns")
@@ -191,15 +221,15 @@ sub do_analyze {
                }
        }
        critical("$min_ns has expired RRSIGs") if ($min_exp < $NOW);
-       if ($min_exp - $NOW < ($CRIT_DAYS*86400)) {
+       if ($min_exp - $NOW < ($CRIT)) {
                my $ND = sprintf "%3.1f days", ($min_exp-$NOW)/86400;
                critical("$min_type RRSIG expires in $ND at $min_ns")
        }
-       if ($min_exp - $NOW < ($WARN_DAYS*86400)) {
+       if ($min_exp - $NOW < ($WARN)) {
                my $ND = sprintf "%3.1f days", ($min_exp-$NOW)/86400;
                warning("$min_type RRSIG expires in $ND at $min_ns")
        }
-       success("No RRSIGs expiring in the next $WARN_DAYS days");
+       success(sprintf("No RRSIGs at zone apex expiring in the next %3.1f days", $WARN/86400));
 }
 
 sub sigrr_exp_epoch {
@@ -249,7 +279,7 @@ sub output {
 }
 
 sub usage {
-       print STDERR "usage: $0 -Z zone\n";
+       print STDERR "usage: $0 [-d] [-w=<warn>] [-c=<crit>] [-t=<timeout>] [-r=<initialns1>[,<initialns2>[,..]] [-s=<packet-size>] <zone>\n";
        exit 3;
 }
 
@@ -260,8 +290,9 @@ sub send_query {
        my $res = Net::DNS::Resolver->new;
        $res->nameserver($server) if $server;
        $res->udp_timeout($opts{t});
+       $res->dnssec(1);
        $res->retry(2);
-       $res->udppacketsize(4096);
+       $res->udppacketsize($opts{s});
        my $pkt = $res->send($qname, $qtype);
        unless ($pkt) {
                $res->usevc(1);
@@ -274,11 +305,11 @@ sub send_query {
 sub get_nslist {
        my $pkt = shift;
        return () unless $pkt;
-       return () unless $pkt->authority;
+       return () if (!$pkt->authority && !$pkt->answer);
        my @nslist;
-       foreach my $rr ($pkt->authority) {
+       foreach my $rr ($pkt->authority, $pkt->answer) {
                next unless ($rr->type eq 'NS');
-               next unless ($rr->name eq $zone);
+               next unless lc($rr->name) eq lc($zone);
                push(@nslist, lc($rr->nsdname));
        }
        return @nslist;