ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.35
Committed: Mon May 26 06:18:53 2008 UTC (16 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-4_05
Changes since 1.34: +2 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::DNS - fully asynchronous DNS resolution
4    
5     =head1 SYNOPSIS
6    
7     use AnyEvent::DNS;
8    
9 root 1.26 my $cv = AnyEvent->condvar;
10 root 1.30 AnyEvent::DNS::a "www.google.de", $cv;
11 root 1.26 # ... later
12     my @addrs = $cv->recv;
13    
14 root 1.1 =head1 DESCRIPTION
15    
16     This module offers both a number of DNS convenience functions as well
17     as a fully asynchronous and high-performance pure-perl stub resolver.
18    
19 root 1.12 The stub resolver supports DNS over UDP, optional EDNS0 support for up to
20     4kiB datagrams and automatically falls back to virtual circuit mode for
21     large responses.
22    
23 root 1.1 =head2 CONVENIENCE FUNCTIONS
24    
25     =over 4
26    
27     =cut
28    
29     package AnyEvent::DNS;
30    
31 root 1.3 no warnings;
32 root 1.1 use strict;
33    
34 root 1.29 use Socket qw(AF_INET SOCK_DGRAM SOCK_STREAM);
35    
36 root 1.35 use AnyEvent ();
37 root 1.6 use AnyEvent::Handle ();
38 root 1.1
39 root 1.32 our @DNS_FALLBACK = (v208.67.220.220, v208.67.222.222);
40    
41 root 1.18 =item AnyEvent::DNS::addr $node, $service, $proto, $family, $type, $cb->([$family, $type, $proto, $sockaddr], ...)
42 root 1.4
43 root 1.18 Tries to resolve the given nodename and service name into protocol families
44     and sockaddr structures usable to connect to this node and service in a
45     protocol-independent way. It works remotely similar to the getaddrinfo
46     posix function.
47    
48     C<$node> is either an IPv4 or IPv6 address or a hostname, C<$service> is
49     either a service name (port name from F</etc/services>) or a numerical
50     port number. If both C<$node> and C<$service> are names, then SRV records
51     will be consulted to find the real service, otherwise they will be
52     used as-is. If you know that the service name is not in your services
53 root 1.24 database, then you can specify the service in the format C<name=port>
54 root 1.18 (e.g. C<http=80>).
55    
56     C<$proto> must be a protocol name, currently C<tcp>, C<udp> or
57     C<sctp>. The default is C<tcp>.
58    
59 root 1.24 C<$family> must be either C<0> (meaning any protocol is OK), C<4> (use
60 root 1.20 only IPv4) or C<6> (use only IPv6). This setting might be influenced by
61     C<$ENV{PERL_ANYEVENT_PROTOCOLS}>.
62 root 1.18
63     C<$type> must be C<SOCK_STREAM>, C<SOCK_DGRAM> or C<SOCK_SEQPACKET> (or
64     C<undef> in which case it gets automatically chosen).
65    
66     The callback will receive zero or more array references that contain
67     C<$family, $type, $proto> for use in C<socket> and a binary
68     C<$sockaddr> for use in C<connect> (or C<bind>).
69    
70     The application should try these in the order given.
71 root 1.4
72     Example:
73    
74 root 1.18 AnyEvent::DNS::addr "google.com", "http", 0, undef, undef, sub { ... };
75 root 1.4
76     =item AnyEvent::DNS::a $domain, $cb->(@addrs)
77    
78     Tries to resolve the given domain to IPv4 address(es).
79    
80 root 1.17 =item AnyEvent::DNS::aaaa $domain, $cb->(@addrs)
81    
82     Tries to resolve the given domain to IPv6 address(es).
83    
84 root 1.4 =item AnyEvent::DNS::mx $domain, $cb->(@hostnames)
85    
86     Tries to resolve the given domain into a sorted (lower preference value
87     first) list of domain names.
88    
89     =item AnyEvent::DNS::ns $domain, $cb->(@hostnames)
90    
91     Tries to resolve the given domain name into a list of name servers.
92    
93     =item AnyEvent::DNS::txt $domain, $cb->(@hostnames)
94    
95     Tries to resolve the given domain name into a list of text records.
96    
97     =item AnyEvent::DNS::srv $service, $proto, $domain, $cb->(@srv_rr)
98    
99     Tries to resolve the given service, protocol and domain name into a list
100     of service records.
101    
102 root 1.24 Each srv_rr is an array reference with the following contents:
103 root 1.4 C<[$priority, $weight, $transport, $target]>.
104    
105     They will be sorted with lowest priority, highest weight first (TODO:
106 root 1.24 should use the RFC algorithm to reorder same-priority records for weight).
107 root 1.4
108     Example:
109    
110     AnyEvent::DNS::srv "sip", "udp", "schmorp.de", sub { ...
111     # @_ = ( [10, 10, 5060, "sip1.schmorp.de" ] )
112    
113     =item AnyEvent::DNS::ptr $ipv4_or_6, $cb->(@hostnames)
114    
115     Tries to reverse-resolve the given IPv4 or IPv6 address (in textual form)
116     into it's hostname(s).
117    
118     Example:
119    
120     AnyEvent::DNS::ptr "2001:500:2f::f", sub { print shift };
121     # => f.root-servers.net
122    
123 root 1.5 =item AnyEvent::DNS::any $domain, $cb->(@rrs)
124    
125     Tries to resolve the given domain and passes all resource records found to
126     the callback.
127    
128 root 1.4 =cut
129    
130     sub resolver;
131    
132     sub a($$) {
133     my ($domain, $cb) = @_;
134    
135     resolver->resolve ($domain => "a", sub {
136     $cb->(map $_->[3], @_);
137     });
138     }
139    
140 root 1.17 sub aaaa($$) {
141     my ($domain, $cb) = @_;
142    
143     resolver->resolve ($domain => "aaaa", sub {
144     $cb->(map $_->[3], @_);
145     });
146     }
147    
148 root 1.4 sub mx($$) {
149     my ($domain, $cb) = @_;
150    
151     resolver->resolve ($domain => "mx", sub {
152     $cb->(map $_->[4], sort { $a->[3] <=> $b->[3] } @_);
153     });
154     }
155    
156     sub ns($$) {
157     my ($domain, $cb) = @_;
158    
159     resolver->resolve ($domain => "ns", sub {
160     $cb->(map $_->[3], @_);
161     });
162     }
163    
164     sub txt($$) {
165     my ($domain, $cb) = @_;
166    
167     resolver->resolve ($domain => "txt", sub {
168     $cb->(map $_->[3], @_);
169     });
170     }
171    
172     sub srv($$$$) {
173     my ($service, $proto, $domain, $cb) = @_;
174    
175     # todo, ask for any and check glue records
176     resolver->resolve ("_$service._$proto.$domain" => "srv", sub {
177     $cb->(map [@$_[3,4,5,6]], sort { $a->[3] <=> $b->[3] || $b->[4] <=> $a->[4] } @_);
178     });
179     }
180    
181     sub ptr($$) {
182     my ($ip, $cb) = @_;
183    
184 root 1.17 $ip = AnyEvent::Socket::parse_ip ($ip)
185     or return $cb->();
186 root 1.4
187 root 1.17 if (4 == length $ip) {
188     $ip = join ".", (reverse split /\./, $ip), "in-addr.arpa.";
189 root 1.4 } else {
190 root 1.17 $ip = join ".", (reverse split //, unpack "H*", $ip), "ip6.arpa.";
191 root 1.4 }
192    
193 root 1.17 resolver->resolve ($ip => "ptr", sub {
194 root 1.4 $cb->(map $_->[3], @_);
195     });
196     }
197 root 1.1
198 root 1.5 sub any($$) {
199     my ($domain, $cb) = @_;
200    
201     resolver->resolve ($domain => "*", $cb);
202     }
203    
204 root 1.18 #############################################################################
205    
206     sub addr($$$$$$) {
207     my ($node, $service, $proto, $family, $type, $cb) = @_;
208    
209 root 1.28 unless (&AnyEvent::Util::AF_INET6) {
210 root 1.18 $family != 6
211     or return $cb->();
212 root 1.19
213     $family ||= 4;
214 root 1.18 }
215    
216 root 1.20 $cb->() if $family == 4 && !$AnyEvent::PROTOCOL{ipv4};
217     $cb->() if $family == 6 && !$AnyEvent::PROTOCOL{ipv6};
218    
219     $family ||=4 unless $AnyEvent::PROTOCOL{ipv6};
220     $family ||=6 unless $AnyEvent::PROTOCOL{ipv4};
221    
222 root 1.18 $proto ||= "tcp";
223 root 1.29 $type ||= $proto eq "udp" ? SOCK_DGRAM : SOCK_STREAM;
224 root 1.18
225     my $proton = (getprotobyname $proto)[2]
226     or Carp::croak "$proto: protocol unknown";
227    
228     my $port;
229    
230     if ($service =~ /^(\S+)=(\d+)$/) {
231     ($service, $port) = ($1, $2);
232     } elsif ($service =~ /^\d+$/) {
233     ($service, $port) = (undef, $service);
234     } else {
235     $port = (getservbyname $service, $proto)[2]
236     or Carp::croak "$service/$proto: service unknown";
237     }
238    
239     my @target = [$node, $port];
240    
241     # resolve a records / provide sockaddr structures
242     my $resolve = sub {
243     my @res;
244     my $cv = AnyEvent->condvar (cb => sub {
245 root 1.21 $cb->(
246 root 1.25 map $_->[2],
247 root 1.21 sort {
248 root 1.31 $AnyEvent::PROTOCOL{$b->[1]} <=> $AnyEvent::PROTOCOL{$a->[1]}
249 root 1.21 or $a->[0] <=> $b->[0]
250     }
251     @res
252     )
253 root 1.18 });
254    
255     $cv->begin;
256     for my $idx (0 .. $#target) {
257     my ($node, $port) = @{ $target[$idx] };
258    
259     if (my $noden = AnyEvent::Socket::parse_ip ($node)) {
260     if (4 == length $noden && $family != 6) {
261 root 1.29 push @res, [$idx, "ipv4", [AF_INET, $type, $proton,
262 root 1.21 AnyEvent::Socket::pack_sockaddr ($port, $noden)]]
263 root 1.18 }
264    
265     if (16 == length $noden && $family != 4) {
266 root 1.28 push @res, [$idx, "ipv6", [&AnyEvent::Util::AF_INET6, $type, $proton,
267 root 1.21 AnyEvent::Socket::pack_sockaddr ( $port, $noden)]]
268 root 1.18 }
269     } else {
270     # ipv4
271     if ($family != 6) {
272     $cv->begin;
273     a $node, sub {
274 root 1.29 push @res, [$idx, "ipv4", [AF_INET, $type, $proton,
275 root 1.21 AnyEvent::Socket::pack_sockaddr ($port, AnyEvent::Socket::parse_ipv4 ($_))]]
276 root 1.18 for @_;
277     $cv->end;
278     };
279     }
280    
281     # ipv6
282     if ($family != 4) {
283     $cv->begin;
284     aaaa $node, sub {
285 root 1.25 push @res, [$idx, "ipv6", [&AnyEvent::Socket::AF_INET6, $type, $proton,
286 root 1.21 AnyEvent::Socket::pack_sockaddr ($port, AnyEvent::Socket::parse_ipv6 ($_))]]
287 root 1.18 for @_;
288     $cv->end;
289     };
290     }
291     }
292     }
293     $cv->end;
294     };
295    
296     # try srv records, if applicable
297 root 1.21 if ($node eq "localhost") {
298 root 1.24 @target = (["127.0.0.1", $port], ["::1", $port]);
299     &$resolve;
300 root 1.21 } elsif (defined $service && !AnyEvent::Socket::parse_ip ($node)) {
301 root 1.18 srv $service, $proto, $node, sub {
302     my (@srv) = @_;
303    
304     # no srv records, continue traditionally
305     @srv
306     or return &$resolve;
307    
308     # only srv record has "." => abort
309     $srv[0][2] ne "." || $#srv
310     or return $cb->();
311    
312     # use srv records then
313 root 1.21 @target = map ["$_->[3].", $_->[2]],
314 root 1.18 grep $_->[3] ne ".",
315     @srv;
316    
317     &$resolve;
318     };
319     } else {
320     &$resolve;
321     }
322     }
323    
324     #############################################################################
325    
326 root 1.15 =back
327    
328 root 1.13 =head2 LOW-LEVEL DNS EN-/DECODING FUNCTIONS
329 root 1.1
330     =over 4
331    
332 root 1.11 =item $AnyEvent::DNS::EDNS0
333    
334 root 1.13 This variable decides whether dns_pack automatically enables EDNS0
335 root 1.24 support. By default, this is disabled (C<0>), unless overridden by
336 root 1.21 C<$ENV{PERL_ANYEVENT_EDNS0>), but when set to C<1>, AnyEvent::DNS will use
337     EDNS0 in all requests.
338 root 1.11
339 root 1.1 =cut
340    
341 root 1.21 our $EDNS0 = $ENV{PERL_ANYEVENT_EDNS0} * 1; # set to 1 to enable (partial) edns0
342 root 1.10
343 root 1.1 our %opcode_id = (
344     query => 0,
345     iquery => 1,
346     status => 2,
347 root 1.5 notify => 4,
348     update => 5,
349     map +($_ => $_), 3, 6..15
350 root 1.1 );
351    
352     our %opcode_str = reverse %opcode_id;
353    
354     our %rcode_id = (
355 root 1.5 noerror => 0,
356     formerr => 1,
357     servfail => 2,
358     nxdomain => 3,
359     notimp => 4,
360     refused => 5,
361     yxdomain => 6, # Name Exists when it should not [RFC 2136]
362     yxrrset => 7, # RR Set Exists when it should not [RFC 2136]
363     nxrrset => 8, # RR Set that should exist does not [RFC 2136]
364     notauth => 9, # Server Not Authoritative for zone [RFC 2136]
365     notzone => 10, # Name not contained in zone [RFC 2136]
366     # EDNS0 16 BADVERS Bad OPT Version [RFC 2671]
367     # EDNS0 16 BADSIG TSIG Signature Failure [RFC 2845]
368     # EDNS0 17 BADKEY Key not recognized [RFC 2845]
369     # EDNS0 18 BADTIME Signature out of time window [RFC 2845]
370     # EDNS0 19 BADMODE Bad TKEY Mode [RFC 2930]
371     # EDNS0 20 BADNAME Duplicate key name [RFC 2930]
372     # EDNS0 21 BADALG Algorithm not supported [RFC 2930]
373     map +($_ => $_), 11..15
374 root 1.1 );
375    
376     our %rcode_str = reverse %rcode_id;
377    
378     our %type_id = (
379     a => 1,
380     ns => 2,
381     md => 3,
382     mf => 4,
383     cname => 5,
384     soa => 6,
385     mb => 7,
386     mg => 8,
387     mr => 9,
388     null => 10,
389     wks => 11,
390     ptr => 12,
391     hinfo => 13,
392     minfo => 14,
393     mx => 15,
394     txt => 16,
395     aaaa => 28,
396     srv => 33,
397 root 1.5 opt => 41,
398     spf => 99,
399     tkey => 249,
400     tsig => 250,
401     ixfr => 251,
402 root 1.1 axfr => 252,
403     mailb => 253,
404     "*" => 255,
405     );
406    
407     our %type_str = reverse %type_id;
408    
409     our %class_id = (
410 root 1.5 in => 1,
411     ch => 3,
412     hs => 4,
413     none => 254,
414     "*" => 255,
415 root 1.1 );
416    
417     our %class_str = reverse %class_id;
418    
419     # names MUST have a trailing dot
420 root 1.34 sub _enc_name($) {
421 root 1.29 pack "(C/a*)*", (split /\./, shift), ""
422 root 1.1 }
423    
424     sub _enc_qd() {
425 root 1.34 (_enc_name $_->[0]) . pack "nn",
426 root 1.1 ($_->[1] > 0 ? $_->[1] : $type_id {$_->[1]}),
427     ($_->[2] > 0 ? $_->[2] : $class_id{$_->[2] || "in"})
428     }
429    
430     sub _enc_rr() {
431     die "encoding of resource records is not supported";
432     }
433    
434     =item $pkt = AnyEvent::DNS::dns_pack $dns
435    
436     Packs a perl data structure into a DNS packet. Reading RFC1034 is strongly
437     recommended, then everything will be totally clear. Or maybe not.
438    
439     Resource records are not yet encodable.
440    
441     Examples:
442    
443     # very simple request, using lots of default values:
444     { rd => 1, qd => [ [ "host.domain", "a"] ] }
445    
446     # more complex example, showing how flags etc. are named:
447    
448     {
449     id => 10000,
450     op => "query",
451     rc => "nxdomain",
452    
453     # flags
454     qr => 1,
455     aa => 0,
456     tc => 0,
457     rd => 0,
458     ra => 0,
459 root 1.5 ad => 0,
460     cd => 0,
461 root 1.1
462     qd => [@rr], # query section
463     an => [@rr], # answer section
464     ns => [@rr], # authority section
465     ar => [@rr], # additional records section
466     }
467    
468     =cut
469    
470     sub dns_pack($) {
471     my ($req) = @_;
472    
473 root 1.7 pack "nn nnnn a* a* a* a* a*",
474 root 1.1 $req->{id},
475    
476     ! !$req->{qr} * 0x8000
477     + $opcode_id{$req->{op}} * 0x0800
478     + ! !$req->{aa} * 0x0400
479     + ! !$req->{tc} * 0x0200
480     + ! !$req->{rd} * 0x0100
481     + ! !$req->{ra} * 0x0080
482 root 1.5 + ! !$req->{ad} * 0x0020
483     + ! !$req->{cd} * 0x0010
484 root 1.1 + $rcode_id{$req->{rc}} * 0x0001,
485    
486     scalar @{ $req->{qd} || [] },
487     scalar @{ $req->{an} || [] },
488     scalar @{ $req->{ns} || [] },
489 root 1.11 $EDNS0 + scalar @{ $req->{ar} || [] }, # include EDNS0 option here
490 root 1.1
491     (join "", map _enc_qd, @{ $req->{qd} || [] }),
492     (join "", map _enc_rr, @{ $req->{an} || [] }),
493     (join "", map _enc_rr, @{ $req->{ns} || [] }),
494 root 1.7 (join "", map _enc_rr, @{ $req->{ar} || [] }),
495    
496 root 1.11 ($EDNS0 ? pack "C nnNn", 0, 41, 4096, 0, 0 : "") # EDNS0, 4kiB udp payload size
497 root 1.1 }
498    
499     our $ofs;
500     our $pkt;
501    
502     # bitches
503 root 1.34 sub _dec_name {
504 root 1.1 my @res;
505     my $redir;
506     my $ptr = $ofs;
507     my $cnt;
508    
509     while () {
510     return undef if ++$cnt >= 256; # to avoid DoS attacks
511    
512     my $len = ord substr $pkt, $ptr++, 1;
513    
514 root 1.34 if ($len >= 0xc0) {
515 root 1.1 $ptr++;
516     $ofs = $ptr if $ptr > $ofs;
517     $ptr = (unpack "n", substr $pkt, $ptr - 2, 2) & 0x3fff;
518     } elsif ($len) {
519     push @res, substr $pkt, $ptr, $len;
520     $ptr += $len;
521     } else {
522     $ofs = $ptr if $ptr > $ofs;
523     return join ".", @res;
524     }
525     }
526     }
527    
528     sub _dec_qd {
529 root 1.34 my $qname = _dec_name;
530 root 1.1 my ($qt, $qc) = unpack "nn", substr $pkt, $ofs; $ofs += 4;
531     [$qname, $type_str{$qt} || $qt, $class_str{$qc} || $qc]
532     }
533    
534     our %dec_rr = (
535 root 1.29 1 => sub { join ".", unpack "C4", $_ }, # a
536 root 1.34 2 => sub { local $ofs = $ofs - length; _dec_name }, # ns
537     5 => sub { local $ofs = $ofs - length; _dec_name }, # cname
538 root 1.1 6 => sub {
539     local $ofs = $ofs - length;
540 root 1.34 my $mname = _dec_name;
541     my $rname = _dec_name;
542 root 1.1 ($mname, $rname, unpack "NNNNN", substr $pkt, $ofs)
543     }, # soa
544 root 1.29 11 => sub { ((join ".", unpack "C4", $_), unpack "C a*", substr $_, 4) }, # wks
545 root 1.34 12 => sub { local $ofs = $ofs - length; _dec_name }, # ptr
546 root 1.29 13 => sub { unpack "C/a* C/a*", $_ }, # hinfo
547 root 1.34 15 => sub { local $ofs = $ofs + 2 - length; ((unpack "n", $_), _dec_name) }, # mx
548 root 1.29 16 => sub { unpack "(C/a*)*", $_ }, # txt
549 root 1.17 28 => sub { AnyEvent::Socket::format_ip ($_) }, # aaaa
550 root 1.34 33 => sub { local $ofs = $ofs + 6 - length; ((unpack "nnn", $_), _dec_name) }, # srv
551 root 1.29 99 => sub { unpack "(C/a*)*", $_ }, # spf
552 root 1.1 );
553    
554     sub _dec_rr {
555 root 1.34 my $name = _dec_name;
556 root 1.1
557     my ($rt, $rc, $ttl, $rdlen) = unpack "nn N n", substr $pkt, $ofs; $ofs += 10;
558     local $_ = substr $pkt, $ofs, $rdlen; $ofs += $rdlen;
559    
560     [
561 root 1.34 $name,
562 root 1.1 $type_str{$rt} || $rt,
563     $class_str{$rc} || $rc,
564     ($dec_rr{$rt} || sub { $_ })->(),
565     ]
566     }
567    
568     =item $dns = AnyEvent::DNS::dns_unpack $pkt
569    
570     Unpacks a DNS packet into a perl data structure.
571    
572     Examples:
573    
574 root 1.13 # an unsuccessful reply
575 root 1.1 {
576     'qd' => [
577     [ 'ruth.plan9.de.mach.uni-karlsruhe.de', '*', 'in' ]
578     ],
579     'rc' => 'nxdomain',
580     'ar' => [],
581     'ns' => [
582     [
583     'uni-karlsruhe.de',
584     'soa',
585     'in',
586     'netserv.rz.uni-karlsruhe.de',
587     'hostmaster.rz.uni-karlsruhe.de',
588 root 1.13 2008052201, 10800, 1800, 2592000, 86400
589 root 1.1 ]
590     ],
591     'tc' => '',
592     'ra' => 1,
593     'qr' => 1,
594     'id' => 45915,
595     'aa' => '',
596     'an' => [],
597     'rd' => 1,
598     'op' => 'query'
599     }
600    
601     # a successful reply
602    
603     {
604     'qd' => [ [ 'www.google.de', 'a', 'in' ] ],
605     'rc' => 0,
606     'ar' => [
607     [ 'a.l.google.com', 'a', 'in', '209.85.139.9' ],
608     [ 'b.l.google.com', 'a', 'in', '64.233.179.9' ],
609     [ 'c.l.google.com', 'a', 'in', '64.233.161.9' ],
610     ],
611     'ns' => [
612     [ 'l.google.com', 'ns', 'in', 'a.l.google.com' ],
613     [ 'l.google.com', 'ns', 'in', 'b.l.google.com' ],
614     ],
615     'tc' => '',
616     'ra' => 1,
617     'qr' => 1,
618     'id' => 64265,
619     'aa' => '',
620     'an' => [
621     [ 'www.google.de', 'cname', 'in', 'www.google.com' ],
622     [ 'www.google.com', 'cname', 'in', 'www.l.google.com' ],
623     [ 'www.l.google.com', 'a', 'in', '66.249.93.104' ],
624     [ 'www.l.google.com', 'a', 'in', '66.249.93.147' ],
625     ],
626     'rd' => 1,
627     'op' => 0
628     }
629    
630     =cut
631    
632     sub dns_unpack($) {
633     local $pkt = shift;
634     my ($id, $flags, $qd, $an, $ns, $ar)
635     = unpack "nn nnnn A*", $pkt;
636    
637     local $ofs = 6 * 2;
638    
639     {
640     id => $id,
641     qr => ! ! ($flags & 0x8000),
642     aa => ! ! ($flags & 0x0400),
643     tc => ! ! ($flags & 0x0200),
644     rd => ! ! ($flags & 0x0100),
645     ra => ! ! ($flags & 0x0080),
646 root 1.5 ad => ! ! ($flags & 0x0020),
647     cd => ! ! ($flags & 0x0010),
648 root 1.1 op => $opcode_str{($flags & 0x001e) >> 11},
649     rc => $rcode_str{($flags & 0x000f)},
650    
651     qd => [map _dec_qd, 1 .. $qd],
652     an => [map _dec_rr, 1 .. $an],
653     ns => [map _dec_rr, 1 .. $ns],
654     ar => [map _dec_rr, 1 .. $ar],
655     }
656     }
657    
658     #############################################################################
659    
660     =back
661    
662     =head2 THE AnyEvent::DNS RESOLVER CLASS
663    
664 root 1.13 This is the class which does the actual protocol work.
665 root 1.1
666     =over 4
667    
668     =cut
669    
670     use Carp ();
671     use Scalar::Util ();
672     use Socket ();
673    
674     our $NOW;
675    
676 root 1.2 =item AnyEvent::DNS::resolver
677    
678     This function creates and returns a resolver that is ready to use and
679     should mimic the default resolver for your system as good as possible.
680    
681     It only ever creates one resolver and returns this one on subsequent
682     calls.
683    
684     Unless you have special needs, prefer this function over creating your own
685     resolver object.
686    
687     =cut
688    
689     our $RESOLVER;
690    
691     sub resolver() {
692     $RESOLVER || do {
693     $RESOLVER = new AnyEvent::DNS;
694 root 1.14 $RESOLVER->os_config;
695 root 1.2 $RESOLVER
696     }
697     }
698    
699 root 1.1 =item $resolver = new AnyEvent::DNS key => value...
700    
701 root 1.6 Creates and returns a new resolver.
702 root 1.2
703     The following options are supported:
704 root 1.1
705     =over 4
706    
707     =item server => [...]
708    
709 root 1.24 A list of server addresses (default: C<v127.0.0.1>) in network format (4
710 root 1.1 octets for IPv4, 16 octets for IPv6 - not yet supported).
711    
712     =item timeout => [...]
713    
714     A list of timeouts to use (also determines the number of retries). To make
715     three retries with individual time-outs of 2, 5 and 5 seconds, use C<[2,
716     5, 5]>, which is also the default.
717    
718     =item search => [...]
719    
720     The default search list of suffixes to append to a domain name (default: none).
721    
722 root 1.2 =item ndots => $integer
723 root 1.1
724     The number of dots (default: C<1>) that a name must have so that the resolver
725     tries to resolve the name without any suffixes first.
726    
727 root 1.2 =item max_outstanding => $integer
728 root 1.1
729     Most name servers do not handle many parallel requests very well. This option
730 root 1.24 limits the number of outstanding requests to C<$n> (default: C<10>), that means
731 root 1.1 if you request more than this many requests, then the additional requests will be queued
732     until some other requests have been resolved.
733    
734 root 1.13 =item reuse => $seconds
735    
736 root 1.22 The number of seconds (default: C<300>) that a query id cannot be re-used
737     after a timeout. If there as no time-out then query id's can be reused
738     immediately.
739 root 1.13
740 root 1.1 =back
741    
742     =cut
743    
744     sub new {
745     my ($class, %arg) = @_;
746    
747 root 1.29 socket my $fh, AF_INET, &Socket::SOCK_DGRAM, 0
748 root 1.1 or Carp::croak "socket: $!";
749    
750     AnyEvent::Util::fh_nonblocking $fh, 1;
751    
752     my $self = bless {
753 root 1.32 server => [],
754 root 1.1 timeout => [2, 5, 5],
755     search => [],
756     ndots => 1,
757     max_outstanding => 10,
758 root 1.22 reuse => 300, # reuse id's after 5 minutes only, if possible
759 root 1.1 %arg,
760     fh => $fh,
761     reuse_q => [],
762     }, $class;
763    
764     # search should default to gethostname's domain
765     # but perl lacks a good posix module
766    
767     Scalar::Util::weaken (my $wself = $self);
768     $self->{rw} = AnyEvent->io (fh => $fh, poll => "r", cb => sub { $wself->_recv });
769    
770     $self->_compile;
771    
772     $self
773     }
774    
775     =item $resolver->parse_resolv_conv ($string)
776    
777 root 1.24 Parses the given string as if it were a F<resolv.conf> file. The following
778     directives are supported (but not necessarily implemented).
779 root 1.1
780     C<#>-style comments, C<nameserver>, C<domain>, C<search>, C<sortlist>,
781     C<options> (C<timeout>, C<attempts>, C<ndots>).
782    
783     Everything else is silently ignored.
784    
785     =cut
786    
787     sub parse_resolv_conf {
788     my ($self, $resolvconf) = @_;
789    
790     $self->{server} = [];
791     $self->{search} = [];
792    
793     my $attempts;
794    
795     for (split /\n/, $resolvconf) {
796     if (/^\s*#/) {
797     # comment
798     } elsif (/^\s*nameserver\s+(\S+)\s*$/i) {
799     my $ip = $1;
800 root 1.25 if (my $ipn = AnyEvent::Socket::parse_ip ($ip)) {
801     push @{ $self->{server} }, $ipn;
802 root 1.1 } else {
803     warn "nameserver $ip invalid and ignored\n";
804     }
805     } elsif (/^\s*domain\s+(\S*)\s+$/i) {
806     $self->{search} = [$1];
807     } elsif (/^\s*search\s+(.*?)\s*$/i) {
808     $self->{search} = [split /\s+/, $1];
809     } elsif (/^\s*sortlist\s+(.*?)\s*$/i) {
810     # ignored, NYI
811     } elsif (/^\s*options\s+(.*?)\s*$/i) {
812     for (split /\s+/, $1) {
813     if (/^timeout:(\d+)$/) {
814     $self->{timeout} = [$1];
815     } elsif (/^attempts:(\d+)$/) {
816     $attempts = $1;
817     } elsif (/^ndots:(\d+)$/) {
818     $self->{ndots} = $1;
819     } else {
820     # debug, rotate, no-check-names, inet6
821     }
822     }
823     }
824     }
825    
826     $self->{timeout} = [($self->{timeout}[0]) x $attempts]
827     if $attempts;
828    
829     $self->_compile;
830     }
831    
832 root 1.14 =item $resolver->os_config
833 root 1.1
834 root 1.24 Tries so load and parse F</etc/resolv.conf> on portable operating systems. Tries various
835     egregious hacks on windows to force the DNS servers and searchlist out of the system.
836 root 1.1
837     =cut
838    
839 root 1.14 sub os_config {
840 root 1.1 my ($self) = @_;
841    
842 root 1.32 $self->{server} = [];
843     $self->{search} = [];
844    
845 root 1.35 if (AnyEvent::WIN32 || $^O =~ /cygwin/i) {
846 root 1.32 no strict 'refs';
847    
848     # there are many options to find the current nameservers etc. on windows
849     # all of them don't work consistently:
850     # - the registry thing needs separate code on win32 native vs. cygwin
851     # - the registry layout differs between windows versions
852     # - calling windows api functions doesn't work on cygwin
853     # - ipconfig uses locale-specific messages
854    
855     # we use ipconfig parsing because, despite all it's brokenness,
856     # it seems most stable in practise.
857     # for good measure, we append a fallback nameserver to our list.
858 root 1.14
859     if (open my $fh, "ipconfig /all |") {
860 root 1.32 # parsing strategy: we go through the output and look for
861     # :-lines with DNS in them. everything in those is regarded as
862     # either a nameserver (if it parses as an ip address), or a suffix
863     # (all else).
864 root 1.14
865 root 1.32 my $dns;
866 root 1.14 while (<$fh>) {
867 root 1.32 if (s/^\s.*\bdns\b.*://i) {
868     $dns = 1;
869     } elsif (/^\S/ || /^\s[^:]{16,}: /) {
870     $dns = 0;
871     }
872     if ($dns && /^\s*(\S+)\s*$/) {
873     my $s = $1;
874     $s =~ s/%\d+(?!\S)//; # get rid of scope id
875     if (my $ipn = AnyEvent::Socket::parse_ip ($s)) {
876     push @{ $self->{server} }, $ipn;
877     } else {
878     push @{ $self->{search} }, $s;
879 root 1.14 }
880     }
881     }
882    
883 root 1.32 # always add one fallback server
884     push @{ $self->{server} }, $DNS_FALLBACK[rand @DNS_FALLBACK];
885 root 1.14
886     $self->_compile;
887     }
888     } else {
889     # try resolv.conf everywhere
890 root 1.1
891 root 1.14 if (open my $fh, "</etc/resolv.conf") {
892     local $/;
893     $self->parse_resolv_conf (<$fh>);
894     }
895     }
896 root 1.1 }
897    
898     sub _compile {
899     my $self = shift;
900    
901 root 1.32 # we currently throw away all ipv6 nameservers, we do not yet support those
902    
903     my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
904     my %server; $self->{server} = [grep 4 == length, grep !$server{$_}++, @{ $self->{server} }];
905    
906     unless (@{ $self->{server} }) {
907     # use 127.0.0.1 by default, and one opendns nameserver as fallback
908     $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
909     }
910    
911 root 1.1 my @retry;
912    
913     for my $timeout (@{ $self->{timeout} }) {
914     for my $server (@{ $self->{server} }) {
915     push @retry, [$server, $timeout];
916     }
917     }
918    
919     $self->{retry} = \@retry;
920     }
921    
922 root 1.6 sub _feed {
923     my ($self, $res) = @_;
924    
925     $res = dns_unpack $res
926     or return;
927    
928     my $id = $self->{id}{$res->{id}};
929    
930     return unless ref $id;
931    
932     $NOW = time;
933     $id->[1]->($res);
934     }
935    
936 root 1.1 sub _recv {
937     my ($self) = @_;
938    
939 root 1.32 # we ignore errors (often one gets port unreachable, but there is
940     # no good way to take advantage of that.
941 root 1.9 while (my $peer = recv $self->{fh}, my $res, 4096, 0) {
942 root 1.21 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
943 root 1.1
944     return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
945    
946 root 1.6 $self->_feed ($res);
947 root 1.1 }
948     }
949    
950 root 1.22 sub _free_id {
951     my ($self, $id, $timeout) = @_;
952    
953     if ($timeout) {
954     # we need to block the id for a while
955     $self->{id}{$id} = 1;
956     push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
957     } else {
958     # we can quickly recycle the id
959     delete $self->{id}{$id};
960     }
961    
962     --$self->{outstanding};
963     $self->_scheduler;
964     }
965    
966     # execute a single request, involves sending it with timeouts to multiple servers
967 root 1.1 sub _exec {
968 root 1.22 my ($self, $req) = @_;
969    
970     my $retry; # of retries
971     my $do_retry;
972    
973     $do_retry = sub {
974     my $retry_cfg = $self->{retry}[$retry++]
975     or do {
976     # failure
977     $self->_free_id ($req->[2], $retry > 1);
978     undef $do_retry; return $req->[1]->();
979     };
980 root 1.1
981     my ($server, $timeout) = @$retry_cfg;
982    
983     $self->{id}{$req->[2]} = [AnyEvent->timer (after => $timeout, cb => sub {
984     $NOW = time;
985    
986     # timeout, try next
987 root 1.22 &$do_retry;
988 root 1.1 }), sub {
989     my ($res) = @_;
990    
991 root 1.6 if ($res->{tc}) {
992     # success, but truncated, so use tcp
993 root 1.17 AnyEvent::Socket::tcp_connect ((Socket::inet_ntoa $server), 53, sub {
994 root 1.6 my ($fh) = @_
995 root 1.22 or return &$do_retry;
996 root 1.6
997     my $handle = new AnyEvent::Handle
998     fh => $fh,
999     on_error => sub {
1000     # failure, try next
1001 root 1.22 &$do_retry;
1002 root 1.6 };
1003    
1004     $handle->push_write (pack "n/a", $req->[0]);
1005 root 1.27 $handle->push_read (chunk => 2, sub {
1006     $handle->unshift_read (chunk => (unpack "n", $_[1]), sub {
1007 root 1.6 $self->_feed ($_[1]);
1008     });
1009     });
1010     shutdown $fh, 1;
1011    
1012 root 1.17 }, sub { $timeout });
1013 root 1.1
1014 root 1.6 } else {
1015     # success
1016 root 1.22 $self->_free_id ($req->[2], $retry > 1);
1017     undef $do_retry; return $req->[1]->($res);
1018 root 1.6 }
1019 root 1.1 }];
1020    
1021 root 1.21 send $self->{fh}, $req->[0], 0, AnyEvent::Socket::pack_sockaddr (53, $server);
1022 root 1.22 };
1023 root 1.1
1024 root 1.22 &$do_retry;
1025 root 1.1 }
1026    
1027     sub _scheduler {
1028     my ($self) = @_;
1029    
1030     $NOW = time;
1031    
1032     # first clear id reuse queue
1033     delete $self->{id}{ (shift @{ $self->{reuse_q} })->[1] }
1034 root 1.13 while @{ $self->{reuse_q} } && $self->{reuse_q}[0][0] <= $NOW;
1035 root 1.1
1036     while ($self->{outstanding} < $self->{max_outstanding}) {
1037 root 1.13
1038     if (@{ $self->{reuse_q} } >= 30000) {
1039     # we ran out of ID's, wait a bit
1040     $self->{reuse_to} ||= AnyEvent->timer (after => $self->{reuse_q}[0][0] - $NOW, cb => sub {
1041     delete $self->{reuse_to};
1042     $self->_scheduler;
1043     });
1044     last;
1045     }
1046    
1047 root 1.1 my $req = shift @{ $self->{queue} }
1048     or last;
1049    
1050     while () {
1051     $req->[2] = int rand 65536;
1052     last unless exists $self->{id}{$req->[2]};
1053     }
1054    
1055 root 1.22 ++$self->{outstanding};
1056 root 1.1 $self->{id}{$req->[2]} = 1;
1057     substr $req->[0], 0, 2, pack "n", $req->[2];
1058    
1059 root 1.22 $self->_exec ($req);
1060 root 1.1 }
1061     }
1062    
1063     =item $resolver->request ($req, $cb->($res))
1064    
1065     Sends a single request (a hash-ref formated as specified for
1066 root 1.3 C<dns_pack>) to the configured nameservers including
1067 root 1.1 retries. Calls the callback with the decoded response packet if a reply
1068     was received, or no arguments on timeout.
1069    
1070     =cut
1071    
1072     sub request($$) {
1073     my ($self, $req, $cb) = @_;
1074    
1075 root 1.3 push @{ $self->{queue} }, [dns_pack $req, $cb];
1076 root 1.1 $self->_scheduler;
1077     }
1078    
1079     =item $resolver->resolve ($qname, $qtype, %options, $cb->($rcode, @rr))
1080    
1081     Queries the DNS for the given domain name C<$qname> of type C<$qtype> (a
1082     qtype of "*" is supported and means "any").
1083    
1084     The callback will be invoked with a list of matching result records or
1085     none on any error or if the name could not be found.
1086    
1087     CNAME chains (although illegal) are followed up to a length of 8.
1088    
1089 root 1.24 Note that this resolver is just a stub resolver: it requires a name server
1090 root 1.3 supporting recursive queries, will not do any recursive queries itself and
1091     is not secure when used against an untrusted name server.
1092    
1093 root 1.1 The following options are supported:
1094    
1095     =over 4
1096    
1097     =item search => [$suffix...]
1098    
1099     Use the given search list (which might be empty), by appending each one
1100     in turn to the C<$qname>. If this option is missing then the configured
1101     C<ndots> and C<search> define its value. If the C<$qname> ends in a dot,
1102 root 1.2 then the searchlist will be ignored.
1103 root 1.1
1104     =item accept => [$type...]
1105    
1106     Lists the acceptable result types: only result types in this set will be
1107     accepted and returned. The default includes the C<$qtype> and nothing
1108     else.
1109    
1110     =item class => "class"
1111    
1112     Specify the query class ("in" for internet, "ch" for chaosnet and "hs" for
1113 root 1.2 hesiod are the only ones making sense). The default is "in", of course.
1114 root 1.1
1115     =back
1116    
1117     Examples:
1118    
1119     $res->resolve ("ruth.plan9.de", "a", sub {
1120     warn Dumper [@_];
1121     });
1122    
1123     [
1124     [
1125     'ruth.schmorp.de',
1126     'a',
1127     'in',
1128     '129.13.162.95'
1129     ]
1130     ]
1131    
1132     $res->resolve ("test1.laendle", "*",
1133     accept => ["a", "aaaa"],
1134     sub {
1135     warn Dumper [@_];
1136     }
1137     );
1138    
1139     [
1140     [
1141     'test1.laendle',
1142     'a',
1143     'in',
1144     '10.0.0.255'
1145     ],
1146     [
1147     'test1.laendle',
1148     'aaaa',
1149     'in',
1150     '3ffe:1900:4545:0002:0240:0000:0000:f7e1'
1151     ]
1152     ]
1153    
1154     =cut
1155    
1156     sub resolve($%) {
1157     my $cb = pop;
1158     my ($self, $qname, $qtype, %opt) = @_;
1159    
1160     my @search = $qname =~ s/\.$//
1161     ? ""
1162     : $opt{search}
1163     ? @{ $opt{search} }
1164     : ($qname =~ y/.//) >= $self->{ndots}
1165     ? ("", @{ $self->{search} })
1166     : (@{ $self->{search} }, "");
1167    
1168     my $class = $opt{class} || "in";
1169    
1170     my %atype = $opt{accept}
1171     ? map +($_ => 1), @{ $opt{accept} }
1172     : ($qtype => 1);
1173    
1174     # advance in searchlist
1175 root 1.22 my ($do_search, $do_req);
1176    
1177     $do_search = sub {
1178 root 1.1 @search
1179 root 1.22 or (undef $do_search), (undef $do_req), return $cb->();
1180 root 1.1
1181 root 1.4 (my $name = lc "$qname." . shift @search) =~ s/\.$//;
1182 root 1.1 my $depth = 2;
1183    
1184     # advance in cname-chain
1185 root 1.22 $do_req = sub {
1186 root 1.1 $self->request ({
1187     rd => 1,
1188     qd => [[$name, $qtype, $class]],
1189     }, sub {
1190     my ($res) = @_
1191     or return $do_search->();
1192    
1193     my $cname;
1194    
1195     while () {
1196 root 1.2 # results found?
1197 root 1.4 my @rr = grep $name eq lc $_->[0] && ($atype{"*"} || $atype{$_->[1]}), @{ $res->{an} };
1198 root 1.1
1199 root 1.22 (undef $do_search), (undef $do_req), return $cb->(@rr)
1200 root 1.1 if @rr;
1201    
1202     # see if there is a cname we can follow
1203 root 1.4 my @rr = grep $name eq lc $_->[0] && $_->[1] eq "cname", @{ $res->{an} };
1204 root 1.1
1205     if (@rr) {
1206     $depth--
1207     or return $do_search->(); # cname chain too long
1208    
1209     $cname = 1;
1210     $name = $rr[0][3];
1211    
1212     } elsif ($cname) {
1213     # follow the cname
1214     return $do_req->();
1215    
1216     } else {
1217 root 1.2 # no, not found anything
1218 root 1.1 return $do_search->();
1219     }
1220     }
1221     });
1222     };
1223    
1224     $do_req->();
1225     };
1226    
1227     $do_search->();
1228     }
1229    
1230 root 1.17 use AnyEvent::Socket (); # circular dependency, so do not import anything and do it at the end
1231    
1232 root 1.1 1;
1233    
1234     =back
1235    
1236     =head1 AUTHOR
1237    
1238     Marc Lehmann <schmorp@schmorp.de>
1239     http://home.schmorp.de/
1240    
1241     =cut
1242