#!/usr/local/bin/perl
# -*- perl -*-

# Copyright (c) 2000 by Jeff Weisberg
# Author: Jeff Weisberg <jaw @ tcp4me.com>
# Function: dig around for DNS problems

use Getopt::Std;
getopts("hvV");

if( $opt_h ){
    print <<XXX;
usage:
    digdeep [-vVh] zone
	-h	does not display this message
	-v	be verbose
	-V	be more verbose
XXX
    ;
    exit;
}

$q = $ARGV[0];
$opt_v = 1 if $opt_V;


# break domain into labels
@a = ('', reverse split /\./, $q );

foreach $a (@a){
    $zone  = $a . ($zone ? "." : "") . $zone;
    $zonen = $zone ? $zone : "<root>";
    
    # first get nameservers from previous nameservers (or default)
    if( keys %nns ){
	@ns = keys %nns;
	# otherwise there was no delegation on this dot,
	# reuse the same nameservers, and try again
    }
    %nns = ();
    print "zone $zonen\n";

    # get nameservers for zone from parent
    @ns = ('') unless @ns;
    foreach $ns (@ns){
	
	if( $ns && $deadns{lc($ns)} ){
	    print STDERR "\tskipping dead server: $ns\n";
	    next;
	}
	if( $ns ){
	    print STDERR "\tchecking $ns\n" if $opt_v;
	    $n = "\@$ns";
	}else{
	    print STDERR "\tchecking <default>\n" if $opt_v;
	    $n = '';
	}

	print STDERR "\tdig $n $zone ns\n" if $opt_v;
	open( DIG, "dig $n $zone ns 2>&1 |" );
	while( <DIG> ){
	    chop;
	    print STDERR ">>$_\n" if $opt_V;
	    if( /\sNS\s/ ){
		s/.*\sNS\s+//;
		chop;
		$nns{uc($_)} ++;
	    }
	    if( $ns && /Connection timed out/ ){
		print STDERR "\tERR: $ns is not responding\n";
		$deadns{lc($ns)} = 1;
	    }
	}
    }

    # get soa data from the nameservers we just found
    @ns = keys %nns;
    $errs = 0;
    print "\tfound ", scalar(@ns), " nameservers\n";
    foreach $ns (@ns){
	if( $ns && $deadns{lc($ns)} ){
	    print STDERR "\tskipping dead server: $ns\n";
	    $errs ++;
	    next;
	}
	
	print STDERR "\tdig \@$ns $zone soa\n" if $opt_v;
	open( DIG, "dig \@$ns $zone soa 2>&1 |" );
	$serial = '';
	while( <DIG> ){
	    chop;
	    print STDERR ">>$_\n" if $opt_V;
	    if( /; serial/ ){
		s/^\s*//;
		s/\s*;.*$//;
		if( $serial && $serial ne $_ ){
		    print STDERR "\tERR: $ns serial number mismatch $serial != $_\n";
		    $errs ++;
		}
		$serial = $_;
	    }
	    if( /;; flags/ && !/\baa\b/ ){
		print STDERR "\tERR: $ns non-authoritative answer\n";
		$errs ++;
	    }
	    if( $ns && /Connection timed out/ ){
		print STDERR "\tERR: $ns is not responding\n";
		$errs ++;
		$deadns{lc($ns)} = 1;
	    }
	}
    }
    if( $errs ){
	print "\terrors found for $zonen ($errs)\n";
    }else{
	print "\tno errors detected for $zonen\n";
    }
}

