--- a/plugins/check_dns-serial Tue Dec 30 23:27:37 2014 +0100
+++ b/plugins/check_dns-serial Tue Jan 06 13:35:59 2015 +0100
@@ -1,4 +1,5 @@
#! /usr/bin/perl
+# source: https://ssl.schlittermann.de/hg/ius/nagios/nagios-plugin-dns-serial
# © 2014 Heiko Schlittermann <hs@schlittermann.de>
=head1 NAME
@@ -47,6 +48,16 @@
use if $ENV{DEBUG} => 'Smart::Comments';
sub uniq { my %h; @h{@_} = (); return keys %h; }
+my @extns = qw(8.8.8.8 8.8.4.4);
+
+package Net::DNS::Resolver {
+ use Storable qw(freeze);
+ sub new {
+ my $class = shift;
+ state %cache;
+ return $cache{freeze \@_} //= $class->SUPER::new(@_);
+ }
+}
# return a list of the zones known to the local
# bind
@@ -97,15 +108,20 @@
sub ns {
my $domain = shift;
### assert: @_ % 2 == 0
- my %resflags = (nameservers => [qw/8.8.8.8/], @_);
+ my %resflags = (nameservers => \@extns, @_);
my $aa = delete $resflags{aa};
- my $nameservers = $resflags{nameservers};
+ my $nameservers = join ',' => @{$resflags{nameservers}};
my @ns;
my $r = Net::DNS::Resolver->new(%resflags);
- my $q = $r->query($domain, 'NS') or die $r->errorstring, "\@@$nameservers\n";
+ my $q;
- die "no aa @@$nameservers\n" if $aa and not $q->header->aa;
+ for (my $i = 3; $i; --$i) {
+ $q = $r->query($domain, 'NS') and last;
+ }
+ die $r->errorstring . "\@$nameservers\n" if not $q;
+
+ 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;
@@ -113,11 +129,17 @@
sub serial {
my $domain = shift;
- my %resflags = (nameservers => [qw/8.8.8.8/], @_);
- my $nameservers = $resflags{nameservers};
+ my %resflags = (nameservers => \@extns, @_);
+ my $nameservers = join ',' => @{$resflags{nameservers}};
my $r = Net::DNS::Resolver->new(%resflags);
- my $q = $r->query($domain, 'SOA') or die $r->errorstring, "\@@$nameservers\n";
+ my $q;
+
+ for (my $i = 3; $i; --$i) {
+ $q = $r->query($domain, 'SOA') and last;
+ }
+ die $r->errorstring, "\@$nameservers\n" if not $q;
+
return (map { $_->serial } grep { $_->type eq 'SOA' } $q->answer)[0];
}
@@ -139,16 +161,29 @@
my @their = eval { sort +ns($domain) };
push @errs, $@ if $@;
- if (!@errs) {
+ if (@errs) {
+ chomp @errs;
+ die join(', ' => @errs) . "\n";
+ }
+
+ if ("@our" ne "@their") {
local $" = ', ';
- if ("@our" eq "@their") {
- return 1;
- }
die "NS differ (our @our) vs (their @their)\n";
}
- chomp @errs;
- die join(', ', @errs) . "\n";
+
+ return uniq sort @our, @their;
+}
+sub serial_ok {
+ my ($domain, @ns) = @_;
+ my @serials = map { my $s = serial $domain, nameservers => [$_]; "$s\@$_" } @ns;
+
+ if (uniq(map { /(\d+)/ } @serials) != 1) {
+ die "serials do not match: @serials\n";
+ }
+
+ $serials[0] =~ /(\d+)/;
+ return $1;
}
sub main {
@@ -176,10 +211,24 @@
my (@OK, %CRITICAL);
foreach my $domain (@domains) {
print STDERR "$domain " if $opt_progress;
- eval { ns_ok($domain, $opt_reference) };
- if ($@) { $CRITICAL{$domain} = $@ }
- else { push @OK, $domain }
- say STDERR $@ ? 'not ok' : 'ok' if $opt_progress;
+
+ my @ns = eval { ns_ok($domain, $opt_reference) };
+ if ($@) {
+ $CRITICAL{$domain} = $@;
+ say STDERR 'ns not ok' if $opt_progress;
+ next;
+ }
+ print STDERR 'ok(ns) ';
+
+ my @serial = eval { serial_ok($domain, @ns) };
+ if ($@) {
+ $CRITICAL{$domain} = $@;
+ say STDERR 'serial not ok' if $opt_progress;
+ next;
+ }
+ say STDERR 'ok(serial)' if $opt_progress;
+ push @OK, $domain;
+
}
# use DDP;
@@ -216,3 +265,5 @@
=back
=cut
+
+# vim:sts=4 ts=8 sw=4 et: