Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Retrieving all hostnames for an IP address...

by RMaxwell (Novice)
on Dec 12, 2006 at 23:39 UTC ( #589454=perlquestion: print w/ replies, xml ) Need Help??
RMaxwell has asked for the wisdom of the Perl Monks concerning the following question:

Question, What is a good efficient way to retrieve from DNS all known hostnames for an IP address? Currently using an external call to host.exe from the dig support files for windows, but with over 1500 address to go through, running into cygwin errors because of execution speed.

This is to try to resolve a network monitoring application's issue with Windows DNS while running on WIndows.

Thanks,
RMaxwell

Update: I realized this morning that I may not have been as clear as needed. I need to retrieve all A records for a given IP address. I currently have IP address that have a maximum of four A records per IP addresses. Thanks for all of your help!

Comment on Retrieving all hostnames for an IP address...
Re: Retrieving all hostnames for an IP address...
by Fletch (Chancellor) on Dec 12, 2006 at 23:53 UTC

    Look at Net::DNS as that should have less overhead than using system or backticks, but keep in mind that your problem (at least as phrased) is unsolvable.

    There is one and only one PTR record for a given IP; there can be an unlimited number of A records which all resolve to the same IP (not to mention CNAME aliases). There's no way to get anything other than the PTR address from DNS. If you've got a list of hostnames you could build a mapping on your own, but it's only going to be complete as your list of hostnames.

      There is one and only one PTR record for a given IP

      Not on this planet.

      use strict; use Socket; my $addr = shift || '172.17.0.1'; my ($name,$aliases) = gethostbyaddr(inet_aton($addr), AF_INET); print "address $addr has the following names:\n"; print "\t$_\n" for ($name, split / /, $aliases);

      When run against my DNS server, produces:

      address 172.17.0.1 has the following names: host1.example.com host2.example.com host3.example.com host4.example.com host5.example.com

      In other words, a PTR lookup can return a result set of more than one record. Many buggy applications make the invalid assumption that no more than one result will be returned. But of course, no Perlmonk ever would :)

      gethostbyaddr is a bit naughty by referring to one as the name, and the others, aliases. According the the RFC (if I remember correctly, it's been a while), they are all equally "at the same level". It's up to the application to sift through them and find the one that suits its needs.

      • another intruder with the mooring in the heart of the Perl

        Technically yes DNS allows multiple PTR RRs to be returned for a single query. However the General Consensus from the DNS types (search an archive of comp.protocols.dns.bind, for example here or here; look enough and you'll see threats to put together a "Best Practices" comdemnation of it) is still that you shouldn't do that because pretty much everything is written with the expectation that PTRs map to a single A record. There's also the problem that it's possible (with a sufficiently hostname-ful IP) to have more PTR RRs than can be returned in a single UDP packet. And I can't say that I've personally ever seen it happen in the wild in 15+ years of varying degrees of sysadmining.

        Sure, you can do it; you can also use a pickaxe to poke speed holes in your car's hood. Neither of them really are going to be of much practical benefit.

      I agree with you that Net::DNS is the way to go, but I also agree with the poster above that there's, many times, more than one PTR. Also, it would seem the parent poster is looking for PTR records, not A records. I sometimes lookup the A records for a PTR to see if they match...

      UPDATE: After reading the update to the question I deleted much of this post and put this instead. It might even be what the asker wants, or close to it...

      use strict; use Net::DNS; my $res = new Net::DNS::Resolver; for my $rr ($res->axfr('domain.name')) { next unless $rr->type eq "A"; my $host = $rr->name; my $ip = $rr->address; next unless $ip eq "ip.ip.ip.ip"; print "$host\n"; }
Re: Retrieving all hostnames for an IP address...
by roboticus (Canon) on Dec 12, 2006 at 23:58 UTC
    RMaxwell:

    Try having your app write a script to feed to nslookup, then parse the answers. That way it should be quick only one invocation of nslookup. A sample nslookup run:

    root@swill ~ $ nslookup *** Can't find server name for address 192.168.0.1: Non-existent domai +n *** Default servers are not available Default Server: UnKnown Address: 192.168.0.1 > set q=A > 216.24.27.80 Server: UnKnown Address: 192.168.0.1 Name: win.net Address: 216.24.27.80 > 216.24.27.81 Server: UnKnown Address: 192.168.0.1 Name: mail.digicove.com Address: 216.24.27.81 >
    It seems to be a simple task to parse out the Name:/Address: pairs.....

    --roboticus

Re: Retrieving all hostnames for an IP address...
by NetWallah (Abbot) on Dec 13, 2006 at 05:40 UTC
    If you parse the output of the following command-line, you can obtain a list of all domain records.

    You will need to provide 2 pieces of info - the domain name, and the name or address of the DNS server :

    echo ls -d YourDomainName.com | nslookup - Your.dns.server

         "A closed mouth gathers no feet." --Unknown

      Thanks, this solution seems to be working the best. It's dirty and not much in perl, but HPOV NNM will be happy now with a hosts file and noiplookup, instead of having issues with Windows DNS.

      Thanks,
      RMaxwell
Re: Retrieving all hostnames for an IP address...
by idsfa (Vicar) on Dec 13, 2006 at 15:47 UTC
    use Socket; for my $ipnum (@list) { my $iaddr = inet_aton($ipnum); my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($iaddr +, AF_INET); print "$ipnum -> $name,$aliases\n"; }

    The intelligent reader will judge for himself. Without examining the facts fully and fairly, there is no way of knowing whether vox populi is really vox dei, or merely vox asinorum. — Cyrus H. Gordon
Re: Retrieving all hostnames for an IP address...
by MidLifeXis (Prior) on Dec 13, 2006 at 19:11 UTC

    Update: Would someone mind explaining why I have a negative rating on this node? Is it factually inacurate? Was my tone inappropriate? Perhaps I didn't say it correctly. If there are factual issues with this node, then I would like to be educated on them. Otherwise, I will chalk it up to bad coffee on the part of the voter or some such trivia. -thx

    IIRC, unless the all of the reverse address pointers (PTR record) are set up for the host, you may not be able to do this. For example, you can have a host that you can find the IP address for giving it a name, but that name will never be found by looking for the IP address.

    Think, for example, of a host on a DSL line that has a dynamic DNS entry. Your ISP doesn't know about the dynamic DNS entry, but it "owns" the PTR record for your IP address.

    However, if all of the addresses are under your control, then refer to the other nodes on this thread.

    --MidLifeXis

Re: Retrieving all hostnames for an IP address...
by RMaxwell (Novice) on Mar 22, 2007 at 16:36 UTC
    Perl Monks, I resolved my issue, and here's what I did to get the data I needed:
    use strict; # Performs strict error checking throughout th +e program use POSIX; # Loads the POSIX module for standardized C fu +nctions use NET::Ping; # Loads the Net::Ping module for ICMP/UDP/TCP +Pinging use Socket; # Loads the Socket module for Socket level com +munications . . . sub Retest_Name { &writelog("Beginning Name to IP Address Retests"); foreach (@Nlist) { my $hst = $_; my $res; if ($res = gethostbyname($hst)) { my $ip = inet_ntoa($res); push @GNaddr, "$hst|DNS - $ip\n"; } else { push @BNaddr, "$hst|Name doesn't resolve to an IP $!\n"; } } &writelog("Completed Name to IP Address Retests"); } sub Retest_IP { &writelog("Beginning IP to Name Address Retests"); open CF, "<", $cfile or &writelog("Unable to open $cfile for readi +ng!!!") and die; my @CFlist = (); # The below while statement reads in and processes the data in the + ipNoLookup.conf # and places the data into an array. while (<CF>) { my $in = chomp $_; my ($ip, $junk) = split(/\t/, $in); my ($ip1, $ip2, $ip3, $ip4) = split(/./, $ip); my ($sip1, $sip2); undef $ip; if ($ip4 =~ /([0-9]+\-[0-9]+)/) { ($sip1, $sip2) = split(/\-/, $ip4); while ($sip1 != $sip2) { $ip = join (".", $ip1, $ip2, $ip3, $sip1); push @CFlist, $ip; undef $ip; $sip1++; } $ip = join (".", $ip1, $ip2, $ip3, $sip2); push @CFlist, $ip; undef $ip; } else { $ip = join (".", $ip1, $ip2, $ip3, $ip4); push @CFlist, $ip; undef $ip; } } # The foreach routine compares the IPs received from the trace fil +es against the # array generated from the ipNoLookup.conf in use on the system, a +nd eliminates # any matches. my $IPidx = 0; foreach (@IPlist) { my $hst = chomp $_; foreach (@CFlist) { my $chst = chomp $_; if ($hst eq $chst) { delete $IPlist[$IPidx]; } } $IPidx++; } # The foreach routine reads each line from the @IPlist array and r +eprocesses it foreach (@IPlist) { my $hst = $_; my $iaddr = inet_aton($hst); ($name,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($iad +dr, AF_INET); if (length ($name) == 0 || $name =~ /[various|hostnames|totest +from]\.internal\.domain\.name/) { my $p = Net::Ping->new(); if ($p->ping($hst)) { $ires = "ICMP Responded"; } else { $ires = "No ICMP Response"; } $p->close(); undef $p; $p = Net::Ping->new("tcp", 2); $p->{port_num} = getservbyname("http", "tcp"); $p->service_check(1); my $res = $p->ping($hst); if ($res == 1) { $hres = "HTTP Responded"; } else { $hres = "No HTTP Response"; } $p->close(); undef $p; undef $res; $p = Net::Ping->new("tcp", 2); $p->{port_num} = getservbyname("telnet", "tcp"); $p->service_check(1); $res = $p->ping($hst); if ($res == 1) { $tres = "Telnet Responded"; } else { $tres = "No Telnet Response"; } $p->close(); undef $p; undef $res; push @BIaddr, "$hst|$ires, $hres, $tres\n"; undef $hst; undef $ires; undef $hres; undef $tres; } else { $name = $name . " " . $aliases; push @GIaddr, "$hst|DNS - $name\n"; undef $hst; undef $name; } } &writelog("Completed IP to Name Address Retests"); }
    Any questions on the above code, please feel free to ask. Thanks again, RMaxwell

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://589454]
Approved by Joost
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2014-07-13 07:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (248 votes), past polls