ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.64
Committed: Thu Jun 5 07:11:40 2008 UTC (16 years, 1 month ago) by elmex
Branch: MAIN
Changes since 1.63: +1 -1 lines
Log Message:
fixed bug in srv priority sorting

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 root 1.57 use AnyEvent::DNS;
8    
9     my $cv = AnyEvent->condvar;
10     AnyEvent::DNS::a "www.google.de", $cv;
11     # ... later
12     my @addrs = $cv->recv;
13 root 1.26
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.62 our $VERSION = 4.13;
41 root 1.39
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.59 Each C<$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 elmex 1.64 for my $pri (sort { $a <=> $b } keys %pri) {
176 root 1.49 # 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 root 1.55 resolver->resolve ("$name." => ($af == (AF_INET) ? "a" : "aaaa"), sub {
271 root 1.48 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 root 1.57 # 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     ad => 0,
419     cd => 0,
420    
421     qd => [@rr], # query section
422     an => [@rr], # answer section
423     ns => [@rr], # authority section
424     ar => [@rr], # additional records section
425     }
426 root 1.1
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.57 # an unsuccessful reply
539     {
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     2008052201, 10800, 1800, 2592000, 86400
553     ]
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 root 1.1
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 root 1.54 after a timeout. If there was no time-out then query ids can be reused
704 root 1.22 immediately.
705 root 1.13
706 root 1.1 =back
707    
708     =cut
709    
710     sub new {
711     my ($class, %arg) = @_;
712    
713     my $self = bless {
714 root 1.32 server => [],
715 root 1.1 timeout => [2, 5, 5],
716     search => [],
717     ndots => 1,
718     max_outstanding => 10,
719 root 1.54 reuse => 300,
720 root 1.1 %arg,
721     reuse_q => [],
722     }, $class;
723    
724     # search should default to gethostname's domain
725     # but perl lacks a good posix module
726    
727 root 1.63 # try to create an ipv4 and an ipv6 socket
728     # only fail when we cannot create either
729     my $got_socket;
730    
731 root 1.1 Scalar::Util::weaken (my $wself = $self);
732 root 1.38
733 root 1.63 if (socket my $fh4, AF_INET , &Socket::SOCK_DGRAM, 0) {
734     ++$got_socket;
735    
736 root 1.38 AnyEvent::Util::fh_nonblocking $fh4, 1;
737     $self->{fh4} = $fh4;
738     $self->{rw4} = AnyEvent->io (fh => $fh4, poll => "r", cb => sub {
739     if (my $peer = recv $fh4, my $pkt, MAX_PKT, 0) {
740     $wself->_recv ($pkt, $peer);
741     }
742     });
743     }
744    
745 root 1.63 if (AF_INET6 && socket my $fh6, AF_INET6, &Socket::SOCK_DGRAM, 0) {
746     ++$got_socket;
747    
748 root 1.38 $self->{fh6} = $fh6;
749     AnyEvent::Util::fh_nonblocking $fh6, 1;
750     $self->{rw6} = AnyEvent->io (fh => $fh6, poll => "r", cb => sub {
751     if (my $peer = recv $fh6, my $pkt, MAX_PKT, 0) {
752     $wself->_recv ($pkt, $peer);
753     }
754     });
755     }
756 root 1.1
757 root 1.63 $got_socket
758     or Carp::croak "unable to create either an IPv4 or an IPv6 socket";
759    
760 root 1.1 $self->_compile;
761    
762     $self
763     }
764    
765     =item $resolver->parse_resolv_conv ($string)
766    
767 root 1.24 Parses the given string as if it were a F<resolv.conf> file. The following
768     directives are supported (but not necessarily implemented).
769 root 1.1
770     C<#>-style comments, C<nameserver>, C<domain>, C<search>, C<sortlist>,
771     C<options> (C<timeout>, C<attempts>, C<ndots>).
772    
773     Everything else is silently ignored.
774    
775     =cut
776    
777     sub parse_resolv_conf {
778     my ($self, $resolvconf) = @_;
779    
780     $self->{server} = [];
781     $self->{search} = [];
782    
783     my $attempts;
784    
785     for (split /\n/, $resolvconf) {
786     if (/^\s*#/) {
787     # comment
788     } elsif (/^\s*nameserver\s+(\S+)\s*$/i) {
789     my $ip = $1;
790 root 1.36 if (my $ipn = AnyEvent::Socket::parse_address ($ip)) {
791 root 1.25 push @{ $self->{server} }, $ipn;
792 root 1.1 } else {
793     warn "nameserver $ip invalid and ignored\n";
794     }
795     } elsif (/^\s*domain\s+(\S*)\s+$/i) {
796     $self->{search} = [$1];
797     } elsif (/^\s*search\s+(.*?)\s*$/i) {
798     $self->{search} = [split /\s+/, $1];
799     } elsif (/^\s*sortlist\s+(.*?)\s*$/i) {
800     # ignored, NYI
801     } elsif (/^\s*options\s+(.*?)\s*$/i) {
802     for (split /\s+/, $1) {
803     if (/^timeout:(\d+)$/) {
804     $self->{timeout} = [$1];
805     } elsif (/^attempts:(\d+)$/) {
806     $attempts = $1;
807     } elsif (/^ndots:(\d+)$/) {
808     $self->{ndots} = $1;
809     } else {
810     # debug, rotate, no-check-names, inet6
811     }
812     }
813     }
814     }
815    
816     $self->{timeout} = [($self->{timeout}[0]) x $attempts]
817     if $attempts;
818    
819     $self->_compile;
820     }
821    
822 root 1.14 =item $resolver->os_config
823 root 1.1
824 root 1.24 Tries so load and parse F</etc/resolv.conf> on portable operating systems. Tries various
825     egregious hacks on windows to force the DNS servers and searchlist out of the system.
826 root 1.1
827     =cut
828    
829 root 1.14 sub os_config {
830 root 1.1 my ($self) = @_;
831    
832 root 1.32 $self->{server} = [];
833     $self->{search} = [];
834    
835 root 1.35 if (AnyEvent::WIN32 || $^O =~ /cygwin/i) {
836 root 1.32 no strict 'refs';
837    
838     # there are many options to find the current nameservers etc. on windows
839     # all of them don't work consistently:
840     # - the registry thing needs separate code on win32 native vs. cygwin
841     # - the registry layout differs between windows versions
842     # - calling windows api functions doesn't work on cygwin
843     # - ipconfig uses locale-specific messages
844    
845 root 1.54 # we use ipconfig parsing because, despite all its brokenness,
846 root 1.32 # it seems most stable in practise.
847     # for good measure, we append a fallback nameserver to our list.
848 root 1.14
849     if (open my $fh, "ipconfig /all |") {
850 root 1.32 # parsing strategy: we go through the output and look for
851     # :-lines with DNS in them. everything in those is regarded as
852     # either a nameserver (if it parses as an ip address), or a suffix
853     # (all else).
854 root 1.14
855 root 1.32 my $dns;
856 root 1.14 while (<$fh>) {
857 root 1.32 if (s/^\s.*\bdns\b.*://i) {
858     $dns = 1;
859     } elsif (/^\S/ || /^\s[^:]{16,}: /) {
860     $dns = 0;
861     }
862     if ($dns && /^\s*(\S+)\s*$/) {
863     my $s = $1;
864 root 1.54 $s =~ s/%\d+(?!\S)//; # get rid of ipv6 scope id
865 root 1.36 if (my $ipn = AnyEvent::Socket::parse_address ($s)) {
866 root 1.32 push @{ $self->{server} }, $ipn;
867     } else {
868     push @{ $self->{search} }, $s;
869 root 1.14 }
870     }
871     }
872    
873 root 1.32 # always add one fallback server
874     push @{ $self->{server} }, $DNS_FALLBACK[rand @DNS_FALLBACK];
875 root 1.14
876     $self->_compile;
877     }
878     } else {
879     # try resolv.conf everywhere
880 root 1.1
881 root 1.14 if (open my $fh, "</etc/resolv.conf") {
882     local $/;
883     $self->parse_resolv_conf (<$fh>);
884     }
885     }
886 root 1.1 }
887    
888 root 1.53 =item $resolver->timeout ($timeout, ...)
889    
890     Sets the timeout values. See the C<timeout> constructor argument (and note
891 root 1.54 that this method uses the values itself, not an array-reference).
892 root 1.53
893     =cut
894    
895     sub timeout {
896     my ($self, @timeout) = @_;
897    
898     $self->{timeout} = \@timeout;
899     $self->_compile;
900     }
901    
902     =item $resolver->max_outstanding ($nrequests)
903    
904     Sets the maximum number of outstanding requests to C<$nrequests>. See the
905     C<max_outstanding> constructor argument.
906    
907     =cut
908    
909     sub max_outstanding {
910     my ($self, $max) = @_;
911    
912     $self->{max_outstanding} = $max;
913     $self->_scheduler;
914     }
915    
916 root 1.1 sub _compile {
917     my $self = shift;
918    
919 root 1.38 my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
920     my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
921 root 1.32
922     unless (@{ $self->{server} }) {
923     # use 127.0.0.1 by default, and one opendns nameserver as fallback
924     $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
925     }
926    
927 root 1.1 my @retry;
928    
929     for my $timeout (@{ $self->{timeout} }) {
930     for my $server (@{ $self->{server} }) {
931     push @retry, [$server, $timeout];
932     }
933     }
934    
935     $self->{retry} = \@retry;
936     }
937    
938 root 1.6 sub _feed {
939     my ($self, $res) = @_;
940    
941     $res = dns_unpack $res
942     or return;
943    
944     my $id = $self->{id}{$res->{id}};
945    
946     return unless ref $id;
947    
948     $NOW = time;
949     $id->[1]->($res);
950     }
951    
952 root 1.1 sub _recv {
953 root 1.38 my ($self, $pkt, $peer) = @_;
954 root 1.1
955 root 1.32 # we ignore errors (often one gets port unreachable, but there is
956     # no good way to take advantage of that.
957 root 1.1
958 root 1.38 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
959    
960     return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
961 root 1.1
962 root 1.38 $self->_feed ($pkt);
963 root 1.1 }
964    
965 root 1.22 sub _free_id {
966     my ($self, $id, $timeout) = @_;
967    
968     if ($timeout) {
969     # we need to block the id for a while
970     $self->{id}{$id} = 1;
971     push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
972     } else {
973     # we can quickly recycle the id
974     delete $self->{id}{$id};
975     }
976    
977     --$self->{outstanding};
978     $self->_scheduler;
979     }
980    
981     # execute a single request, involves sending it with timeouts to multiple servers
982 root 1.1 sub _exec {
983 root 1.22 my ($self, $req) = @_;
984    
985     my $retry; # of retries
986     my $do_retry;
987    
988     $do_retry = sub {
989     my $retry_cfg = $self->{retry}[$retry++]
990     or do {
991     # failure
992     $self->_free_id ($req->[2], $retry > 1);
993     undef $do_retry; return $req->[1]->();
994     };
995 root 1.1
996     my ($server, $timeout) = @$retry_cfg;
997    
998     $self->{id}{$req->[2]} = [AnyEvent->timer (after => $timeout, cb => sub {
999     $NOW = time;
1000    
1001     # timeout, try next
1002 root 1.22 &$do_retry;
1003 root 1.1 }), sub {
1004     my ($res) = @_;
1005    
1006 root 1.6 if ($res->{tc}) {
1007     # success, but truncated, so use tcp
1008 root 1.38 AnyEvent::Socket::tcp_connect (AnyEvent::Socket::format_address ($server), DOMAIN_PORT, sub {
1009 root 1.52 return unless $do_retry; # some other request could have invalidated us already
1010    
1011 root 1.6 my ($fh) = @_
1012 root 1.22 or return &$do_retry;
1013 root 1.6
1014 root 1.52 my $handle; $handle = new AnyEvent::Handle
1015 root 1.6 fh => $fh,
1016 root 1.52 timeout => $timeout,
1017 root 1.6 on_error => sub {
1018 root 1.52 undef $handle;
1019     return unless $do_retry; # some other request could have invalidated us already
1020 root 1.6 # failure, try next
1021 root 1.22 &$do_retry;
1022 root 1.6 };
1023    
1024     $handle->push_write (pack "n/a", $req->[0]);
1025 root 1.27 $handle->push_read (chunk => 2, sub {
1026     $handle->unshift_read (chunk => (unpack "n", $_[1]), sub {
1027 root 1.52 undef $handle;
1028 root 1.6 $self->_feed ($_[1]);
1029     });
1030     });
1031    
1032 root 1.17 }, sub { $timeout });
1033 root 1.1
1034 root 1.6 } else {
1035     # success
1036 root 1.22 $self->_free_id ($req->[2], $retry > 1);
1037     undef $do_retry; return $req->[1]->($res);
1038 root 1.6 }
1039 root 1.1 }];
1040 root 1.38
1041     my $sa = AnyEvent::Socket::pack_sockaddr (DOMAIN_PORT, $server);
1042    
1043 root 1.39 my $fh = AF_INET == Socket::sockaddr_family ($sa)
1044 root 1.38 ? $self->{fh4} : $self->{fh6}
1045     or return &$do_retry;
1046 root 1.1
1047 root 1.38 send $fh, $req->[0], 0, $sa;
1048 root 1.22 };
1049 root 1.1
1050 root 1.22 &$do_retry;
1051 root 1.1 }
1052    
1053     sub _scheduler {
1054     my ($self) = @_;
1055    
1056 root 1.51 no strict 'refs';
1057    
1058 root 1.1 $NOW = time;
1059    
1060     # first clear id reuse queue
1061     delete $self->{id}{ (shift @{ $self->{reuse_q} })->[1] }
1062 root 1.13 while @{ $self->{reuse_q} } && $self->{reuse_q}[0][0] <= $NOW;
1063 root 1.1
1064     while ($self->{outstanding} < $self->{max_outstanding}) {
1065 root 1.13
1066     if (@{ $self->{reuse_q} } >= 30000) {
1067     # we ran out of ID's, wait a bit
1068     $self->{reuse_to} ||= AnyEvent->timer (after => $self->{reuse_q}[0][0] - $NOW, cb => sub {
1069     delete $self->{reuse_to};
1070     $self->_scheduler;
1071     });
1072     last;
1073     }
1074    
1075 root 1.51 if (my $req = shift @{ $self->{queue} }) {
1076     # found a request in the queue, execute it
1077     while () {
1078     $req->[2] = int rand 65536;
1079     last unless exists $self->{id}{$req->[2]};
1080     }
1081    
1082     ++$self->{outstanding};
1083     $self->{id}{$req->[2]} = 1;
1084     substr $req->[0], 0, 2, pack "n", $req->[2];
1085    
1086     $self->_exec ($req);
1087    
1088     } elsif (my $cb = shift @{ $self->{wait} }) {
1089     # found a wait_for_slot callback, call that one first
1090     $cb->($self);
1091 root 1.1
1092 root 1.51 } else {
1093     # nothing to do, just exit
1094     last;
1095 root 1.1 }
1096     }
1097     }
1098    
1099     =item $resolver->request ($req, $cb->($res))
1100    
1101 root 1.54 This is the main low-level workhorse for sending DNS requests.
1102    
1103     This function sends a single request (a hash-ref formated as specified
1104     for C<dns_pack>) to the configured nameservers in turn until it gets a
1105     response. It handles timeouts, retries and automatically falls back to
1106     virtual circuit mode (TCP) when it receives a truncated reply.
1107    
1108     Calls the callback with the decoded response packet if a reply was
1109     received, or no arguments in case none of the servers answered.
1110 root 1.1
1111     =cut
1112    
1113     sub request($$) {
1114     my ($self, $req, $cb) = @_;
1115    
1116 root 1.3 push @{ $self->{queue} }, [dns_pack $req, $cb];
1117 root 1.1 $self->_scheduler;
1118     }
1119    
1120     =item $resolver->resolve ($qname, $qtype, %options, $cb->($rcode, @rr))
1121    
1122 root 1.44 Queries the DNS for the given domain name C<$qname> of type C<$qtype>.
1123    
1124 root 1.54 A C<$qtype> is either a numerical query type (e.g. C<1> for A records) or
1125 root 1.44 a lowercase name (you have to look at the source to see which aliases are
1126 root 1.50 supported, but all types from RFC 1035, C<aaaa>, C<srv>, C<spf> and a few
1127 root 1.54 more are known to this module). A C<$qtype> of "*" is supported and means
1128 root 1.44 "any" record type.
1129 root 1.1
1130     The callback will be invoked with a list of matching result records or
1131     none on any error or if the name could not be found.
1132    
1133 root 1.61 CNAME chains (although illegal) are followed up to a length of 10.
1134 root 1.1
1135 root 1.44 The callback will be invoked with an result code in string form (noerror,
1136     formerr, servfail, nxdomain, notimp, refused and so on), or numerical
1137     form if the result code is not supported. The remaining arguments are
1138     arraryefs of the form C<[$name, $type, $class, @data>], where C<$name> is
1139     the domain name, C<$type> a type string or number, C<$class> a class name
1140     and @data is resource-record-dependent data. For C<a> records, this will
1141     be the textual IPv4 addresses, for C<ns> or C<cname> records this will be
1142     a domain name, for C<txt> records these are all the strings and so on.
1143    
1144 root 1.55 All types mentioned in RFC 1035, C<aaaa>, C<srv>, C<naptr> and C<spf> are
1145     decoded. All resource records not known to this module will have
1146 root 1.44 the raw C<rdata> field as fourth entry.
1147    
1148 root 1.24 Note that this resolver is just a stub resolver: it requires a name server
1149 root 1.3 supporting recursive queries, will not do any recursive queries itself and
1150     is not secure when used against an untrusted name server.
1151    
1152 root 1.1 The following options are supported:
1153    
1154     =over 4
1155    
1156     =item search => [$suffix...]
1157    
1158     Use the given search list (which might be empty), by appending each one
1159     in turn to the C<$qname>. If this option is missing then the configured
1160 root 1.55 C<ndots> and C<search> values define its value (depending on C<ndots>, the
1161     empty suffix will be prepended or appended to that C<search> value). If
1162     the C<$qname> ends in a dot, then the searchlist will be ignored.
1163 root 1.1
1164     =item accept => [$type...]
1165    
1166     Lists the acceptable result types: only result types in this set will be
1167     accepted and returned. The default includes the C<$qtype> and nothing
1168 root 1.44 else. If this list includes C<cname>, then CNAME-chains will not be
1169     followed (because you asked for the CNAME record).
1170 root 1.1
1171     =item class => "class"
1172    
1173     Specify the query class ("in" for internet, "ch" for chaosnet and "hs" for
1174 root 1.2 hesiod are the only ones making sense). The default is "in", of course.
1175 root 1.1
1176     =back
1177    
1178     Examples:
1179    
1180 root 1.46 # full example, you can paste this into perl:
1181 root 1.45 use Data::Dumper;
1182     use AnyEvent::DNS;
1183     AnyEvent::DNS::resolver->resolve (
1184     "google.com", "*", my $cv = AnyEvent->condvar);
1185     warn Dumper [$cv->recv];
1186    
1187     # shortened result:
1188     # [
1189     # [ 'google.com', 'soa', 'in', 'ns1.google.com', 'dns-admin.google.com',
1190     # 2008052701, 7200, 1800, 1209600, 300 ],
1191     # [
1192     # 'google.com', 'txt', 'in',
1193     # 'v=spf1 include:_netblocks.google.com ~all'
1194     # ],
1195     # [ 'google.com', 'a', 'in', '64.233.187.99' ],
1196     # [ 'google.com', 'mx', 'in', 10, 'smtp2.google.com' ],
1197     # [ 'google.com', 'ns', 'in', 'ns2.google.com' ],
1198     # ]
1199    
1200     # resolve a records:
1201     $res->resolve ("ruth.plan9.de", "a", sub { warn Dumper [@_] });
1202    
1203     # result:
1204     # [
1205     # [ 'ruth.schmorp.de', 'a', 'in', '129.13.162.95' ]
1206     # ]
1207 root 1.1
1208 root 1.45 # resolve any records, but return only a and aaaa records:
1209 root 1.1 $res->resolve ("test1.laendle", "*",
1210     accept => ["a", "aaaa"],
1211     sub {
1212     warn Dumper [@_];
1213     }
1214     );
1215    
1216 root 1.45 # result:
1217     # [
1218     # [ 'test1.laendle', 'a', 'in', '10.0.0.255' ],
1219     # [ 'test1.laendle', 'aaaa', 'in', '3ffe:1900:4545:0002:0240:0000:0000:f7e1' ]
1220     # ]
1221 root 1.1
1222     =cut
1223    
1224     sub resolve($%) {
1225     my $cb = pop;
1226     my ($self, $qname, $qtype, %opt) = @_;
1227    
1228     my @search = $qname =~ s/\.$//
1229     ? ""
1230     : $opt{search}
1231     ? @{ $opt{search} }
1232     : ($qname =~ y/.//) >= $self->{ndots}
1233     ? ("", @{ $self->{search} })
1234     : (@{ $self->{search} }, "");
1235    
1236     my $class = $opt{class} || "in";
1237    
1238     my %atype = $opt{accept}
1239     ? map +($_ => 1), @{ $opt{accept} }
1240     : ($qtype => 1);
1241    
1242     # advance in searchlist
1243 root 1.22 my ($do_search, $do_req);
1244    
1245     $do_search = sub {
1246 root 1.1 @search
1247 root 1.22 or (undef $do_search), (undef $do_req), return $cb->();
1248 root 1.1
1249 root 1.4 (my $name = lc "$qname." . shift @search) =~ s/\.$//;
1250 root 1.61 my $depth = 10;
1251 root 1.1
1252     # advance in cname-chain
1253 root 1.22 $do_req = sub {
1254 root 1.1 $self->request ({
1255     rd => 1,
1256     qd => [[$name, $qtype, $class]],
1257     }, sub {
1258     my ($res) = @_
1259     or return $do_search->();
1260    
1261     my $cname;
1262    
1263     while () {
1264 root 1.2 # results found?
1265 root 1.4 my @rr = grep $name eq lc $_->[0] && ($atype{"*"} || $atype{$_->[1]}), @{ $res->{an} };
1266 root 1.1
1267 root 1.22 (undef $do_search), (undef $do_req), return $cb->(@rr)
1268 root 1.1 if @rr;
1269    
1270     # see if there is a cname we can follow
1271 root 1.4 my @rr = grep $name eq lc $_->[0] && $_->[1] eq "cname", @{ $res->{an} };
1272 root 1.1
1273     if (@rr) {
1274     $depth--
1275     or return $do_search->(); # cname chain too long
1276    
1277     $cname = 1;
1278     $name = $rr[0][3];
1279    
1280     } elsif ($cname) {
1281     # follow the cname
1282     return $do_req->();
1283    
1284     } else {
1285 root 1.2 # no, not found anything
1286 root 1.1 return $do_search->();
1287     }
1288     }
1289     });
1290     };
1291    
1292     $do_req->();
1293     };
1294    
1295     $do_search->();
1296     }
1297    
1298 root 1.51 =item $resolver->wait_for_slot ($cb->($resolver))
1299    
1300     Wait until a free request slot is available and call the callback with the
1301     resolver object.
1302    
1303     A request slot is used each time a request is actually sent to the
1304     nameservers: There are never more than C<max_outstanding> of them.
1305    
1306     Although you can submit more requests (they will simply be queued until
1307     a request slot becomes available), sometimes, usually for rate-limiting
1308     purposes, it is useful to instead wait for a slot before generating the
1309     request (or simply to know when the request load is low enough so one can
1310     submit requests again).
1311    
1312     This is what this method does: The callback will be called when submitting
1313     a DNS request will not result in that request being queued. The callback
1314     may or may not generate any requests in response.
1315    
1316     Note that the callback will only be invoked when the request queue is
1317     empty, so this does not play well if somebody else keeps the request queue
1318     full at all times.
1319    
1320     =cut
1321    
1322     sub wait_for_slot {
1323     my ($self, $cb) = @_;
1324    
1325     push @{ $self->{wait} }, $cb;
1326     $self->_scheduler;
1327     }
1328    
1329 root 1.17 use AnyEvent::Socket (); # circular dependency, so do not import anything and do it at the end
1330    
1331 root 1.1 1;
1332    
1333     =back
1334    
1335     =head1 AUTHOR
1336    
1337 root 1.58 Marc Lehmann <schmorp@schmorp.de>
1338     http://home.schmorp.de/
1339 root 1.1
1340     =cut
1341