Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Mass Domain Name Lookup

by argus (Acolyte)
on Nov 15, 2001 at 21:40 UTC ( [id://125625]=sourcecode: print w/replies, xml ) Need Help??
Category: networking
Author/Contact Info John Barrett
Description: This code will allow you to query several nameservers for different fully qualified domain names.

The help:

Mass domain name lookup Usage: ./mdnl.pl [--ns <nameserver> --addr <FQDN> --verbose --outfile +<filename> --nsfile <filename> --addrfile <filename>] --ns <namserver> Nameserver to query against --addr <FQDN> Fully qualified domin name (FQDN) to query --verbose Output data to the screen --outfile <filename> Tab delimited file to output to --nsfile <filename> File of nameservers to query against (nameserv +er<tab>ISP) --addrfile <filename> Tab delimited file of adresses to query --help Print help text (what you're reading now)
You must have either --verbose or --outfile, --addr or --addrfile & --ns or --nsfile.

The structure of the nsfile is IP\tISP Name
(the ISP Name was something folks here wanted, I just wrote a little script to query ARIN against all the IPs)
In the addrfile enter a fully qualified domain name (fqdn) on each line.

The outputfile structure is:
Nameserver\tfqdn\tttl (in seconds)\tIP resolved

On the command line you can can have either --addr fqdn --addr fqdn or --addr fqdn,fqdn, this holds true for --ns as well.

Please give me comments and feedback. anything I am doing wrong or could be done better is helpful.

Thanks

Update: Total code update based on comments. which were greatly appricated and help me learn.

#!/usr/local/bin/perl                                           

#--------------------------------------------------------------------#
# Mass domain name lookup
#       Author:         John Barrett
#
#       This is written to query multiple name servers for the 
#         same information.  To ensure proper propagation of 
#         DNS changes.
#--------------------------------------------------------------------#
#
#  Many thanks to www.perlmonks.com for help and resources!
#
#--------------------------------------------------------------------#
use Getopt::Long;

# Setup my variables
my $dig "/usr/local/bin/dig";                                    
my $help = 0;
my $verbose = 0;
my $outfile = '';
my $nsfile = '';
my $addrfile = '';
my @ns = ();
my @addr = ();
my $type = "IN A";                                           
my $i = 0;
my @time_values = qw [ d h m s ];
my %time_value  = ( d => 86400, h => 3600, m => 60, s => 1 );


# Define the options for getopts (These allow us to pass commands on t
+he commandline) 
GetOptions ('help' => \$help,
            'verbose' => \$verbose,
            'ns:s' => \@ns,
            'addr:s' => \@addr,
            'outfile:s' => \$outfile,
            'nsfile:s' => \$nsfile,
            'addrfile:s' => \$addrfile
);

# This will allow the use of multiple values for one comman switch
# e.g. --addr domain.name,domain.name2 
@ns = split(/,/,join(',',@ns));
@addr = split(/,/,join(',',@addr));

if ( $help
    ||  !@ns && !$nsfile
    ||  !@addr && !$addrfile
    ||  !$verbose && !$outfile ) {
    print <<END;
Mass domain name lookup
Usage: $0\t[--ns <nameserver> --addr <FQDN> --verbose 
\t\t--outfile <filename> --nsfile <filename> --addrfile <filename>]
--ns <namserver>\tNameserver to quer against
--addr <FQDN>\t\tFully qualified domin name (FQDN) to query
--verbose\t\tOutput data to th screen rathr than a file
--outfile <filename>\tTab delimited file to output to 
--nsfile <filename>\tTab delimited file of nameservers to query agains
+t 
--addrfile <filename>\tTab delimited file of adresses to query
--help\t\t\tPrint help text (what you're reading now)
END
    exit;
}

if (!@ns) {
  open (DATAIN, "< $nsfile") || die "can't open file: $!";  
                                                          
  while (<DATAIN>) {                                        
    chomp;                                                 
    my ($one,$two) = split(/\t/);
   if ($one ne '') { 
    push (@dns, $one);
    if($two){
      push (@provide, $two);
    } else {
      push (@provide, "Unknown");
    }                                       
   }
  }                                                         
                                                          
  close DATAIN;                                             
} else {
  @dns = @ns;
  push @provide, ('Unknown') x @ns; 
}

if (!@addr) {
  open (DATAIN, "< $addrfile") || die "can't open file: $!";  
                                                          
  while (<DATAIN>) {                                        
    chomp;                                                 
    my ($one,$two) = split(/\t/);
   if ($one ne '') { 
    push (@addr, $one);
   }                         
  }                                                         
                                                          
  close DATAIN;                                             
}


foreach $ldns (@dns) {   
   if ($verbose) {
      print "=========================================================
+======\n";
      print "== Local DNS: $ldns Provider: $provide[$i]\n";           
+      
      print "=========================================================
+======\n"; 
   }
   $i++;
       foreach $fqdn (@addr) {             
          lookup ($ldns, $fqdn);               
       }         
}                  

if (@data_out) {
    open (DATAOUT, ">> $outfile") || die "can't open $outfile: $!";
        print DATAOUT @data_out;
    close DATAOUT;
}

sub lookup {
    my ($ldns, $fqdn) = @_;

    my ($error, $error_a);

    open DIG, "$dig \@$ldns $type $fqdn | " or die $!;
        while (<DIG>) {
            if (/;; ->>HEADER<<- opcode: QUERY\s|QUERY, status: NOERRO
+R, .*/) {
                $error = 1;
                next;
            }
            next unless /$fqdn\.\s+(\w+)(\s+A|\s+IN\sA)\s+(.*)/;

            $error_a    = 1;
            my $time    = lc($1);
            my $ip      = $3;
            my $seconds = $time =~ /[dhms]/ ? string_to_time($time) : 
+$time;
            my $extended_time = time_to_string($seconds);
            print "Request: $fqdn\tTTL: $extended_time\tIP: $ip\n" if 
+$verbose;
            push @data_out, "$ldns\t$fqdn\t$seconds\t$ip\n" if $outfil
+e;
        }
    close DIG;

    if (!$error) {
        print "Request: $fqdn\tERROR (No domain found)\n" if $verbose;
        push @data_out, "$ldns\t$fqdn\tERROR\tNO DOMAIN\n" if $outfile
+;
    } elsif (!$error_a) {
        print "Request: $fqdn\tERROR (Domain found, no A record found)
+\n" if $verbose;
        push @data_out, "$ldns\t$fqdn\tERROR\tNOT A RECORD\n" if $outf
+ile;
    }
}

sub string_to_time
{
        my ($time) = @_;
        my $value  = 0;

        foreach my $letter (@time_values)
        {
                if ($time =~ s/(\d+)$letter//)
                {
                        $value += $1 * $time_value{$letter};
                }
        }

        return -1 if length $time;

        return $value;
}

sub time_to_string
{
        my ($time) = @_;
        my $value  = '';

        foreach my $letter (@time_values)
        {
                my $time_value = $time_value{$letter};

                if ($time > $time_value)
                {
                        $value .= int($time/$time_value).$letter;
                        $time %= $time_value;
                }
        }

        return $value;
}
Replies are listed 'Best First'.
Re: Mass Domain Name Lookup
by CharlesClarkson (Curate) on Nov 16, 2001 at 20:54 UTC

    You're opening and closing DATAOUT too often. How about loading an array and doing the write to file just once.

    sub lookup { my ($ldns, $fqdn) = @_; my ($error, $error_a); open DIG, "$dig \@$ldns $type $fqdn | " or die $!; while (<DIG>) { if (/;; ->>HEADER<<- opcode: QUERY\s|QUERY, status: NOERRO +R, .*/) { $error = 1; next; } next unless /$fqdn\.\s+(\w+)(\s+A|\s+IN\sA)\s+(.*)/; $error_a = 1; my $time = lc($1); my $ip = $3; my $seconds = $time =~ /[dhms]/ ? string_to_time($time) : +$time; my $extended_time = time_to_string($seconds); print "Request: $fqdn\tTTL: $extended_time\tIP: $ip\n" if +$verbose; push @data_out, "$ldns\t$fqdn\t$seconds\t$ip\n" if $outfil +e; } close DIG; if (!$error) { print "Request: $fqdn\tERROR (No domain found)\n" if $verbose; push @data_out, "$ldns\t$fqdn\tERROR\tNO DOMAIN\n" if $outfile +; } elsif (!$error_a) { print "Request: $fqdn\tERROR (Domain found, no A record found) +\n" if $verbose; push @data_out, "$ldns\t$fqdn\tERROR\tNOT A RECORD\n" if $outf +ile; } }

    As you can see, the code is tighter and easier to read. But, we now must add a test for @data_out.

    if (@data_out) { open (DATAOUT, ">> $outfile") || die "can't open $outfile: $!"; print DATAOUT @data_out; close DATAOUT; }

    This can be rewritten by taken advantage of the x operator.

    foreach $thing (@ns){ push (@provide, "Unknown"); }
    push @provide, ('Unknown') x @ns;

    And, finally, all those ifs in the beginning could be combined.

    if ( $help || !@ns && !$nsfile || !@addr && !$addrfile || !$verbose && !$outfile ) { print <<END; . . .



    HTH,
    Charles K. Clarkson
      Outstanding! Thank you. I gave you credit in the copy of the code I have here. This helped me learn a lot.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://125625]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (3)
As of 2024-06-21 03:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.