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!
Re: Retrieving all hostnames for an IP address...
by Fletch (Bishop) 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.
| [reply] |
|
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
| [reply] [d/l] [select] |
|
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.
| [reply] |
|
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";
}
| [reply] [d/l] |
Re: Retrieving all hostnames for an IP address...
by roboticus (Chancellor) 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 | [reply] [d/l] |
Re: Retrieving all hostnames for an IP address...
by NetWallah (Canon) 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
| [reply] [d/l] |
|
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
| [reply] |
Re: Retrieving all hostnames for an IP address...
by MidLifeXis (Monsignor) 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.
| [reply] |
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
| [reply] [d/l] |
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 | [reply] [d/l] |
|
|