从Perl中的IP地址获取所有主机名

时间:2011-04-15 21:12:40

标签: perl

我正在尝试找到一种方法来获取解析为IP地址的所有主机名。

gethostbyaddr函数似乎只从DNS中检索第一条记录(无论它是在标量还是列表上下文中)。

示例:

my $hostname = gethostbyaddr(inet_aton($ip_to_check), AF_INET);
$print($hostname); //output: joe.example.com

my @hostnames = gethostbyaddr(inet_aton($ip_to_check), AF_INET);
foreach my $hostname (@hostnames){
 print "(", join(',',@hostnames), ")"; //output: (joe.example.com,,2,4,?)
}

从终端:

$ host 192.168.1.5
5.1.168.192.in-addr.arpa domain name pointer joe.example.com.
5.1.168.192.in-addr.arpa domain name pointer john.example.com.

我听说Net :: DNS有点强大,但我也没有运气来获取所有条目。

5 个答案:

答案 0 :(得分:3)

我在这里和其他地方使用了堆栈溢出的答案组合来找到我正在寻找的答案。

# create new Resolver Object
my $res = Net::DNS::Resolver->new;

# change IP from 192.168.1.15 to 15.1.168.192.in-addr.arpa for searching
my $target_IP = join('.', reverse split(/\./, $ip_to_check)).".in-addr.arpa";

# query DNS
my $query = $res->query("$target_IP", "PTR");

# if a result is found
if ($query){
    print("Resolves to:\n");

    # for every result, print the IP address
    foreach my $rr ($query->answer){
        # show all unless the type is PTR (pointer to a canonical name)
        next unless $rr->type eq "PTR";

        # remove the period at the end
        printf(substr($rr->rdatastr, 0, -1));
    }
}

答案 1 :(得分:2)

gethostby...接口非常陈旧且笨重,在Perl获得对OO的引用和预扩展之前,在原始时间定义。并且它不会像您尝试使用它一样工作。在列表上下文中使用时,它将主要名称作为第一个元素返回,并将空格分隔的(!)别名列表作为第二个:

my ($hostname, $aliases) = gethostbyaddr($addr, AF_INET);
my @hostname = ($hostname, split ' ', $aliases);
say join ' ', @hostname;

现在这就是理论;我没有找到任何有多个PTR记录的IP地址,所以我无法测试gethostbyaddr是否会实际返回它们 - 它可能还取决于你的底层C运行时 - 但它确实有用例如,将gethostbynameCNAME d名称一起使用。

答案 2 :(得分:2)

这是一个小程序,用于在执行滥用跟踪任务时查找网络掩码的所有PTR记录(例如192.0.2.0/28)。它每秒最多发送15个查询,当它们全部发送时,然后开始读取响应(因此需要一些工作才能正常运行更大的网络块)。

#!/usr/bin/env perl
use strict;
use warnings;

use Net::Netmask;
use Net::DNS;

@ARGV or die "$0 ip/cidr\n";

my $block = Net::Netmask->new(shift);

my $res = Net::DNS::Resolver->new;

my %sockets;

my $i = 0;
for my $i (1 .. $block->size - 1) {
    my $ip = $block->nth($i);

    my $reverse_ip = join ".", reverse split m/\./, $ip;
    $reverse_ip .= ".in-addr.arpa";

    #print "$ip\n";

    my $bgsock = $res->bgsend($reverse_ip, 'PTR');
    $sockets{$ip} = $bgsock;

    sleep 1 unless $i % 15;
}

$i = 0;
for my $i (1 .. $block->size - 1) {

    my $ip = $block->nth($i);

    my $socket = $sockets{$ip};
    my $wait   = 0;
    until ($res->bgisready($socket)) {
        print "waiting for $ip\n" if $wait > 0;
        sleep 1 + $wait;
        $wait++;
    }
    my $packet = $res->bgread($socket);
    my @rr     = $packet->answer;

    printf "%-15s %s\n", $ip, $res->errorstring
      unless @rr;

    for my $rr (@rr) {
        printf "%-15s %s\n", $ip, $rr->string;
    }
}

答案 3 :(得分:1)

我认为这不是一个结构良好的问题陈述。在一般情况下,有几乎无限数量的DNS名称可以解析为任何IP地址,即使持有该地址的一方不知道也是如此。反向查找从根本上说是不可靠的,并且无法回答海报想要的问题,因为IP的所有名称都不需要在可见的反向映射中。

第一个答案,列举了反向地图,是最好的答案,但它会遗漏任何尚未在地图中输入的名称。

答案 4 :(得分:0)

这就是我用过的:

sub getauthoritivename
    {
    my ($printerdns)=@_;
    my $res = Net::DNS::Resolver->new(searchlist=>$config->{searchlist});

    my $query = $res->search($printerdns);
    if ($query) 
        {
        foreach my $rr ($query->answer) 
            {
            next unless $rr->type eq "A";
            print $rr->name;
            }
        } 
    else
        {
        warn "query failed: ", $res->errorstring, "\n";
        return 0;
        }
    }

只要$ rr->名称找到名称,就会不断添加它们。