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