#! /usr/local/bin/perl
#
#  grc - reverse mapping checker
#
#  invoke as:
#       rmc [-l msglevel]
#
#  Copyright (C) 1992, 1993 PUUG - Grupo Portugues de Utilizadores do
#				   Sistema UNIX
#                1992, 1993 FCCN - Fundacao para o Desenvolvimento dos Meios 
#                            	   Nacionais de Calculo Cientifico 
#
#  Authors: Jorge Frazao de Oliveira <frazao@puug.pt>
#           Artur Romao <artur@dns.pt>
#
#  This file is part of the DDT package, Version 2.0.
#
#  Permission to use, copy, modify, and distribute this software and its 
#  documentation for any purpose and without any fee is hereby granted, 
#  provided that the above copyright notice appear in all copies.  Neither 
#  PUUG nor FCCN make any representations about the suitability of this
#  software for any purpose.  It is provided "as is" without express or 
#  implied warranty.


# =()<push(@INC, "@<LIBDIR>@");>()=
push(@INC, "/usr/local/lib/ddt/cmd");

require "ddt.pl";


# scan the standard input
while (<STDIN>) {
	next if /^;/;			# ignore commented lines

	chop;				# strip record separator	
	@Field = split(/\s+/, $_);	# break the input line

	if (/^\$ORIGIN/) {
		$Origin = $Field[2];	# set to a different origin
	
		next;
    	}

	if (/^[*\.\-0-9A-Za-z]+/) { 
		$Name = &make_name($Field[1], $Origin);
	}

	if (/\tIN\tSOA\t/) {
		$Zone         = $Name;
		$Zones{$Zone} = 1;

		<STDIN> if /\(\s*$/;	# skip the line defining the timers
	}
	elsif (/\tIN\tA/) {
		&A_RR($Zone, $Name, $Field[$#Field]);
	}
	elsif (/\tIN\tPTR/) {
		&PTR_RR($Zone, $Name, $Field[$#Field]);
	}
}

foreach $Zone (keys %Zones) {
        &show_zone($Zone);
}

exit 0;


sub perror_rev_mapping {
    	local($host, $address) = @_;

	if (!$Printed{$host, $address}) {
		if ($Level >= 3) {
			$Printed{$host, $address} = 1;		
	
			$address = join(".", reverse(split(/\./, $address)));

			print "$Lpad[3]No $address.in-addr.arpa PTR RR found for $host";
		}
	}
}


sub perror_mapping {
	local($host, $address) = @_;

        if (!$Printed{$host, $address}) {
                if ($Level >= 3) {
                        $Printed{$host, $address} = 1;

			print "$Lpad[3]No $host A RR found with", 
			      &arpa2ip($address);
		}
	}
}


#
# converts an in-addr.arpa name to an IP address
#
sub arpa2ip {
	local($revaddress) = @_;
	local($first, $second, $third, $fourth);

	($first, $second, $third, $fourth) = split(/\./, $revaddress);

	return join(".", $fourth, $third, $second, $first);
}


#
# add $address to the list of addresses for $host in $zone
#
sub A_RR {
    	local($zone, $host, $address) = @_;

	$host = &tolower($host);

	$Azone{$zone} = &add_list($Azone{$zone}, 
				      join($ELEMsep1, $host, $address));

	$Addresses{$host} = &add_list($Addresses{$host}, $address);
}


#
# add $host to the list of hosts addressed $address in $zone
#
sub PTR_RR {
    	local($zone, $address, $host) = @_;

	$host = &tolower($host);

    	$address = join(".", split(/\./, $address));

	$PTRzone{$zone} = &add_list($PTRzone{$zone},
				     join($ELEMsep1, $host, $address));

    	$Hosts{&arpa2ip($address)} = &add_list($Hosts{$address}, $host);
}


#
# if $address "has" $host
#
sub rev_mapped {
    	local($host, $address) = @_;

	return &in($host, $Hosts{$address}, $LISTsep);
}


#
# if $host has $address
#
sub mapped {
    	local($host, $address) = @_;

	return &in(&arpa2ip($address), $Addresses{$host}, $LISTsep);
}


#
# for each A record check if there is the corresponding PTR
# and vice-versa for PTR RR's
#
sub check_mapping {
    	local($zone) = @_; 
	local(@HA, $ha);

	if (defined $Azone{$zone}) {
		@HA = split($LISTsep, $Azone{$zone});

		while ($ha = shift(@HA)) {
			($host, $address) = split($ELEMsep1, $ha);

			if (!&rev_mapped($host, $address)) {
				&perror_rev_mapping($host, $address);
			}
		}
	}

	if (defined $PTRzone{$zone}) {
		@HA = split($LISTsep, $PTRzone{$zone});

              	while ($ha = shift(@HA)) {
                  	($host, $address) = split($ELEMsep1, $ha);

                    	if (!&mapped($host, $address)) {
                              	&perror_mapping($host, $address);
                        }
                }
        }
}


sub show_zone {
	local($zone) = @_;

	print "\n ###", &toupper($zone), "###";

	&check_mapping($zone);
}
