ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.47
Committed: Thu May 29 17:51:33 2008 UTC (16 years, 1 month ago) by root
Branch: MAIN
Changes since 1.46: +6 -0 lines
Log Message:
naptr

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