#!/usr/bin/perl -s
# $Id: chkdns.rel 17563 2015-01-08 07:03:52Z rmoffitt $

# chkdns 2.1: Checks a list of A/CNAME records using one or more lists
#     of DNS servers, reporting number of successful and failed lookups.
#     Verbose mode (-v) will show result of each lookup while debug mode
#     (-d) will show the actual record retrieved from each lookup.
#     Default mode will just show total number of failures.
#
# Copyright (C) 2001-2002 Rod Moffitt rod@moffitt.info http://rod.moffitt.info
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

require 5.6.0;

use Net::DNS::Resolver;
use Net::DNS::Packet;
use Net::DNS::RR;

# chkdns
#
# history:
#
# 1.0 08/12/1999   Rod Moffitt       Creation
# 1.1 05/26/2001   Rod Moffitt       multiple DNS database support with individual
#                                    IP addresses
# 1.2 10/30/2001   Rod Moffitt       only displays failures if '-v' is not specified
# 2.0 05/22/2002   Rod Moffitt       uses new Net::DNS objects instead of 'host'
#                                    resulting in much quicker lookups, as a result
#                                    requires Perl 5.6.0+ and Net::DNS
# 2.1 09/24/2007   Rod Moffitt       added support for MX records

# DNS server database: for a DNS database 'NAME' @NAMEDNSserv is an array of comma
# seperated DNS servers in the database and $NAMEDNSname is the string name for
# the database
@alistDNSserv = ('1.2.3.4', '1.2.3.5', '1.2.3.6');
$alistDNSname = "DNS server list A";

@blistDNSserv = ('2.2.3.4', '2.2.3.5', '2.2.3.6');
$blistDNSname = "DNS server list B";

# host database
#
# A records are specified by an IP address, CNAME records are specified by
# a string host name with a trailing dot and MX records are specified by a
# string starting with the numeric priority followed by a '^' then the
# hostname of the mail exchanger for the given priority
#
@hosts = 
(
   # host name/IP             rec type expected value          list of DNS DB's to query
   "domain.com                A        1.2.3.4                 alist",
   "domain.com                MX       10^mail.domain.com.     blist",    
   "1.2.3.4                   PTR      domain.com.             alist blist"
);

$res = Net::DNS::Resolver->new;

if ($res != undef)
{
   $numTests = 0;
   $numFailures = 0;
   @failureArray = '';

   foreach $entry ( @hosts )
   {
      @aEntry = split(' ', $entry);

      $hostIP = shift(@aEntry);
      $type = shift(@aEntry);
      $val = shift(@aEntry); # default of 'CNAME'
      # we use '^' to indicate spaces
      $val =~ s/\^/ /g;

      if ($v)
      { print "checking '$type $hostIP = $val'\n"; }

      foreach $db ( @aEntry )
      {
         $dbName = "$db" . "DNSserv";
         $dbIDStr = "$db" . "DNSname";

         foreach $server ( @$dbName )
         {
            $res->nameservers($server);

            if ($d)
            { print "checking $type record for $hostIP at $server\n"; }

            $packet = $res->send($hostIP, $type);

            if (($packet != undef))
            {
               $ansIndex = 0;

               if ($type =~ /PTR/)
               { $ansIndex = $#answers; }

               @answers = $packet->answer;
               $answer = $answers[ $ansIndex ];
               $ansStr = "";

               # default of failure & CNAME lookup
               $statStr = '** FAIL **';

               if ($answer != undef)
               { $ansStr = $answer->string; }

               $ansStr =~ s/\s/ /g;

               if ($d)
               { print "  answer from $server for $hostIP:\n    $ansStr\n"; }

               if ($ansStr =~ /IN\s*$type\s*$val/si)
               { $statStr = '   PASS   '; }
               else
               {
                  $numFailures++;
                  push(@failureArray, 
                     "\n  no $type record for $hostIP matching $val at $server ($$dbIDStr)");
               }

               if ($v)
               { print "  $statStr for $server ($$dbIDStr)\n"; }

               $numTests++;
            }
         }
      }
   }

   print "\n$numTests tests executed with $numFailures failures";

   if ($numFailures)
   { print @failureArray; }

   print "\n";
}
else
{ print "error initializing resolver!\n"; }

