AnyEvent

 view release on metacpan or  search on metacpan

lib/AnyEvent/DNS.pm  view on Meta::CPAN

      if $AnyEvent::PROTOCOL{ipv6} > $AnyEvent::PROTOCOL{ipv4};

   @DNS_FALLBACK = (@$ipv4, @$ipv6);
}

=item AnyEvent::DNS::a $domain, $cb->(@addrs)

Tries to resolve the given domain to IPv4 address(es).

=item AnyEvent::DNS::aaaa $domain, $cb->(@addrs)

Tries to resolve the given domain to IPv6 address(es).

=item AnyEvent::DNS::mx $domain, $cb->(@hostnames)

Tries to resolve the given domain into a sorted (lower preference value
first) list of domain names.

=item AnyEvent::DNS::ns $domain, $cb->(@hostnames)

Tries to resolve the given domain name into a list of name servers.

=item AnyEvent::DNS::txt $domain, $cb->(@hostnames)

Tries to resolve the given domain name into a list of text records. Only
the first text string per record will be returned. If you want all
strings, you need to call the resolver manually:

   resolver->resolve ($domain => "txt", sub {
      for my $record (@_) {
         my (undef, undef, undef, @txt) = @$record;
         # strings now in @txt
      }
   });

=item AnyEvent::DNS::srv $service, $proto, $domain, $cb->(@srv_rr)

Tries to resolve the given service, protocol and domain name into a list
of service records.

Each C<$srv_rr> is an array reference with the following contents:
C<[$priority, $weight, $transport, $target]>.

They will be sorted with lowest priority first, then randomly
distributed by weight as per RFC 2782.

Example:

   AnyEvent::DNS::srv "sip", "udp", "schmorp.de", sub { ...
   # @_ = ( [10, 10, 5060, "sip1.schmorp.de" ] )

=item AnyEvent::DNS::any $domain, $cb->(@rrs)

Tries to resolve the given domain and passes all resource records found
to the callback. Note that this uses a DNS C<ANY> query, which, as of RFC
8482, are officially deprecated.

=item AnyEvent::DNS::ptr $domain, $cb->(@hostnames)

Tries to make a PTR lookup on the given domain. See C<reverse_lookup>
and C<reverse_verify> if you want to resolve an IP address to a hostname
instead.

=item AnyEvent::DNS::reverse_lookup $ipv4_or_6, $cb->(@hostnames)

Tries to reverse-resolve the given IPv4 or IPv6 address (in textual form)
into its hostname(s). Handles V4MAPPED and V4COMPAT IPv6 addresses
transparently.

=item AnyEvent::DNS::reverse_verify $ipv4_or_6, $cb->(@hostnames)

The same as C<reverse_lookup>, but does forward-lookups to verify that
the resolved hostnames indeed point to the address, which makes spoofing
harder.

If you want to resolve an address into a hostname, this is the preferred
method: The DNS records could still change, but at least this function
verified that the hostname, at one point in the past, pointed at the IP
address you originally resolved.

Example:

   AnyEvent::DNS::reverse_verify "2001:500:2f::f", sub { print shift };
   # => f.root-servers.net

=cut

sub MAX_PKT() { 4096 } # max packet size we advertise and accept

sub DOMAIN_PORT() { 53 } # if this changes drop me a note

sub resolver ();

sub a($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "a", sub {
      $cb->(map $_->[4], @_);
   });
}

sub aaaa($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "aaaa", sub {
      $cb->(map $_->[4], @_);
   });
}

sub mx($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "mx", sub {
      $cb->(map $_->[5], sort { $a->[4] <=> $b->[4] } @_);
   });
}

sub ns($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "ns", sub {
      $cb->(map $_->[4], @_);
   });
}

sub txt($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "txt", sub {
      $cb->(map $_->[4], @_);
   });
}

sub srv($$$$) {
   my ($service, $proto, $domain, $cb) = @_;

   # todo, ask for any and check glue records
   resolver->resolve ("_$service._$proto.$domain" => "srv", sub {
      my @res;

      # classify by priority
      my %pri;
      push @{ $pri{$_->[4]} }, [ @$_[4,5,6,7] ]

lib/AnyEvent/DNS.pm  view on Meta::CPAN

            }
         }
      }

      $cb->(@res);
   });
}

sub ptr($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "ptr", sub {
      $cb->(map $_->[4], @_);
   });
}

sub any($$) {
   my ($domain, $cb) = @_;

   resolver->resolve ($domain => "*", $cb);
}

# convert textual ip address into reverse lookup form
sub _munge_ptr($) {
   my $ipn = $_[0]
      or return;

   my $ptr;

   my $af = AnyEvent::Socket::address_family ($ipn);

   if ($af == AF_INET6) {
      $ipn = substr $ipn, 0, 16; # anticipate future expansion

      # handle v4mapped and v4compat
      if ($ipn =~ s/^\x00{10}(?:\xff\xff|\x00\x00)//) {
         $af = AF_INET;
      } else {
         $ptr = join ".", (reverse split //, unpack "H32", $ipn), "ip6.arpa.";
      }
   }

   if ($af == AF_INET) {
      $ptr = join ".", (reverse unpack "C4", $ipn), "in-addr.arpa.";
   }

   $ptr
}

sub reverse_lookup($$) {
   my ($ip, $cb) = @_;

   $ip = _munge_ptr AnyEvent::Socket::parse_address ($ip)
      or return $cb->();

   resolver->resolve ($ip => "ptr", sub {
      $cb->(map $_->[4], @_);
   });
}

sub reverse_verify($$) {
   my ($ip, $cb) = @_;
   
   my $ipn = AnyEvent::Socket::parse_address ($ip)
      or return $cb->();

   my $af = AnyEvent::Socket::address_family ($ipn);

   my @res;
   my $cnt;

   my $ptr = _munge_ptr $ipn
      or return $cb->();

   $ip = AnyEvent::Socket::format_address ($ipn); # normalise into the same form

   ptr $ptr, sub {
      for my $name (@_) {
         ++$cnt;
         
         # () around AF_INET to work around bug in 5.8
         resolver->resolve ("$name." => ($af == (AF_INET) ? "a" : "aaaa"), sub {
            for (@_) {
               push @res, $name
                  if $_->[4] eq $ip;
            }
            $cb->(@res) unless --$cnt;
         });
      }

      $cb->() unless $cnt;
   };
}

#################################################################################

=back

=head2 LOW-LEVEL DNS EN-/DECODING FUNCTIONS

=over 4

=item $AnyEvent::DNS::EDNS0

This variable decides whether dns_pack automatically enables EDNS0
support. By default, this is disabled (C<0>), unless overridden by
C<$ENV{PERL_ANYEVENT_EDNS0}>, but when set to C<1>, AnyEvent::DNS will use
EDNS0 in all requests.

=cut

our $EDNS0 = $ENV{PERL_ANYEVENT_EDNS0}*1; # set to 1 to enable (partial) edns0

our %opcode_id = (
   query  => 0,
   iquery => 1,
   status => 2,
   notify => 4,
   update => 5,
   map +($_ => $_), 3, 6..15
);



( run in 0.509 second using v1.01-cache-2.11-cpan-13bb782fe5a )