Blame demo/check_zone

Packit Service ab31fe
#!/usr/bin/perl -w
Packit Service f6e53a
# $Id: check_zone 264 2005-04-06 09:16:15Z olaf $
Packit Service f6e53a
Packit Service f6e53a
=head1 NAME
Packit Service f6e53a
Packit Service f6e53a
check_zone - Check a DNS zone for errors
Packit Service f6e53a
Packit Service f6e53a
=head1 SYNOPSIS
Packit Service f6e53a
Packit Service f6e53a
C<check_zone> [ C<-r> ] I<domain> [ I<class> ]
Packit Service f6e53a
Packit Service f6e53a
=head1 DESCRIPTION
Packit Service f6e53a
Packit Service f6e53a
Checks a DNS zone for errors.  Current checks are:
Packit Service f6e53a
Packit Service f6e53a
=over 4
Packit Service f6e53a
Packit Service f6e53a
=item *
Packit Service f6e53a
Packit Service f6e53a
Checks that all A records have corresponding PTR records.
Packit Service f6e53a
Packit Service f6e53a
=item *
Packit Service f6e53a
Packit Service f6e53a
Checks that hosts listed in NS, MX, and CNAME records have
Packit Service f6e53a
A records.
Packit Service f6e53a
Packit Service f6e53a
=back
Packit Service f6e53a
Packit Service f6e53a
=head1 OPTIONS
Packit Service f6e53a
Packit Service f6e53a
=over 4
Packit Service f6e53a
Packit Service f6e53a
=item C<-r>
Packit Service f6e53a
Packit Service f6e53a
Perform a recursive check on subdomains.
Packit Service f6e53a
Packit Service f6e53a
=back
Packit Service f6e53a
Packit Service f6e53a
=head1 AUTHOR
Packit Service f6e53a
Packit Service f6e53a
Michael Fuhr <mike@fuhr.org>
Packit Service f6e53a
Packit Service f6e53a
=head1 SEE ALSO
Packit Service f6e53a
Packit Service f6e53a
L<perl(1)>, L<axfr>, L<check_soa>, L<mresolv>, L<mx>, L<perldig>, L<Net::DNS>
Packit Service f6e53a
Packit Service f6e53a
=cut
Packit Service f6e53a
Packit Service f6e53a
use strict;
Packit Service f6e53a
use vars qw($opt_r);
Packit Service f6e53a
Packit Service f6e53a
use Getopt::Std;
Packit Service f6e53a
use File::Basename;
Packit Service f6e53a
use IO::Socket;
Packit Service f6e53a
use Net::DNS;
Packit Service f6e53a
Packit Service f6e53a
getopts("r");
Packit Service f6e53a
Packit Service f6e53a
die "Usage: ", basename($0), " [ -r ] domain [ class ]\n"
Packit Service f6e53a
	unless (@ARGV >= 1) && (@ARGV <= 2);
Packit Service f6e53a
Packit Service f6e53a
check_domain(@ARGV);
Packit Service f6e53a
exit;
Packit Service f6e53a
Packit Service f6e53a
sub check_domain {
Packit Service f6e53a
	my ($domain, $class) = @_;
Packit Service f6e53a
	$class ||= "IN";
Packit Service f6e53a
Packit Service f6e53a
	print "-" x 70, "\n";
Packit Service f6e53a
	print "$domain (class $class)\n";
Packit Service f6e53a
	print "\n";
Packit Service f6e53a
Packit Service f6e53a
	my $res = Net::DNS::Resolver->new;
Packit Service f6e53a
	$res->defnames(0);
Packit Service f6e53a
	$res->retry(2);
Packit Service f6e53a
Packit Service f6e53a
	my $nspack = $res->query($domain, "NS", $class);
Packit Service f6e53a
Packit Service f6e53a
	unless (defined($nspack)) {
Packit Service f6e53a
		warn "Couldn't find nameservers for $domain: ",
Packit Service f6e53a
		     $res->errorstring, "\n";
Packit Service f6e53a
		return;
Packit Service f6e53a
	}
Packit Service f6e53a
Packit Service f6e53a
	print "nameservers (will request zone from first available):\n";
Packit Service f6e53a
	my $ns;
Packit Service f6e53a
	foreach $ns (grep { $_->type eq "NS" } $nspack->answer) {
Packit Service f6e53a
		print "\t", $ns->nsdname, "\n";
Packit Service f6e53a
	}
Packit Service f6e53a
	print "\n";
Packit Service f6e53a
		
Packit Service f6e53a
	$res->nameservers(map  { $_->nsdname }
Packit Service f6e53a
			  grep { $_->type eq "NS" }
Packit Service f6e53a
			  $nspack->answer);
Packit Service f6e53a
Packit Service f6e53a
	my @zone = $res->axfr($domain, $class);
Packit Service f6e53a
	unless (@zone) {
Packit Service f6e53a
		warn "Zone transfer failed: ", $res->errorstring, "\n";
Packit Service f6e53a
		return;
Packit Service f6e53a
	}
Packit Service f6e53a
Packit Service f6e53a
	print "checking PTR records\n";
Packit Service f6e53a
	check_ptr($domain, $class, @zone);
Packit Service f6e53a
	print "\n";
Packit Service f6e53a
Packit Service f6e53a
	print "checking NS records\n";
Packit Service f6e53a
	check_ns($domain, $class, @zone);
Packit Service f6e53a
	print "\n";
Packit Service f6e53a
Packit Service f6e53a
	print "checking MX records\n";
Packit Service f6e53a
	check_mx($domain, $class, @zone);
Packit Service f6e53a
	print "\n";
Packit Service f6e53a
Packit Service f6e53a
	print "checking CNAME records\n";
Packit Service f6e53a
	check_cname($domain, $class, @zone);
Packit Service f6e53a
	print "\n";
Packit Service f6e53a
Packit Service f6e53a
	if ($opt_r) {
Packit Service f6e53a
		print "checking subdomains\n\n";
Packit Service f6e53a
		my %subdomains;
Packit Service f6e53a
		foreach (grep { $_->type eq "NS" and $_->name ne $domain } @zone) {
Packit Service f6e53a
			$subdomains{$_->name} = 1;
Packit Service f6e53a
		}
Packit Service f6e53a
		foreach (sort keys %subdomains) {
Packit Service f6e53a
			check_domain($_, $class);
Packit Service f6e53a
		}
Packit Service f6e53a
	}
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
sub check_ptr {
Packit Service f6e53a
	my ($domain, $class, @zone) = @_;
Packit Service f6e53a
	my $res = Net::DNS::Resolver->new;
Packit Service f6e53a
	my $rr;
Packit Service f6e53a
	foreach $rr (grep { $_->type eq "A" } @zone) {
Packit Service f6e53a
		my $host = $rr->name;
Packit Service f6e53a
		my $addr = $rr->address;
Packit Service f6e53a
		my $ans = $res->send($addr, "A", $class);
Packit Service f6e53a
		print "\t$host ($addr) has no PTR record\n"
Packit Service f6e53a
			if ($ans->header->ancount < 1);
Packit Service f6e53a
	}
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
sub check_ns {
Packit Service f6e53a
	my ($domain, $class, @zone) = @_;
Packit Service f6e53a
	my $res = Net::DNS::Resolver->new;
Packit Service f6e53a
	my $rr;
Packit Service f6e53a
	foreach $rr (grep { $_->type eq "NS" } @zone) {
Packit Service f6e53a
		my $ans = $res->send($rr->nsdname, "A", $class);
Packit Service f6e53a
		print "\t", $rr->nsdname, " has no A record\n"
Packit Service f6e53a
			if ($ans->header->ancount < 1);
Packit Service f6e53a
	}
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
sub check_mx {
Packit Service f6e53a
	my ($domain, $class, @zone) = @_;
Packit Service f6e53a
	my $res = Net::DNS::Resolver->new;
Packit Service f6e53a
	my $rr;
Packit Service f6e53a
	foreach $rr (grep { $_->type eq "MX" } @zone) {
Packit Service f6e53a
		my $ans = $res->send($rr->exchange, "A", $class);
Packit Service f6e53a
		print "\t", $rr->exchange, " has no A record\n"
Packit Service f6e53a
			if ($ans->header->ancount < 1);
Packit Service f6e53a
	}
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
sub check_cname {
Packit Service f6e53a
	my ($domain, $class, @zone) = @_;
Packit Service f6e53a
	my $res = Net::DNS::Resolver->new;
Packit Service f6e53a
	my $rr;
Packit Service f6e53a
	foreach $rr (grep { $_->type eq "CNAME" } @zone) {
Packit Service f6e53a
		my $ans = $res->send($rr->cname, "A", $class);
Packit Service f6e53a
		print "\t", $rr->cname, " has no A record\n"
Packit Service f6e53a
			if ($ans->header->ancount < 1);
Packit Service f6e53a
	}
Packit Service f6e53a
}