X-Git-Url: https://git.adam-barratt.org.uk/?a=blobdiff_plain;ds=inline;f=dsa-nagios-checks%2Fchecks%2Fdsa-check-dnssec-delegation;h=82ffcd5e95e392ab1c220a889b7427490d85a99b;hb=99b3f8cd5e377af0bb167a3b5bb2e56bdac0b68b;hp=ff8f9202de4ebc889d533e1f86552078e257581a;hpb=3ba5f9f245f7343b9c9ebd9f4e808e9af7aa1d19;p=mirror%2Fdsa-nagios.git diff --git a/dsa-nagios-checks/checks/dsa-check-dnssec-delegation b/dsa-nagios-checks/checks/dsa-check-dnssec-delegation index ff8f920..82ffcd5 100755 --- a/dsa-nagios-checks/checks/dsa-check-dnssec-delegation +++ b/dsa-nagios-checks/checks/dsa-check-dnssec-delegation @@ -31,12 +31,14 @@ $SIG{'__DIE__'} = sub { print @_; exit 4; }; my $RES = Net::DNS::Resolver->new; my $DLV = 'dlv.isc.org'; +my $params; sub get_tag_generic { my $zone = shift; my $type = shift; my @result; + print "Querying $type $zone\n" if $params->{'verbose'}; my $pkt = $RES->send($zone, $type); return () unless $pkt; return () unless $pkt->answer; @@ -67,31 +69,104 @@ sub get_dlvtags { $zone .= ".".$DLV; return get_tag_generic($zone, 'DLV'); }; +sub has_dnskey_parent { + my $zone = shift; + + my $potential_parent; + if ($zone =~ m/\./) { + $potential_parent = $zone; + $potential_parent =~ s/^[^.]+\.//; + } else { + $potential_parent = '.'; + } + + print "Querying DNSKEY $potential_parent\n" if $params->{'verbose'}; + my $pkt = $RES->send($potential_parent, 'DNSKEY'); + return undef unless $pkt; + return undef unless $pkt->header; + + unless ($pkt->answer) { + return undef unless $pkt->authority; + for my $rr ($pkt->authority) { + next unless ($rr->type eq 'SOA'); + + $potential_parent = $rr->name; + print "Querying DNSKEY $potential_parent\n" if $params->{'verbose'}; + $pkt = $RES->send($potential_parent, 'DNSKEY'); + return undef unless $pkt; + last; + }; + }; + + return (0, $potential_parent) unless $pkt->answer; + for my $rr ($pkt->answer) { + next unless ($rr->type eq 'DNSKEY'); + return (1, $potential_parent); + }; +} +sub get_parent_dnssec_status { + my $zone = shift; + my @result; + + while (1) { + my ($status, $parent) = has_dnskey_parent($zone); + last unless defined $status; + push @result, ($status ? "yes" : "no") . ("($parent)"); + $zone = $parent; + last if $zone eq "" || $zone eq '.'; + }; + + return join(', ', @result); +}; sub usage { my $fd = shift; my $exit = shift; - print $fd "Usage: $PROGRAM_NAME overview|check-dlv|check-ds zone [zone...]\n"; - print $fd " $PROGRAM_NAME --dir overview|check-dlv|check-ds\n"; + print $fd "Usage: $PROGRAM_NAME [--dir ] overview|check-dlv|check-ds|check-header zone [zone...]\n"; + print $fd " $PROGRAM_NAME --dir overview|check-dlv|check-ds|check-header\n"; print $fd " $PROGRAM_NAME --help\n"; exit $exit; } -my $params; +sub what_to_check { + my $zone = shift; + my $indir = shift; + + my $do_dlv = 0; + my $do_ds = 0; + + open(F, "<", $indir."/".$zone) or die ("Cannot open zonefile for $zone: $!\n"); + while () { + if (/^;\s*dlv-submit\s*=\s*yes\s*$/) { $do_dlv = 1; } + if (/^;\s*ds-in-parent\s*=\s*yes\s*$/) { $do_ds = 1; } + } + close(F); + + my @keys = (); + push @keys, 'dlv' if $do_dlv; + push @keys, 'ds' if $do_ds; + return @keys; +} + Getopt::Long::config('bundling'); GetOptions ( '--help' => \$params->{'help'}, '--dir=s' => \$params->{'dir'}, '--dlv=s' => \$params->{'dlv'}, + '--verbose' => \$params->{'verbose'}, ) or usage(\*STDERR, 1); usage(\*STDOUT, 0) if ($params->{'help'}); my $mode = shift @ARGV; +usage(\*STDOUT, 0) unless (defined $mode && $mode =~ /^(overview|check-dlv|check-ds|check-header)$/); +die ("check-header needs --dir") if ($mode eq 'check-header' && !defined $params->{'dir'}); my @zones; if (scalar @ARGV) { - warn "--dir option ignored" if defined $params->{'dir'}; + if (defined $params->{'dir'} && $mode ne 'check-header') { + warn "--dir option ignored" + } @zones = @ARGV; } else { my $dir = $params->{'dir'}; @@ -109,44 +184,50 @@ if (scalar @ARGV) { closedir(DIR); }; -usage(\*STDOUT, 0) unless (defined $mode && $mode =~ /^(overview|check-dlv|check-ds)$/); $DLV = $params->{'dlv'} if $params->{'dlv'}; my %data; for my $zone (@zones) { $data{$zone} = { 'dnskey' => join(', ', get_dnskeytags($zone)), 'ds' => join(', ', get_dstags($zone)), - 'dlv' => join(', ', get_dlvtags($zone)) }; + 'dlv' => join(', ', get_dlvtags($zone)), + 'parent_dnssec' => get_parent_dnssec_status($zone) }; } if ($mode eq 'overview') { - my $format = "%30s %-16s %-16s %-16s\n"; - printf $format, "zone", "DNSKEY", "DS in parent", "DLV"; - printf $format, "-"x 30, "-"x 16, "-"x 16, "-"x 16; + my $format = "%60s %-10s %-10s %-10s %-10s\n"; + printf $format, "zone", "DNSKEY", "DS\@parent", "DLV", "dnssec\@parent"; + printf $format, "-"x 60, "-"x 10, "-"x 10, "-"x 10, "-"x 10; for my $zone (sort {$a cmp $b} keys %data) { printf $format, $zone, $data{$zone}->{'dnskey'}, $data{$zone}->{'ds'}, - $data{$zone}->{'dlv'}; + $data{$zone}->{'dlv'}, + $data{$zone}->{'parent_dnssec'}; } exit(0); -} elsif ($mode eq 'check-dlv' || $mode eq 'check-ds') { +} elsif ($mode eq 'check-dlv' || $mode eq 'check-ds' || $mode eq 'check-header') { my $key; $key = 'dlv' if $mode eq 'check-dlv'; $key = 'ds' if $mode eq 'check-ds'; + $key = 'per-zone' if $mode eq 'check-header'; die ("key undefined") unless $key; my @warn; my @ok; for my $zone (sort {$a cmp $b} keys %data) { - my $dnskey = $data{$zone}->{'dnskey'} || '-'; - my $target = $data{$zone}->{$key} || '-'; - - if ($dnskey ne $target) { - push @warn, "$zone ($dnskey != $target)"; - } else { - push @ok, "$zone ($dnskey)"; - }; + my @thiskeys = $key eq 'per-zone' ? what_to_check($zone, $params->{'dir'}) : ($key); + + for my $thiskey (@thiskeys) { + my $dnskey = $data{$zone}->{'dnskey'} || '-'; + my $target = $data{$zone}->{$thiskey} || '-'; + + if ($dnskey ne $target) { + push @warn, "$zone ($dnskey != $target)"; + } else { + push @ok, "$zone ($dnskey)"; + }; + } } print "WARNING: ", join(", ", @warn), "\n" if (scalar @warn); print "OK: ", join(", ", @ok), "\n" if (scalar @ok);