4.4BSD/usr/src/contrib/bind-4.9/contrib/misc/dnsrpt.shar

#Date: Mon, 26 Apr 1993 09:28:17 -0700
#From: Don Lewis <gdonl@ssi1.com>
#Message-Id: <199304261628.AA09295@sunrise.ssi1.com>
#To: vixie
#Subject: Re:  send me your tools

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  dnsrpt
#
sed 's/^X//' << 'SHAR_EOF' > dnsrpt &&
X#!/usr/local/bin/perl
X#
X# Copyright (c) 1993 by Silicon Systems Inc.
X# 
X# Permission to use, copy, modify, and distribute this software for any
X# purpose with or without fee is hereby granted, provided that this
X# copyright notice appear in all copies, and that the name of Silicon
X# Systems Inc. not be used in advertising or publicity pertaining to
X# distribution of the document or software without specific,
X# written prior permission.
X# 
X# THE SOFTWARE IS PROVIDED "AS IS" AND SILICON SYSTEMS INC. DISCLAIMS ALL
X# WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
X# OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL SILICON SYTEMS
X# INC. BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X# SOFTWARE.
X#
X# Author: Don Lewis <gdonl@ssi1.com>
X#
X# This perl script reads the /etc/named.boot file to find all the zone
X# files.  It reads the zone files and produces a report listing the
X# hosts sorted by both name and address in a format similar to that of
X# /etc/hosts (the difference being that this report contains multiple
X# address fields for multi-homed hosts).  This script checks that the
X# A RRs and PTR RRs match up, and also knows about CNAME RRs.
X#
X# This script is fairly dependent on having a complete set of the zone
X# files for a domain (both forward and reverse) accessable.
X#
X
Xsub getnonblank {
X	local ($line, $instring, $inparens, $saweof);
X	local ($handle) = @_;
X
X	$instring = 0;
X	$inparens = 0;
X	$saweof = 0;
X
X	do {
X		$line = '';
X		do {
X			$c = getc($handle);
X			if ($c eq ';') {
X				do {
X					$c = getc($handle);
X					if ($c eq '') {
X						last;
X					}
X				} while ($c ne "\n");
X			}
X			if ($c eq '') {
X				$saweof = 1;
X				last;
X			} elsif ($c eq ';') {
X				$line .= $c;
X			} else {
X				$line .= $c;
X			}
X			if ($instring) {
X				if ($c eq '"') {
X					$instring = 0;
X				}
X			} else {
X				if ($c eq '"') {
X					$instring = 1;
X				} elsif ($c eq '(') {
X					$inparens = 1;
X				} elsif ($c eq ')') {
X					$inparens = 0;
X				}
X			}
X		} while ( $inparens || $c ne "\n" );
X	} while ((! $saweof) && (split(/[ \t\n]/, $line) == 0));
X	return($line);
X}
X
Xsub parsezone {
X	local ($origin) = $_[0];
X	local ($zonefile) = $_[1];
X	local ($zonedata);
X	local ($owner);
X	
X	if ($origin ne '.') {
X		$origin .= '.';
X	}
X
X	if ($directory ne '') {
X		$zonefile = $directory . '/' . $zonefile;
X	}
X
X	if (! -f $zonefile) {
X		die "zone file '" . $zonefile . "' for zone '" . $origin . "' is not a file\n";
X	}
X	if (open(zone, $zonefile) != 1) {
X		die "can't open zone file '" . $zonefile . "' for zone '" . $origin . "'\n";
X	}
X
X	while ($zonedata = &getnonblank(zone)) {
X		split(/[ \t\n]+/, $zonedata);
X		if ($_[0] eq '$ORIGIN') {
X			$origin = $_[1];
X		} else {
X			if ($_[0] ne '') {
X				if ($_[0] eq '@') {
X					$owner = $origin;
X				} elsif ($_[0] =~ /.*\.$/) {
X					$owner = $_[0];
X				} elsif ($origin eq '.') {
X					$owner = $_[0] . '.';
X				} else {
X					$owner = $_[0] . '.' . $origin;
X				}
X			}
X			shift;		# skip owner
X			if ($_[0] =~ /^[0-9]+$/) {
X				shift;	# skip ttl
X			}
X			if ($_[0] ne 'IN') {
X				print "skipping non-IN class RR " . $zonedata;
X				next;
X			}
X			shift;		# skip class
X			if ($_[0] eq 'A') {
X				if ($addrtohost{$_[1]}) {
X					local (@tmpvar);
X					foreach $var (split(/ /, $addrtohost{$_[1]})) {
X						$tmpvar{$var} = 'junk';
X					}
X					if (! $tmpvar{$owner} ) {
X						$addrtohost{$_[1]} .= " " . $owner;
X					}
X				} else {
X					$addrtohost{$_[1]} = $owner;
X				}
X				if ($hosttoaddr{$owner}) {
X					local (@tmpvar);
X					foreach $var (split(/ /, $hosttoaddr{$owner})) {
X						$tmpvar{$var} = 'junk';
X					}
X					if (! $tmpvar{$_[1]} ) {
X						$hosttoaddr{$owner} .= " " . $_[1];
X					}
X				} else {
X					$hosttoaddr{$owner} = $_[1];
X				}
X			} elsif ($_[0] eq 'CNAME') {
X				local ($hostname);
X	
X				if ($_[1] =~ /.*\.$/) {
X					$hostname = $_[1];
X				} elsif ($origin eq '.') {
X					$hostname = $_[1] . '.';
X				} else {
X					$hostname = $_[1] . '.' . $origin;
X				}
X	
X				if ($hosttocname{$hostname}) {
X					$hosttocname{$hostname} .= " " . $owner;
X				} else {
X					$hosttocname{$hostname} = $owner;
X				}
X			} elsif ($_[0] eq 'PTR') {
X				if ($ptrtohost{$owner}) {
X					$ptrtohost{$owner} .= " " . $_[1];
X				} else {
X					$ptrtohost{$owner} = $_[1];
X				}
X			}
X		}
X	}
X
X	close(zone);
X}
X
Xsub cmpaddr {
X	local (@addr1) = split(/\./, $a);
X	local (@addr2) = split(/\./, $b);
X
X	for ($i = 0; $i < 4; $i++) {
X		if ($addr1[$i] != $addr2[$i]) {
X			return($addr1[$i] - $addr2[$i]);
X		}
X	}
X	return(0);
X}
X
Xif (open(bootfile, "</etc/named.boot") != 1) {
X	die "can't open /etc/named.boot\n";
X}
X
Xwhile ($cmd = &getnonblank(bootfile)) {
X	split(/[ \t\n]+/, $cmd);
X	if ($_[0] eq 'directory') {
X		$directory = $_[1];
X	} elsif ($_[0] eq 'primary') {
X		&parsezone( $_[1], $_[2]);
X	} elsif ($_[0] eq 'secondary') {
X		&parsezone( $_[1], $_[$#_]);
X	}
X}
X
Xforeach $addr (keys(%addrtohost)) {
X	local ($revaddr) = join('.', reverse(split(/\./, $addr)));
X	local ($ptr) = $ptrtohost{$revaddr . '.in-addr.arpa.'};
X	local ($hostname) = $addrtohost{$addr};
X	
X	if (! $ptr ) {
X		print "address " . $addr . " (" . $hostname . ") has no matching PTR record\n";
X	} elsif ( $ptr ne $hostname ) {
X		print "address " . $addr . " has name " . $hostname . " and PTR " . $ptr . "\n";
X	}
X}
X
Xforeach $ptr (keys(%ptrtohost)) {
X	local ($hostname) = $ptrtohost{$ptr};
X	local (@parts) = split(/\./, $ptr);
X
X	if ($parts[$#parts] eq 'arpa' && $parts[$#parts - 1] eq 'in-addr') {
X
X		if ( ! $hosttoaddr{$hostname} ) {
X			if ( $ptrtohost{$hostname} ) {
X				if ( $ptrtohost{$hostname} ne $ptr ) {
X					print "mismatched PTRs for " . $ptr . " and " . $hostname . "\n";
X				}
X			} else {
X				print "PTR " . $ptr . " to " . $hostname . " is dangling\n";
X			}
X		} else {
X			local ($addr) = $parts[3] . '.' . $parts[2] . '.' . $parts[1] . '.' . $parts[0];
X
X			if ( ! $addrtohost{$addr} ) {
X				print "PTR " . $ptr . " to " . $hostname . " refers to an invalid address\n";
X			} elsif ( $hostname ne $addrtohost{$addr} ) {
X				print "PTR " . $ptr . " to " . $hostname . " has address of host " . $addrtohost{$addr} . "\n";
X			}
X		}
X	} elsif ( ! $ptrtohost{$hostname} ) {
X		print "network PTR " . $ptr . " to " . $hostname . " is dangling\n";
X	}
X}
X
Xprint "                        Hosts Sorted by Name\n\n\n";
X
Xforeach $host (sort(keys(%hosttoaddr))) {
X	local ($count) = 0;
X	foreach $addr (split(/ /, $hosttoaddr{$host})) {
X		$count++;
X		printf("%-16s", $addr);
X	}
X	for (; $count < 2; $count++) {
X		printf("%-16s", "");
X	}
X	printf "  %s", $host;
X	if ($hosttocname{$host}) {
X		print ' ' . $hosttocname{$host};
X	}
X	print "\n";
X}
X
Xprint "\f                        Hosts Sorted by Address\n\n\n";
X
Xforeach $addr (sort(cmpaddr keys(%addrtohost))) {
X	printf "%-32s  %s\n", $addr, $addrtohost{$addr};
X}
SHAR_EOF
chmod 0755 dnsrpt || echo "restore of dnsrpt fails"
exit 0



Don "Truck" Lewis              Phone: +1 916 478-8284   Silicon Systems
Internet: gdonl@ssi1.com       FAX:   +1 916 478-8251   138 New Mohawk Road
UUCP: {uunet,tektronix!gvgpsa.gvg.tek.com}!ssigv!gdonl  Nevada City, CA  95959