#!/usr/bin/perl -w #------------------------------------------------------------------------------ # Usage: mresolv2 [ -t timeout ] [ file... ] # # Reads IP addresses and issues non-blocking DNS queries. Answers are # sent to standard output in RR format: # # 1.1.168.192.in-addr.arpa. 86400 IN PTR host1.example.com. # # 1.2.168.192.in-addr.arpa. 86400 IN CNAME 1.0-16.2.168.192.in-addr.arpa. # 1.0-16.2.168.192.in-addr.arpa. 86400 IN PTR host2.example.com. # # Michael Fuhr # mike@fuhr.org # # Copyright (c) 1999-2000 Michael Fuhr. All rights reserved. This program # is free software; you can redistribute it and/or modify it under the same # terms as Perl itself. # # $Id: mresolv2,v 1.3 2000/11/24 17:14:40 mfuhr Exp mfuhr $ #------------------------------------------------------------------------------ use IO::Socket; use IO::Select; use Net::DNS; use Getopt::Std; use strict; use constant DEFAULT_TIMEOUT => 30; use constant DEFAULT_NAMESERVER => "127.0.0.1"; use constant DEFAULT_PORT => 53; use constant DEFAULT_SRCADDR => "0.0.0.0"; use constant DEFAULT_SRCPORT => 0; $| = 1; #------------------------------------------------------------------------------ # Get the timeout or use a reasonable default. #------------------------------------------------------------------------------ my $progname = $0; $progname =~ s!.*/!!; my %opt; getopts("t:", \%opt); my $timeout = defined($opt{"t"}) ? $opt{"t"} : DEFAULT_TIMEOUT; die "$progname: invalid timeout: $timeout\n" if $timeout < 0; #------------------------------------------------------------------------------ # Create a socket pointing at the default nameserver. #------------------------------------------------------------------------------ my $sock = IO::Socket::INET->new(Proto => "udp"); die "couldn't create socket: $!" unless $sock; my $sockaddr_src = sockaddr_in(DEFAULT_SRCPORT, inet_aton(DEFAULT_SRCADDR)); $sock->bind($sockaddr_src) or die "can't bind socket: $!"; my $res = Net::DNS::Resolver->new; my $ns = $res->nameservers ? ($res->nameservers)[0] : DEFAULT_NAMESERVER; my $sockaddr_dst = sockaddr_in(DEFAULT_PORT, inet_aton($ns)); my $sel = IO::Select->new; $sel->add($sock); #------------------------------------------------------------------------------ # Read IP addresses and send queries. #------------------------------------------------------------------------------ my $pending = 0; while (<>) { chomp; next unless /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; my $ip = "$4.$3.$2.$1.in-addr.arpa"; my $packet = Net::DNS::Packet->new($ip, "PTR"); $sock->send($packet->data, 0, $sockaddr_dst) or die "send: $ip: $!"; ++$pending; while ($sel->can_read(0)) { --$pending; my $buf = ""; $sock->recv($buf, 512) or die "recv: $!"; next unless $buf; my $ans = Net::DNS::Packet->new(\$buf); next unless $ans; foreach my $rr ($ans->answer) { $rr->print; if ($rr->type eq "CNAME") { my $cname = $rr->cname; my $packet = Net::DNS::Packet->new($cname, "PTR"); $sock->send($packet->data, 0, $sockaddr_dst) or die "send: $cname: $!"; ++$pending; } } } } #------------------------------------------------------------------------------ # Wait for outstanding requests until all are complete or we've timed out. #------------------------------------------------------------------------------ while ($pending > 0 && $sel->can_read($timeout)) { --$pending; my $buf = ""; $sock->recv($buf, 512) or die "recv: $!"; next unless $buf; my $ans = Net::DNS::Packet->new(\$buf); next unless $ans; foreach my $rr ($ans->answer) { $rr->print; if ($rr->type eq "CNAME") { my $cname = $rr->cname; my $packet = Net::DNS::Packet->new($cname, "PTR"); $sock->send($packet->data, 0, $sockaddr_dst) or die "send: $cname: $!"; ++$pending; } } }