home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / comp / protocol / tcpip / domains / 910 < prev    next >
Encoding:
Internet Message Format  |  1993-01-28  |  8.1 KB

  1. Path: sparky!uunet!tcsi.com!iat.holonet.net!news.cerf.net!usc!zaphod.mps.ohio-state.edu!saimiri.primate.wisc.edu!usenet.coe.montana.edu!news.u.washington.edu!news.uoregon.edu!pith.uoregon.edu!meyer
  2. From: meyer@darkwing.uoregon.edu (David M. Meyer 503/346-1747)
  3. Newsgroups: comp.protocols.tcp-ip.domains
  4. Subject: how to you do consistency checking?
  5. Date: 26 Jan 93 16:47:57
  6. Organization: University Network Services, University of Oregon, Eugene, OR
  7.     97403
  8. Lines: 364
  9. Distribution: world
  10. Message-ID: <MEYER.93Jan26164757@darkwing.uoregon.edu>
  11. NNTP-Posting-Host: darkwing.uoregon.edu
  12.  
  13.  
  14.  
  15.     I have the need to check consistency checking between my
  16.     zone and reverse zone files. I wrote the following perl
  17.     code, but I'm not too happy with it. Anyone have anything
  18.     better, or suggestions on how to make this better?
  19.  
  20.     Thanks,
  21.  
  22.  
  23.     Dave
  24.  
  25.     David M. Meyer            Voice:     503/346-1747
  26.     Senior Network Engineer        Pager:       503/342-9458
  27.     Office of University Computing    FAX:       503/346-4397
  28.     Computing Center        Internet:  meyer@ns.uoregon.edu
  29.     University of Oregon
  30.     1225 Kincaid
  31.     Eugene, OR 97403    
  32.  
  33.  
  34.  
  35. -------
  36.  
  37.  
  38. #!/usr/local/bin/perl -- # -*- perl -*-
  39.  
  40. #
  41. #    checkdns --
  42. #
  43. #    Be mindful of the multitiude of errors I make here...
  44. #
  45. #    David M. Meyer
  46. #    meyer@phloem.uoregon.edu
  47. #    15-Jan-93
  48. #
  49. #    $Header: /usr/local/etc/named/RCS/checkdns,v 1.0 1993/01/27 00:36:55 meyer Exp $
  50. #
  51. #
  52. require('getopts.pl');
  53.  
  54. ($program = $0) =~ s%.*/%%;
  55. $Usage = " [args]                \
  56.     -d for debugging            \
  57.     -i <initial domain name>        \
  58.     -n <network number>            \
  59.     -r <path to reverse zone file>        \
  60.     -s <subnet mask> (subnet octet only)    \
  61.     -u for this message            \ 
  62.     -z <path to zone file>            \
  63. ";
  64.  
  65. do Getopts("di:n:r:s:uz:");
  66.  
  67. if ($opt_d eq "") {
  68.     $DEBUG = 0;
  69. } else {
  70.    $DEBUG = 1;
  71. }
  72.  
  73. if ($opt_i eq "") {
  74.     $domain = "uoregon.edu";
  75. } else {
  76.    $domain = $opt_i;
  77. }
  78.  
  79. if ($opt_n eq "") {
  80.     $network = "128.223";
  81. } else {
  82.    $network = $opt_n;
  83. }
  84.  
  85. if ($opt_r eq "") {
  86.     $revzonefile = "/usr/local/etc/named/uoregon.rev";
  87. } else {
  88.    $revzonefile = $opt_r;
  89. }
  90.  
  91. if ($opt_s eq "") {
  92.     $subnetmask = 0xfe;            # subnet only
  93. } else {
  94.    $subnetmask = $opt_s;
  95. }
  96. if ($opt_u ne "") {
  97.     printf("Usage: $program $Usage");
  98.     exit 1;
  99. }
  100.  
  101. if ($opt_z eq "") {
  102.     $zonefile = "/usr/local/etc/named/uoregon.zone";
  103. } else {
  104.    $zonefile = $opt_z;
  105. }
  106.  
  107.  
  108. #
  109. #    Do some inititalizing...
  110. #
  111.  
  112. $GOOD            = 0;
  113. $BAD            = 1;
  114. $exitval        = $GOOD;
  115. $HaveRevNotZone        = 0;
  116. $HaveInconsistent    = 0;
  117. $HaveBadIP        = 0;
  118. $NoNameServer        = 0;
  119.  
  120.  
  121. select(STDERR); $| = 1;
  122. &CheckZone($zonefile);
  123. &CheckRevZone($revzonefile);
  124. printf("\nAnalyzing...\n");
  125.  
  126.  
  127. #
  128. #    First, check for inconsistency
  129. #
  130.  
  131. if ($HaveInconsistent) {
  132.     foreach $ipaddr (sort keys(%Inconsistent)) {
  133.     printf(STDERR "%s inconsistent\n", $ipaddr);
  134.     }
  135.     $exitval = $BAD;
  136. }
  137.  
  138. #
  139. #    Now, just see if every address in the zone file is 
  140. #    actually in the reverse zone file. If not, check that the
  141. #    file actually had a good IP address (not a typo -> inconsistent).
  142. #
  143.  
  144. foreach $ipaddr (sort keys(%ZoneHaveSeen)) {
  145.     next if &NotOurSubnet($ipaddr);
  146.     if ($RevHaveSeen{$ipaddr} ne $ipaddr) {
  147.     if (!&CouldBeIPAddr($ipaddr)) {
  148.         printf(STDERR "Bad IP address for %s (%s) in %s\n", 
  149.            $IPAddrs{$ipaddr}, $ipaddr, $zonefile);
  150.     }
  151.     printf(STDERR "Missing %s (%s) from %s\n",
  152.            $IPAddrs{$ipaddr}, $ipaddr, $revzonefile);
  153.     $exitval = $BAD;
  154.     }
  155. }
  156.  
  157. #
  158. #    Check for addresses in the reverse zone file which are not 
  159. #    in the zone file
  160. #
  161.  
  162. if ($HaveRevNotZone) {
  163.     foreach $ipaddr (sort keys(%RevNotZone)) {
  164.     $fqdn = $RevNotZone{$ipaddr};
  165.     printf(STDERR "Missing %s (%s) from %s\n",
  166.            $fqdn, $ipaddr, $zonefile);
  167.     if (!&CouldBeIPAddr($ipaddr)) {
  168.         printf(STDERR "Bad IP address for %s (%s) in %s\n", 
  169.            $fqdn,$ipaddr, $revzonefile);
  170.     }
  171.     }
  172.     $exitval = $BAD;
  173. }
  174.  
  175. if ($HaveBadIP) {
  176.     foreach $ipaddr (sort keys(%BadIP)) {
  177.     $fqdn = $BadIP{$ipaddr};
  178.     printf(STDERR "%s (%s) bad IP address\n", $fqdn, $ipaddr);
  179.     }
  180.     $exitval = $BAD;
  181. }
  182.     
  183. if ($NoNameServer) {
  184.     foreach $ns (sort keys(%NoNameServer)) {
  185.     printf(STDERR "Inconsistent NS records for %s\n", $ns);
  186.     }
  187.     $exitval = $BAD;
  188. }
  189.     
  190. exit $exitval;
  191.     
  192. #
  193. #    Just check A records in a zone file. "Try" to handle include
  194. #    files...
  195. #
  196.  
  197. sub CheckZone {
  198.     local($zonefile) = @_;
  199.     open(ZONE, $zonefile) || die "Can't open ZONE FILE: $!\n";
  200.     printf("Reading zone file (%s)\n", $zonefile);
  201.     while (<ZONE>) {
  202.     next if /^$/;                    # throw blank lines
  203.     next if /^[\s]*;/;                # throw comments
  204.     if (/[^\s]*\$[include|INCLUDE]/) {
  205.         ($include_file) = /[include|INCLUDE]\W+([^'"\s]+)/;
  206.         &CheckZone($include_file);
  207.     }
  208.     chop;                        # and \n on last field
  209.     @tmp = split;                    # now get fields
  210.     
  211.     if ($tmp[0] eq '$origin') {
  212.         chop($tmp[1]);                # remove trailing .
  213.         $domain = $tmp[1];
  214.     } elsif ($tmp[2] eq 'NS') {             # $tmp[0] = domain
  215.         $NameServer{$tmp[3]} = $tmp[0];         # $tmp[3] = NS
  216.     } elsif ($tmp[3] eq 'NS') {             # ttl
  217.         $NameServer{$tmp[4]} = $tmp[0];
  218.     } elsif ($tmp[2] eq 'A') {             # no ttl
  219.         if (!&SpecialCase($tmp[0])) {        # $tmp[0] = name
  220.         &HandleARecord($tmp[0],$domain,$tmp[3]);# $tmp[3] = IP addr
  221.         }
  222.     } elsif ($tmp[3] eq 'A') {            # have ttl
  223.         if (!&SpecialCase($tmp[0])) {         # $tmp[0] = name
  224.         &HandleARecord($tmp[0],$domain,$tmp[4]);# $tmp[4 = IP addr
  225.         }
  226.     }
  227.     
  228.     }
  229.     close(ZONE);    
  230.     printf("Done with $zonefile\n");
  231. }    
  232.  
  233. #
  234. #    Just check PTR records in a reverse zone file. "Try" to handle 
  235. #    include files...
  236. #
  237.  
  238. sub CheckRevZone {
  239.     local($revzonefile) = @_;
  240.     
  241.     open(REVZONE, $revzonefile) || die "Can't open REVERSE ZONE FILE: $!\n";
  242.     printf("Reading reverse zone file (%s)\n", $revzonefile);
  243.     
  244.     while (<REVZONE>) {
  245.     next if /^$/;                    # throw blank lines
  246.     next if /^[\s]*[;@]/;                # throw comments
  247.     if (/[^\s]*\$[include|INCLUDE]/) {
  248.         ($include_file) = /[include|INCLUDE]\W+([^'"\s]+)/;
  249.         &CheckRevZone($include_file);
  250.     }
  251.     chop;                        # and \n on last field
  252.     @tmp = split;                    # get fields
  253.     
  254.     @addr = split(/[. ]/,$tmp[0]);             # get addr octets
  255.     
  256.     if (($tmp[2] eq 'A') || ($tmp[3] eq 'A')) {     # Ignore NSs
  257.         next if ($NameServer{$tmp[0]} ne "");
  258.         $NoNameServer{$tmp[0]} = $tmp[0];
  259.         $NoNameServer = 1;
  260.         next;
  261.     }
  262. #
  263. #    Ignore inverse address 0.0 and and NS glue records
  264. #
  265.     next if (($addr[0] eq "")    ||            
  266.          ($addr[1] eq "")    ||
  267.          ($addr[0] eq "0")   ||
  268.          ($addr[1] eq "0"));             # Ignore this
  269.     
  270.     $fqdn = $tmp[$#tmp];                # last in rev file
  271.     chop($fqdn);                    # trailing .
  272.     $ipaddr = sprintf("%s.%s.%s", $network,$addr[1],$addr[0]);
  273.     $RevHaveSeen{$ipaddr} = $ipaddr;
  274.     
  275.     if ($DEBUG) {
  276.         printf("revzone:\t$fqdn,$ipaddr\n");
  277.     }
  278.     
  279.     if ($IPAddrs{$ipaddr} eq "") {
  280.         $HaveRevNotZone = 1;
  281.         $RevNotZone{$ipaddr} = $fqdn;
  282.     }
  283.     if ($IPAddrs{$ipaddr} ne $fqdn) {
  284.         $HaveInconsistent = 1;
  285.         $Inconsistent{$ipaddr} = $fqdn;
  286.     }
  287.     if (!&CouldBeIPAddr($ipaddr)) {
  288.         $HaveBadIP = 1;
  289.         $BadIP{$ipaddr} = $fqdn;
  290.     }
  291.     }
  292.     close(REVZONE);
  293.     printf("Done with $revzonefile\n");
  294. }
  295.  
  296.  
  297. #
  298. #    Find out if it could be an IP address...
  299. #
  300. #    NB.    Doesn't catch problems trailing digits on the 
  301. #        last octet, e.g., 128.223.32.115e won't be 
  302. #        detected.
  303. #    
  304. #
  305. #
  306.  
  307. sub CouldBeIPAddr {
  308.     local($ipaddr) = @_;
  309.     @octets = split(/[. ]/,$ipaddr);
  310.     if ($#octets != 3) {            # count from 0
  311.     return(0);
  312.     } 
  313.     if ($ipaddr =~ /(\d+\.\d+\.\d+\.\d+)/) {
  314.     return(1);
  315.     } else {
  316.     return(0);
  317.     }
  318. }
  319.  
  320. #
  321. #    Handle Glue and other A records for which we don't have 
  322. #    in-addr.arpa authority.
  323. #
  324.                          
  325. sub NotOurSubnet {
  326.     local($ipaddr) = @_;
  327.     @addr = split(/[. ]/,$ipaddr);
  328.     $subnet = $subnetmask & $addr[2];
  329.     if (($addr[0] == 128) &&
  330.     ($addr[1] == 223) && 
  331.     ($subnet != 4)    &&
  332.     ($subnet != 6)    &&
  333.     ($subnet != 8)    &&
  334.     ($subnet != 90)) {
  335.     return(0);
  336.     } else {
  337.     return(1);
  338.     }
  339. }
  340.                          
  341.                          
  342. #
  343. #    These names are special cases...
  344. #
  345.                          
  346. sub SpecialCase {
  347.     local($name) = @_;
  348.     $name =~ y/A-Z/a-z/;            # canonicalize to lower...
  349.     if ($name eq "localhost") {
  350.     return(1);
  351.     } else {
  352.     return(0);
  353.     }
  354. }
  355.                          
  356. #
  357. #    Do this if A Record
  358. #
  359. #
  360.                          
  361. sub HandleARecord {
  362.     local($name,$domain,$ipaddr) = @_;
  363.     if ($name eq "") {
  364.     $name = $lastname;
  365.     } else {
  366.     $lastname = $name;
  367.     }
  368.     $fqdn = sprintf("%s.%s.",$name,$domain);
  369.     chop($fqdn);
  370.     $IPAddrs{$ipaddr} = $fqdn;
  371.     $ZoneHaveSeen{$ipaddr} = $ipaddr;
  372.     if ($DEBUG) {
  373.     printf("zone:\t%s,%s\n",$fqdn,$ipaddr);
  374.     }
  375. }
  376.                          
  377.