plugins/check_dns-serial
changeset 5 2e27cfdf85ea
parent 4 ebada07bb701
child 6 eac6751d5bff
equal deleted inserted replaced
4:ebada07bb701 5:2e27cfdf85ea
    42 use strict;
    42 use strict;
    43 use warnings;
    43 use warnings;
    44 use Getopt::Long qw(GetOptionsFromArray);
    44 use Getopt::Long qw(GetOptionsFromArray);
    45 use Net::DNS;
    45 use Net::DNS;
    46 use Pod::Usage;
    46 use Pod::Usage;
    47 
    47 use Smart::Comments;
    48 my %resolver;
    48 
    49 sub uniq { my %h; @h{@_} = (); return keys %h; }
    49 sub uniq { my %h; @h{@_} = (); return keys %h; }
    50 
    50 
    51 # return a list of the zones known to the local
    51 # return a list of the zones known to the local
    52 # bind
    52 # bind
    53 sub get_local_zones {
    53 sub get_local_zones {
    92 
    92 
    93     return @domains;
    93     return @domains;
    94 }
    94 }
    95 
    95 
    96 # return a list of "official" nameservers
    96 # return a list of "official" nameservers
    97 sub get_ns {
    97 sub ns {
    98     my ($nameserver) = map { /^\@(.*)/ } $_[0] =~ /^\@/ ? shift : '@8.8.8.8';
    98     my $domain = shift;
    99     my ($domain) = @_;
    99     ### assert: @_ % 2 == 0
       
   100     my %resflags = (nameservers => [qw/8.8.8.8/], @_);
       
   101     my $aa = delete $resflags{aa};
       
   102     my $nameservers = $resflags{nameservers};
   100     my @ns;
   103     my @ns;
   101 
   104 
   102     my $r = $resolver{$nameserver} //=
   105     my $r = Net::DNS::Resolver->new(%resflags);
   103       Net::DNS::Resolver->new(nameservers => [$nameserver]);
   106     my $q = $r->query($domain, 'NS') or die $r->errorstring, "\@@$nameservers\n";
   104     my $q = $r->query($domain, 'NS') or die $r->errorstring, "\@$nameserver\n";
   107 
       
   108     die "no aa @@$nameservers\n" if $aa and not $q->header->aa;
   105     push @ns, map { $_->nsdname } grep { $_->type eq 'NS' } $q->answer;
   109     push @ns, map { $_->nsdname } grep { $_->type eq 'NS' } $q->answer;
   106 
   110 
   107     return sort @ns;
   111     return sort @ns;
   108 }
   112 }
   109 
   113 
   110 sub get_serial {
   114 sub serial {
   111     my ($nameserver) = map { /^\@(.*)/ } $_[0] =~ /^\@/ ? shift : '@8.8.8.8';
   115     my $domain = shift;
   112     my ($domain) = shift;
   116     my %resflags = (nameservers => [qw/8.8.8.8/], @_);
   113 
   117     my $nameservers = $resflags{nameservers};
   114     my $r = $resolver{$nameserver} //=
   118 
   115       Net::DNS::Resolver->new(nameservers => [$nameserver]);
   119     my $r = Net::DNS::Resolver->new(%resflags);
   116     my $q = $r->query($domain, 'SOA') or die $r->errorstring, "\@$nameserver\n";
   120     my $q = $r->query($domain, 'SOA') or die $r->errorstring, "\@@$nameservers\n";
   117     return (map { $_->serial } grep { $_->type eq 'SOA' } $q->answer)[0];
   121     return (map { $_->serial } grep { $_->type eq 'SOA' } $q->answer)[0];
   118 }
   122 }
   119 
   123 
   120 # - the nameservers known from the ns records
   124 # - the nameservers known from the ns records
   121 # - from the primary master if this is not one of the
   125 # - from the primary master if this is not one of the
   125 # OK - if the serial numbers are in sync
   129 # OK - if the serial numbers are in sync
   126 # WARNING - if there is some difference
   130 # WARNING - if there is some difference
   127 # CRITICAL - if the serial cannot be found at one of the sources
   131 # CRITICAL - if the serial cannot be found at one of the sources
   128 
   132 
   129 sub ns_ok {
   133 sub ns_ok {
   130     my ($reference, $domain) = @_;
   134     my ($domain, $reference) = @_;
   131 
   135 
   132     my @our = sort eval { get_ns($reference, $domain) };
   136     my @our = sort +ns($domain, nameservers => [$reference], aa => 1);
   133     my @their = sort +get_ns($domain);
   137     my @their = sort +ns($domain);
   134 
   138 
   135     {
   139     {
   136         local $" = "\0";
   140         local $" = "\0";
   137         return 1 if "@our" eq "@their";
   141         return 1 if "@our" eq "@their";
   138     }
   142     }
   146     my $opt_reference = '127.0.0.1';
   150     my $opt_reference = '127.0.0.1';
   147     my $opt_progress  = -t;
   151     my $opt_progress  = -t;
   148 
   152 
   149     GetOptionsFromArray(
   153     GetOptionsFromArray(
   150         \@argv,
   154         \@argv,
   151 ## Please see file perltidy.ERR
       
   152 ## Please see file perltidy.ERR
       
   153         'reference=s' => \$opt_reference,
   155         'reference=s' => \$opt_reference,
   154         'progress!'   => \$opt_progress,
   156         'progress!'   => \$opt_progress,
   155         'h|help'      => sub { pod2usage(-verbose => 1, -exit => 0) },
   157         'h|help'      => sub { pod2usage(-verbose => 1, -exit => 0) },
   156         'm|man'       => sub {
   158         'm|man'       => sub {
   157             pod2usage(
   159             pod2usage(
   166     my @domains = get_domains(@argv);
   168     my @domains = get_domains(@argv);
   167 
   169 
   168     my (@OK, %CRITICAL);
   170     my (@OK, %CRITICAL);
   169     foreach my $domain (@domains) {
   171     foreach my $domain (@domains) {
   170         print STDERR "$domain " if $opt_progress;
   172         print STDERR "$domain " if $opt_progress;
   171         eval { ns_ok('@212.80.235.130', $domain) };
   173         eval { ns_ok($domain, $opt_reference) };
   172         if ($@) { $CRITICAL{$domain} = $@ }
   174         if ($@) { $CRITICAL{$domain} = $@ }
   173         else    { push @OK, $domain }
   175         else    { push @OK, $domain }
   174         say STDERR $@ ? 'not ok' : 'ok' if $opt_progress;
   176         say STDERR $@ ? 'not ok' : 'ok' if $opt_progress;
   175     }
   177     }
   176 
   178