http://www.perlmonks.org?node_id=18912
Category: Networking Code
Author/Contact Info jon@divisionbyzero.com
Description:
This script should be pretty straightforward. Feed it a network (ip
address/CIDR or ip address/netmask ) and it scans the dns records of said 
network, reporting theresults to STDOUT. Neat. 

Note: This script views the following notations as equivalent:
	
	10.0.0.0/24
	10.0.0.0/255.255.255.0
	10.0.0.0:255.255.255.0

Rather than reinvent the wheel, I cheated and used Net::Netmask. Eventually
I'll write a sub to handle slash/netmask notation, but until then this program
requires the forementioned module, which is available from cpan.

Here's some example output (and no, none of these machines are publicly
routable, so don't even think about it):


nooky:~$ ./scandns.pl 10.0.0.0/24
<----snip---->
10.0.0.202 => beauty.zacknetwork.com => 10.0.3.101 
10.0.0.203 => tman.zacknetwork.com => 10.0.3.15 
10.0.0.204 => afterglow.zacknetwork.com 
10.0.0.205 => serenity.zacknetwork.com => 10.0.7.10 
10.0.0.206 => girth.zacknetwork.com => girth.zacknetwork.com has no A record
10.0.0.207 => no PTR record
<----snip---->


Note that afterglow's A and PTR records matched. Ideally there shouldn't be
anthing in the third column. If there is, then your forward/inverse records
aren't getting along very well.
#!/usr/bin/perl -w
#
# File:           scandns.pl
# Summary:        dns cleanup tool
#
# Author:         Jon Schatz
# E-Mail:         jon@divisionbyzero.com
# Org:            
#
# Orig-Date:      22-Mar-00 at 13:30:53
# Last-Mod:       19-Jun-00 at 16:24:42 by 
#
#    This program is free software; you can redistribute it and/or mod
+ify it
#    under the terms of the GNU General Public License as published
#    by the Free Software Foundation; either version 1, or (at your op
+tion)
#    any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See either
#    the GNU General Public License or the Artistic License for more d
+etails.
#
# 
# $Source: /home/jschatz/.cvs/el/file-hdr/hdr.perl,v $
# $Date: 1999/12/23 00:06:23 $
# $Revision: 1.1.1.1 $
# $Author: tkunze $
# $State: Exp $
# $Locker:  $
#
# -*- EOF -*-


use IO::Socket;
use Net::Netmask;
use strict;

my ($network)=@ARGV;

#separate the netmask from the network

my ($ip_address,$netmask) = split /[\/||:]/ , $network;
my $address;

&usage unless ($ip_address); #complain if @ARGV was incorrect
&badip unless (&validip($ip_address)); #copmlain if $ip_address is inv
+alid

#complain if $netmask is bad. unfortunately Net::Netmask only warns if
+ it's
#given an invalid netmask. I'm working on a patch so that the module w
+ill
#be smart enough to return something useful when it cant parse the net
+mask.

&badnet unless (&validnet($netmask));

#if the netmask is given as a netmask (ie, 255.255.255.0 as opposed to
+ CIDR
# notation (/24)), then ditch the "/" since Net::Netmask isn't smart e
+nough
# to do that either.

$network=~s/\//:/ if (validip($netmask));

#create the netmask object

(my $obj=Net::Netmask->new ($network)) or die "Invalid address / netma
+sk\n";

#return an array of all addresses in the given network

my (@addresses)=$obj->enumerate();


foreach $address (@addresses) {
  &checkdns($address);
}

#the good stuff

sub checkdns {
  my ($ip_address)=@_;
  my ($packed_ip_address)=&get_packed_ip($ip_address);
  my ($hostname)=gethostbyaddr($packed_ip_address, AF_INET);
  
  if (! $hostname) { 
    &no_ptr("$ip_address"); 
    return; 
  }
  
  my $reverse_packed_ip_address;
  $reverse_packed_ip_address=gethostbyname($hostname);
  
  if (length($reverse_packed_ip_address)!=4) { 
    &no_a("$ip_address","$hostname"); 
    return;
  }
  
  my ($reverse_ip_address)=inet_ntoa($reverse_packed_ip_address);
  
  if ($reverse_ip_address ne $ip_address) {
    print("$ip_address => $hostname => $reverse_ip_address \n");
  }
  
  else {
    print("$ip_address => $hostname \n");
  }
}

sub no_ptr {
  my ($ip_address)=@_;
  print "$ip_address => no PTR record\n";
  
  return;
}

sub no_a {
  my ($ip_address, $hostname)=@_;
  print "$ip_address => $hostname => $hostname has no A record\n";
  return;
}

sub badip {
  print "$ip_address is an invalid address.\n";
  exit 1;
}

sub badnet {
  print "/$netmask is an invalid netmask.\n";
  exit 1;
}

sub usage {
  print "Usage: scandns.pl <address>[/netmask]\n";
  exit 1;
}

sub validnet {
  my ($netmask)=@_;
  return(1) if (validip($netmask)) ;
  return(1) if (($netmask>=0)&&($netmask<=32));
}

#this is an ip checker that seems simpler to me than the enormous rege
+x in
#the cookbook. since it's only executed twice, it's probably not gener
+ating
#that much overhead.

sub validip {
  my ($ip)=@_;
  my $x;
  foreach ($ip=~/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/){ 
    $x++ if(($_>=0)&&($_<=255)); 
  }
  return($x==4);
}

sub get_packed_ip {
 
  my ($ip)=@_;
  chomp $ip;
  my $a;
  my $b;
  my $c;
  my $d;
  ($a, $b, $c, $d)=split(/\./,$ip);
  my $packed_ip=pack "C4","$a","$b","$c","$d";
  return $packed_ip;
}

sub bin2dec {
  my $str= unpack("B8", pack("N", shift));
  $str=~s/^0+(?=\d)//;
  return $str;
}

sub dec2bin {
  return unpack("N",pack("B8", substr("0"x 8, -8)));
}