|
Packit |
e6c8bb |
#!/usr/local/bin/perl -w
|
|
Packit |
e6c8bb |
# $Id: check_zone 638 2007-05-15 18:59:26Z olaf $
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 NAME
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
check_zone - Check a DNS zone for errors
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 SYNOPSIS
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
C<check_zone> [ C<-r> ][ C<-v> ] I<domain> [ I<class> ]
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 DESCRIPTION
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Checks a DNS zone for errors. Current checks are:
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=over 4
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item *
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Checks the domain's SOA from each of the domain's name servers. The SOA serial numbers should match. This program's output cannot be trusted if they do not.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item *
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Tries to perform an AXFR from each of the domain's name servers. This test helps to detect whether the name server is blocking AXFR.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item *
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Checks that all A records have corresponding PTR records. For each A record its PTR's name is match checked.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item *
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Checks that all PTR records match an A record (sometimes they match a CNAME). Check the PTR's name against the A record.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item *
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Checks that hosts listed in NS, MX, and CNAME records have
|
|
Packit |
e6c8bb |
A records. Checks for NS and CNAME records not pointing to another CNAME (i.e., they must directly resolve to an A record). That test may be somewhat controversial because, in many cases, a MX to a CNAME or a CNAME to another CNAME will resolve; however, in DNS circles it isn't a recommended practise.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item *
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Check each record processed for being with the class requested. This is an internal integrity check.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=back
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 OPTIONS
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=over 4
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=back
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item C<-r>
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Perform a recursive check on subdomains.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item C<-v>
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Verbose.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item C<-a alternate_domain>
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Treat <alternate_domain> as equal to <domain>. This is useful when supporting a change of domain names (eg from myolddomain.example.net to mynewdomain.example.net) where the PTR records can point to only one of the two supported domains (which are otherwise identical).
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=item C<-e exception_file>
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Ignore exceptions in file <exception_file>. File format can be space-separated domain pairs, one pair per line, or it can be straight output from this program itself (for simple cut-and-paste functionality).
|
|
Packit |
e6c8bb |
This allows for skipping entries that are odd or unusual, but not causing problems. Note: this only works with A - PTR checks.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 AUTHORS
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
Originally developed by Michael Fuhr (mfuhr@dimensional.com) and
|
|
Packit |
e6c8bb |
hacked--with furor--by Dennis Glatting
|
|
Packit |
e6c8bb |
(dennis.glatting@software-munitions.com).
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
"-a" and "-e" options added by Paul Archer
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 COPYRIGHT
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 SEE ALSO
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
L<perl(1)>, L<axfr>, L<check_soa>, L<mx>, L<perldig>, L<Net::DNS>
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=head1 BUGS
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
A query for an A RR against a name that is a CNAME may not follow the CNAME to an A RR.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
There isn't a mechanism to insure records are returned from an authoritative source.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
There appears to be a bug in the resolver AXFR routine where, if one server cannot be contacted, the routine doesn't try another in its list.
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
=cut
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
require 'assert.pl';
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use strict;
|
|
Packit |
e6c8bb |
use vars qw($opt_r);
|
|
Packit |
e6c8bb |
use vars qw($opt_v);
|
|
Packit |
e6c8bb |
use vars qw($opt_a);
|
|
Packit |
e6c8bb |
use vars qw($opt_e);
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use Getopt::Std;
|
|
Packit |
e6c8bb |
use File::Basename;
|
|
Packit |
e6c8bb |
use IO::Socket;
|
|
Packit |
e6c8bb |
use Net::DNS;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
getopts("rva:e:");
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
die "Usage: ", basename($0), " [ -r -v ] [ -a alternate_domain] [ -e eqivalent_domains_file ] domain [ class ]\n"
|
|
Packit |
e6c8bb |
unless (@ARGV >= 1) && (@ARGV <= 2);
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
our $exit_status = 0;
|
|
Packit |
e6c8bb |
$SIG{__WARN__} = sub {$exit_status=1 ; print STDERR @_ };
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$opt_r = 1;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
our $main_domain=$ARGV[0];
|
|
Packit |
e6c8bb |
our %exceptions = parse_exceptions_file();
|
|
Packit |
e6c8bb |
foreach my $key (sort keys %exceptions) {
|
|
Packit |
e6c8bb |
print "$key:\t";
|
|
Packit |
e6c8bb |
foreach my $val (@{$exceptions{$key}}) {
|
|
Packit |
e6c8bb |
print "$val ";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
check_domain(@ARGV);
|
|
Packit |
e6c8bb |
exit $exit_status;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub parse_exceptions_file {
|
|
Packit |
e6c8bb |
my %exceptions;
|
|
Packit |
e6c8bb |
my $file = $opt_e || "";
|
|
Packit |
e6c8bb |
return %exceptions unless ( -r $file);
|
|
Packit |
e6c8bb |
open FH, $file or warn "Couldn't read $file: $!";
|
|
Packit |
e6c8bb |
my $line;
|
|
Packit |
e6c8bb |
while ( defined ($line = <FH>) ) {
|
|
Packit |
e6c8bb |
chomp $line;
|
|
Packit |
e6c8bb |
#print " raw line: $line\n";
|
|
Packit |
e6c8bb |
next if $line =~ /^\s*#/;
|
|
Packit |
e6c8bb |
$line =~ s/#.*$//;
|
|
Packit |
e6c8bb |
$line =~ s/^\s*//;
|
|
Packit |
e6c8bb |
$line =~ s/\s*$//;
|
|
Packit |
e6c8bb |
$line =~ s/'//g;
|
|
Packit |
e6c8bb |
my ($left, $right) = (split /[\s:]+/, $line)[0, -1];
|
|
Packit |
e6c8bb |
push @{$exceptions{$left}}, $right;
|
|
Packit |
e6c8bb |
#print "processed line: $line\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
return %exceptions;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_domain {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my ( $domain, $class ) = @_;
|
|
Packit |
e6c8bb |
my $ns;
|
|
Packit |
e6c8bb |
my @zone;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$class ||= "IN";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "-" x 70, "\n";
|
|
Packit |
e6c8bb |
print "$domain (class $class)\n";
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $nspack, $ns_rr, @nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Get a list of name servers for the domain.
|
|
Packit |
e6c8bb |
# Error-out if the query isn't satisfied.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$nspack = $res->query( $domain, 'NS', $class );
|
|
Packit |
e6c8bb |
unless( defined( $nspack )) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "Couldn't find nameservers for $domain: ",
|
|
Packit |
e6c8bb |
$res->errorstring, "\n";
|
|
Packit |
e6c8bb |
return;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
printf( "List of name servers returned from '%s'\n", $res->answerfrom );
|
|
Packit |
e6c8bb |
foreach $ns_rr ( $nspack->answer ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$ns_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $ns_rr->class );
|
|
Packit |
e6c8bb |
assert( 'NS' eq $ns_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
if( $ns_rr->name eq $domain ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\t", $ns_rr->rdatastr, "\n";
|
|
Packit |
e6c8bb |
push @nsl, $ns_rr->rdatastr;
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "asked for '$domain', got '%s'\n", $ns_rr->rdatastr );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\tZone has no NS records\n" ) if( scalar( @nsl ) == 0 );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Transfer the zone from each of the name servers.
|
|
Packit |
e6c8bb |
# The zone is transferred for several reasons.
|
|
Packit |
e6c8bb |
# First, so the check routines won't (an efficiency
|
|
Packit |
e6c8bb |
# issue) and second, to see if we can.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->nameservers( @nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $ns ( @nsl ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->nameservers( $ns );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my @local_zone = $res->axfr( $domain, $class );
|
|
Packit |
e6c8bb |
unless( @local_zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "Zone transfer from '", $ns, "' failed: ",
|
|
Packit |
e6c8bb |
$res->errorstring, "\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
@zone = @local_zone if( ! @zone );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Query each name server for the zone
|
|
Packit |
e6c8bb |
# and check the zone's SOA serial number.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking SOA records\n";
|
|
Packit |
e6c8bb |
check_soa( $domain, $class, \@nsl );
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Check specific record types.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking NS records\n";
|
|
Packit |
e6c8bb |
check_ns( $domain, $class, \@nsl, \@zone );
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking A records\n";
|
|
Packit |
e6c8bb |
check_a( $domain, $class, \@nsl, \@zone );
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking PTR records\n";
|
|
Packit |
e6c8bb |
check_ptr( $domain, $class, \@nsl, \@zone );
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking MX records\n";
|
|
Packit |
e6c8bb |
check_mx( $domain, $class, \@nsl, \@zone );
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking CNAME records\n";
|
|
Packit |
e6c8bb |
check_cname( $domain, $class, \@nsl, \@zone );
|
|
Packit |
e6c8bb |
print "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Recurse?
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
if( $opt_r ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my %subdomains;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "checking subdomains\n\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Get a list of NS records from the zone that
|
|
Packit |
e6c8bb |
# are not for the zone (i.e., they're subdomains).
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach ( grep { $_->type eq 'NS' and $_->name ne $domain } @zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$subdomains{$_->name} = 1;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# For each subdomain, check it.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach ( sort keys %subdomains ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
check_domain($_, $class);
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_soa {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $domain, $class, $nsl ) = @_;
|
|
Packit |
e6c8bb |
my( $soa_sn, $soa_diff ) = ( 0, 0 );
|
|
Packit |
e6c8bb |
my( $ns, $soa_rr );
|
|
Packit |
e6c8bb |
my $rr_count = 0;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->recurse( 0 );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Contact each name server and get the
|
|
Packit |
e6c8bb |
# SOA for the somain.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $ns ( @$nsl ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $soa = 0;
|
|
Packit |
e6c8bb |
my $nspack;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Query the name server and test
|
|
Packit |
e6c8bb |
# for a result.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->nameservers( $ns );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$nspack = $res->query( $domain, "SOA", $class );
|
|
Packit |
e6c8bb |
unless( defined( $nspack )) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "Couldn't get SOA from '$ns'\n";
|
|
Packit |
e6c8bb |
next;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Look at each SOA for the domain from the
|
|
Packit |
e6c8bb |
# name server. Specifically, look to see if
|
|
Packit |
e6c8bb |
# its serial number is different across
|
|
Packit |
e6c8bb |
# the name servers.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $soa_rr ( $nspack->answer ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$soa_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $soa_rr->class );
|
|
Packit |
e6c8bb |
assert( 'SOA' eq $soa_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\t$ns:\t", $soa_rr->serial, "\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# If soa_sn is zero then an SOA serial number
|
|
Packit |
e6c8bb |
# hasn't been recorded. In that case record
|
|
Packit |
e6c8bb |
# the serial number. If the serial number
|
|
Packit |
e6c8bb |
# doesn't match a previously recorded one then
|
|
Packit |
e6c8bb |
# indicate they are different.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
# If the serial numbers are different then you
|
|
Packit |
e6c8bb |
# cannot really trust the remainder of the test.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
if( $soa_sn ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$soa_diff = 1 if ( $soa_sn != $soa_rr->serial );
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$soa_sn = $soa_rr->serial;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
++$rr_count;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\t*** SOAs are different!\n" if( $soa_diff );
|
|
Packit |
e6c8bb |
print "$rr_count SOA RRs checked.\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_ptr {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $domain, $class, $nsl, $zone ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
my $ptr_rr;
|
|
Packit |
e6c8bb |
my $rr_count = 0;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $ptr_rr ( grep { $_->type eq 'PTR' } @$zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my @types;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$ptr_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $ptr_rr->class );
|
|
Packit |
e6c8bb |
assert( 'PTR' eq $ptr_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\tchecking PTR rr '$ptr_rr' to PTR\n" if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
@types = types4name( $ptr_rr->ptrdname, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
if( grep { $_ eq 'A' } @types ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
xcheck_ptr2a( $ptr_rr, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "\t'", $ptr_rr->ptrdname,
|
|
Packit |
e6c8bb |
"' doesn't resolve to an A RR (RRs are '",
|
|
Packit |
e6c8bb |
join( ', ', @types ), "')\n";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
++$rr_count;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "$rr_count PTR RRs checked.\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_ns {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $domain, $class, $nsl, $zone ) = @_;
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
my $ns_rr;
|
|
Packit |
e6c8bb |
my $rr_count = 0;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Go through the zone data and process
|
|
Packit |
e6c8bb |
# all NS RRs for the zone (delegation
|
|
Packit |
e6c8bb |
# NS RRs are ignored). Specifically,
|
|
Packit |
e6c8bb |
# check to see if the indicate name server
|
|
Packit |
e6c8bb |
# is a CNAME RR and the name resolves to an A
|
|
Packit |
e6c8bb |
# RR. Check to insure the address resolved
|
|
Packit |
e6c8bb |
# against the name has an associated PTR RR.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $ns_rr ( grep { $_->type eq 'NS' } @$zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my @types;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$ns_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $ns_rr->class );
|
|
Packit |
e6c8bb |
assert( 'NS' eq $ns_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
next if( $ns_rr->name ne $domain );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
printf( "rr nsdname: %s\n", $ns_rr->nsdname ) if $opt_v;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
@types = types4name( $ns_rr->nsdname, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
if( grep { $_ eq 'A' } @types ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
xcheck_name( $ns_rr->nsdname, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "\t'", $ns_rr->nsdname,
|
|
Packit |
e6c8bb |
"' doesn't resolve to an A RR (RRs are '",
|
|
Packit |
e6c8bb |
join( ', ', @types ), "')\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
++$rr_count;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "$rr_count NS RRs checked.\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_a {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $domain, $class, $nsl, $zone ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
my $a_rr;
|
|
Packit |
e6c8bb |
my $rr_count = 0;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Go through the zone data and process
|
|
Packit |
e6c8bb |
# all A RRs. Specifically, check to insure
|
|
Packit |
e6c8bb |
# each A RR matches a PTR RR and the PTR RR
|
|
Packit |
e6c8bb |
# matches the A RR.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $a_rr ( grep { $_->type eq 'A' } @$zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$a_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $a_rr->class );
|
|
Packit |
e6c8bb |
assert( 'A' eq $a_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\tchecking A RR '", $a_rr->address, "' to PTR\n" if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
xcheck_a2ptr( $a_rr, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
++$rr_count;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "$rr_count A RRs checked.\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_mx {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $domain, $class, $nsl, $zone ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
my $mx_rr;
|
|
Packit |
e6c8bb |
my $rr_count = 0;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Go through the zone data and process
|
|
Packit |
e6c8bb |
# all MX RRs. Specifically, check to insure
|
|
Packit |
e6c8bb |
# each MX RR resolves to an A RR and the
|
|
Packit |
e6c8bb |
# A RR has a matching PTR RR.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $mx_rr ( grep { $_->type eq 'MX' } @$zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$mx_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $mx_rr->class );
|
|
Packit |
e6c8bb |
assert( 'MX' eq $mx_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\tchecking MX RR '", $mx_rr->exchange, "' to A\n" if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
xcheck_name( $mx_rr->exchange, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
++$rr_count;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "$rr_count MX RRs checked.\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_cname {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $domain, $class, $nsl, $zone ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
my $cname_rr;
|
|
Packit |
e6c8bb |
my $rr_count = 0;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Go through the zone data and process
|
|
Packit |
e6c8bb |
# all CNAME RRs. Specifically, check to insure
|
|
Packit |
e6c8bb |
# each CNAME RR resolves to an A RR and the
|
|
Packit |
e6c8bb |
# A RR has a matching PTR RR.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
foreach $cname_rr ( grep { $_->type eq 'CNAME' } @$zone ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my @types;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$cname_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $cname_rr->class );
|
|
Packit |
e6c8bb |
assert( 'CNAME' eq $cname_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "\tchecking CNAME RR '", $cname_rr->cname, "' to A\n"
|
|
Packit |
e6c8bb |
if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
@types = types4name( $cname_rr->cname, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
if( grep { $_ eq 'A' } @types ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
xcheck_name( $cname_rr->cname, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "\t'", $cname_rr->cname,
|
|
Packit |
e6c8bb |
"' doesn't resolve to an A RR (RRs are '",
|
|
Packit |
e6c8bb |
join( ', ', @types ), "')\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
++$rr_count;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print "$rr_count CNAME RRs checked.\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub check_w_equivs_and_exceptions {
|
|
Packit |
e6c8bb |
my ($left, $comp, $right) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
if (defined $exceptions{$left}) {
|
|
Packit |
e6c8bb |
foreach my $rval (@{$exceptions{$left}}) {
|
|
Packit |
e6c8bb |
$left = $right if ($rval eq $right);
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
if ($opt_a){
|
|
Packit |
e6c8bb |
$left =~ s/\.?$opt_a$//;
|
|
Packit |
e6c8bb |
$left =~ s/\.?$main_domain$//;
|
|
Packit |
e6c8bb |
$right =~ s/\.?$opt_a$//;
|
|
Packit |
e6c8bb |
$right =~ s/\.?$main_domain$//;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
return (eval ("\"$left\" $comp \"$right\"") );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub xcheck_a2ptr {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $a_rr, $domain, $class, $nsl ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $a_rr->class );
|
|
Packit |
e6c8bb |
assert( 'A' eq $a_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Request a PTR RR against the A RR.
|
|
Packit |
e6c8bb |
# A missing PTR RR is an error.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ans = $res->query( $a_rr->address, 'PTR', $class );
|
|
Packit |
e6c8bb |
if( defined( $ans )) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ptr_rr;
|
|
Packit |
e6c8bb |
foreach $ptr_rr ( $ans->answer ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$ptr_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $ptr_rr->class );
|
|
Packit |
e6c8bb |
assert( 'PTR' eq $ptr_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\t'", $a_rr->name, "' has address '",
|
|
Packit |
e6c8bb |
$a_rr->address, "' but PTR is '",
|
|
Packit |
e6c8bb |
$ptr_rr->ptrdname, "'\n" )
|
|
Packit |
e6c8bb |
if( check_w_equivs_and_exceptions($a_rr->name, "ne", $ptr_rr->ptrdname) );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\t'", $a_rr->name, "' has address '",
|
|
Packit |
e6c8bb |
$a_rr->address, "' but PTR is '",
|
|
Packit |
e6c8bb |
ip_ptr2a_str( $ptr_rr->name ), "'\n" )
|
|
Packit |
e6c8bb |
if( $a_rr->address ne ip_ptr2a_str( $ptr_rr->name ));
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\tNO PTR RR for '", $a_rr->name,
|
|
Packit |
e6c8bb |
"' at address '", $a_rr->address,"'\n" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub xcheck_ptr2a {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $ptr_rr, $domain, $class, $nsl ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $ptr_rr->class );
|
|
Packit |
e6c8bb |
assert( 'PTR' eq $ptr_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Request an A RR against the PTR RR.
|
|
Packit |
e6c8bb |
# A missing A RR is an error.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ans = $res->query( $ptr_rr->ptrdname, 'A', $class );
|
|
Packit |
e6c8bb |
if( defined( $ans )) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $a_rr;
|
|
Packit |
e6c8bb |
foreach $a_rr ( $ans->answer ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$a_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $a_rr->class );
|
|
Packit |
e6c8bb |
assert( 'A' eq $a_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\tPTR RR '", $ptr_rr->name, "' has name '",
|
|
Packit |
e6c8bb |
$ptr_rr->ptrdname, "' but A query returned '",
|
|
Packit |
e6c8bb |
$a_rr->name, "'\n" )
|
|
Packit |
e6c8bb |
if( check_w_equivs_and_exceptions($ptr_rr->ptrdname, "ne", $a_rr->name) );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\tPTR RR '", $ptr_rr->name, "' has address '",
|
|
Packit |
e6c8bb |
ip_ptr2a_str( $ptr_rr->name ),
|
|
Packit |
e6c8bb |
"' but A query returned '", $a_rr->address, "'\n" )
|
|
Packit |
e6c8bb |
if( ip_ptr2a_str( $ptr_rr->name ) ne $a_rr->address );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\tNO A RR for '", $ptr_rr->ptrdname,
|
|
Packit |
e6c8bb |
"' at address '", ip_ptr2a_str( $ptr_rr->address ), "'\n" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub xcheck_name {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $name, $domain, $class, $nsl ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Get the A RR for the name.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ans = $res->query( $name, 'A', $class );
|
|
Packit |
e6c8bb |
if( defined( $ans )) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# There is one or more A RRs.
|
|
Packit |
e6c8bb |
# For each A RR do a reverse look-up
|
|
Packit |
e6c8bb |
# and verify the PTR matches the A.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $a_rr;
|
|
Packit |
e6c8bb |
foreach $a_rr ( $ans->answer ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$a_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $a_rr->class );
|
|
Packit |
e6c8bb |
assert( 'A' eq $a_rr->type );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\tQuery for '$name' returned A RR name '",
|
|
Packit |
e6c8bb |
$a_rr->name, "'\n" )
|
|
Packit |
e6c8bb |
if( check_w_equivs_and_exceptions($name, "ne", $a_rr->name) );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
xcheck_a2ptr( $a_rr, $domain, $class, $nsl );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\t", $name, " has no A RR\n" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub types4name {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $name, $domain, $class, $nsl ) = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $res = new Net::DNS::Resolver;
|
|
Packit |
e6c8bb |
my @rr_types;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$res->defnames( 0 );
|
|
Packit |
e6c8bb |
$res->retry( 2 );
|
|
Packit |
e6c8bb |
$res->nameservers( @$nsl );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# Get the RRs for the name.
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ans = $res->query( $name, 'ANY', $class );
|
|
Packit |
e6c8bb |
if( defined( $ans )) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $any_rr;
|
|
Packit |
e6c8bb |
foreach $any_rr ( $ans->answer ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$any_rr->print if( $opt_v );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( $class eq $any_rr->class );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
push @rr_types, ( $any_rr->type );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn( "\t'", $name, "' doesn't resolve.\n" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
# If there were no RRs for the name then
|
|
Packit |
e6c8bb |
# return the RR types of ???
|
|
Packit |
e6c8bb |
#
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
push @rr_types, ( '???' ) if( ! @rr_types );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
return @rr_types;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub ip_ptr2a_str {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my( $d, $c, $b, $a ) = ip_parts( $_[0]);
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
return "$a.$b.$c.$d";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub ip_parts {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ip = $_[0];
|
|
Packit |
e6c8bb |
assert( $ip ne '' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
if( $ip =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/oi ) {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
return ( $1, $2, $3, $4 );
|
|
Packit |
e6c8bb |
} else {
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
warn "Unable to parse '$ip'\n";
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
assert( 0 );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|