Skip to content

Instantly share code, notes, and snippets.

@bitfolk
Created December 12, 2012 12:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitfolk/4267353 to your computer and use it in GitHub Desktop.
Save bitfolk/4267353 to your computer and use it in GitHub Desktop.
Check that reverse DNS exists for every one of a big list of IPv4 and IPv6 addresses.
#!/usr/bin/perl
use strict;
use warnings;
use Net::IP qw(:PROC);
use Net::DNS;
use Getopt::Long;
use Pod::Usage;
my ($allow_invalid, $help, $man) = (0, 0, 0);
GetOptions(
'allowinvalid|a|daviey' => \$allow_invalid,
'help|?' => \$help,
'man' => \$man,
) or pod2usage(2);
pod2usage(1) if ($help);
pod2usage(-exitstatus => 0, -verbose => 2) if ($man);
my $res = Net::DNS::Resolver->new;
my @invalid_v6;
my @invalid_v4;
# IP ranges that aren't valid on the Internet (localhost, RFC1918, etc.) in
# CIDR format.
foreach (
'0000::0/127', # Loopback
'fc00::/8', # Unique local
'fd00::/8', # Unique local
'fe80:0000::/10', # Link-local
'0000::/3', # Non-interface
'0000::/8', # Reserved
'fec0:0000::/10', # Site-local (obsolete)
) {
push(@invalid_v6, Net::IP->new($_));
}
foreach (
'127.0.0.0/8', # Loopback
'10.0.0.0/8', # RFC1918
'172.16.0.0/12', # RFC1918
'192.168.0.0/16', # RFC1918
'224.0.0.0/4', # Class D multicast
'240.0.0.0/5', # Class E reserved
'248.0.0.0/5', # Reserved
'192.0.2.0/24', # Reserved for test
'0.0.0.0/8', # Reserved broadcast
'169.254.0.0/16', # Link-local
) {
push(@invalid_v4, Net::IP->new($_));
}
my %ips;
my $dsh;
open $dsh, '-|', 'sudo', 'dsh', '-Mca', '-r', 'ssh', '-o-q', 'ip -4 addr'
or die "Can't pipe from dsh: $!";
while (<$dsh>) {
# admin.bitfolk.com: 1: lo: <LOOPBACK,UP,10000> mtu 16436 qdisc noqueue
# admin.bitfolk.com: inet 127.0.0.1/8 scope host lo
# .
# .
#
# Only interested in lines that match inet and then an IPv4 address.
next unless (/^(\S+):\s+inet\s+(\d+\.\d+\.\d+\.\d+)\/\d+/i);
# Put them in a hash, which makes them unique as a side benefit.
$ips{$2} = $1;
}
close($dsh) or warn "Something weird when closing pipe: $!";
open $dsh, '-|', 'sudo', 'dsh', '-Mca', '-r', 'ssh', '-o-q',
'ip -o -6 addr show scope global' or die "Can't pipe from dsh: $!";
while (<$dsh>) {
# admin.bitfolk.com: 2: eth0 inet6 2001:ba8:1f1:f040::3/128 scope global \ valid_lft forever preferred_lft forever
# admin.bitfolk.com: 2: eth0 inet6 2001:ba8:1f1:f040::123/128 scope global \ valid_lft forever preferred_lft forever
# admin.bitfolk.com: 2: eth0 inet6 2001:ba8:1f1:f040:a800:ff:fe13:5ca4/64 scope global \ valid_lft forever preferred_lft forever
# backup0.bitfolk.com: 2: eth0 inet6 2001:ba8:1f1:f1e0::2/64 scope global \ valid_lft forever preferred_lft forever
# .
# .
#
# Only interested in lines that match a device called /eth|bond/, inet6 and
# then an IPv6 address.
next unless (/^(\S+):\s+\d+:\s+(?:eth|bond)\d+\s+inet6\s+([0-9a-f:]+)\/\d+/i);
$ips{$2} = $1;
}
foreach my $i (keys %ips) {
my $is_invalid = 0;
my $net_ip = Net::IP->new($i);
my $invalid_ref;
if (not $allow_invalid) {
if (ip_is_ipv6($i)) {
$invalid_ref = \@invalid_v6;
} else {
$invalid_ref = \@invalid_v4;
}
foreach (@{ $invalid_ref }) {
if ($_->overlaps($net_ip) == $IP_B_IN_A_OVERLAP) {
$is_invalid = 1;
last;
}
}
if ($is_invalid) {
print "Not bothering to query $i because it isn't valid on the Internet.\n";
next;
}
}
my $query = $res->query($net_ip->reverse_ip, 'PTR');
if ($query) {
foreach my $rr ($query->answer) {
next unless $rr->type eq 'PTR';
# print $rr->rdatastr, "\n";
}
} else {
warn "query failed: ", $res->errorstring, " for $i on ",
$ips{$i}, "\n";
}
}
__END__
=pod
=head1 NAME
check_rev_dns_exists.pl -- Check that reverse DNS exists for every IP address on every host
=head1 SYNOPSIS
check_rev_dns_exists.pl [options]
Options:
-a, --allowinvalid, --daviey Check reverse DNS even for invalid IPs
=head1 OPTIONS
=over 4
=item B<-a>, B<--allowinvalid>, B<--daviey>
By default, IP addresses that belong to ranges that aren't expected to be valid
on the Internet do not have their reverse DNS checked. Supplying one of these
flags will force these to be checked too.
=back
=head1 DESCRIPTION
Connects to every host (using dsh) and lists configured IPv4 and v6 addresses.
Then checks that reverse DNS configuration exists for every one of them.
Ignores addresses that are not valid on the Internet, such as RFC1918 and
reserved ranges.
=head AUTHOR
Andy Smith <andy@bitfolk.com>
=head1 COPYRIGHT AND LICENSE
Copyright 2012 Andy Smith <andy@bitfolk.com>.
This program is free software; you can redistribute it and/or modify it under
the terms of the Perl Artistic License.
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment