|
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 |
}
|