ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.43
Committed: Thu May 29 06:19:22 2008 UTC (16 years, 1 month ago) by root
Branch: MAIN
Changes since 1.42: +5 -4 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::DNS - fully asynchronous DNS resolution
4    
5     =head1 SYNOPSIS
6    
7     use AnyEvent::DNS;
8    
9 root 1.26 my $cv = AnyEvent->condvar;
10 root 1.30 AnyEvent::DNS::a "www.google.de", $cv;
11 root 1.26 # ... later
12     my @addrs = $cv->recv;
13    
14 root 1.1 =head1 DESCRIPTION
15    
16     This module offers both a number of DNS convenience functions as well
17     as a fully asynchronous and high-performance pure-perl stub resolver.
18    
19 root 1.12 The stub resolver supports DNS over UDP, optional EDNS0 support for up to
20     4kiB datagrams and automatically falls back to virtual circuit mode for
21     large responses.
22    
23 root 1.1 =head2 CONVENIENCE FUNCTIONS
24    
25     =over 4
26    
27     =cut
28    
29     package AnyEvent::DNS;
30    
31 root 1.3 no warnings;
32 root 1.1 use strict;
33    
34 root 1.29 use Socket qw(AF_INET SOCK_DGRAM SOCK_STREAM);
35    
36 root 1.35 use AnyEvent ();
37 root 1.6 use AnyEvent::Handle ();
38 root 1.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.5 opt => 41,
254     spf => 99,
255     tkey => 249,
256     tsig => 250,
257     ixfr => 251,
258 root 1.1 axfr => 252,
259     mailb => 253,
260     "*" => 255,
261     );
262    
263     our %type_str = reverse %type_id;
264    
265     our %class_id = (
266 root 1.5 in => 1,
267     ch => 3,
268     hs => 4,
269     none => 254,
270     "*" => 255,
271 root 1.1 );
272    
273     our %class_str = reverse %class_id;
274    
275     # names MUST have a trailing dot
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.11 $EDNS0 + scalar @{ $req->{ar} || [] }, # include EDNS0 option 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.38 ($EDNS0 ? pack "C nnNn", 0, 41, MAX_PKT, 0, 0 : "") # EDNS0, 4kiB udp payload size
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.29 99 => sub { unpack "(C/a*)*", $_ }, # spf
408 root 1.1 );
409    
410     sub _dec_rr {
411 root 1.34 my $name = _dec_name;
412 root 1.1
413     my ($rt, $rc, $ttl, $rdlen) = unpack "nn N n", substr $pkt, $ofs; $ofs += 10;
414     local $_ = substr $pkt, $ofs, $rdlen; $ofs += $rdlen;
415    
416     [
417 root 1.34 $name,
418 root 1.1 $type_str{$rt} || $rt,
419     $class_str{$rc} || $rc,
420     ($dec_rr{$rt} || sub { $_ })->(),
421     ]
422     }
423    
424     =item $dns = AnyEvent::DNS::dns_unpack $pkt
425    
426     Unpacks a DNS packet into a perl data structure.
427    
428     Examples:
429    
430 root 1.13 # an unsuccessful reply
431 root 1.1 {
432     'qd' => [
433     [ 'ruth.plan9.de.mach.uni-karlsruhe.de', '*', 'in' ]
434     ],
435     'rc' => 'nxdomain',
436     'ar' => [],
437     'ns' => [
438     [
439     'uni-karlsruhe.de',
440     'soa',
441     'in',
442     'netserv.rz.uni-karlsruhe.de',
443     'hostmaster.rz.uni-karlsruhe.de',
444 root 1.13 2008052201, 10800, 1800, 2592000, 86400
445 root 1.1 ]
446     ],
447     'tc' => '',
448     'ra' => 1,
449     'qr' => 1,
450     'id' => 45915,
451     'aa' => '',
452     'an' => [],
453     'rd' => 1,
454     'op' => 'query'
455     }
456    
457     # a successful reply
458    
459     {
460     'qd' => [ [ 'www.google.de', 'a', 'in' ] ],
461     'rc' => 0,
462     'ar' => [
463     [ 'a.l.google.com', 'a', 'in', '209.85.139.9' ],
464     [ 'b.l.google.com', 'a', 'in', '64.233.179.9' ],
465     [ 'c.l.google.com', 'a', 'in', '64.233.161.9' ],
466     ],
467     'ns' => [
468     [ 'l.google.com', 'ns', 'in', 'a.l.google.com' ],
469     [ 'l.google.com', 'ns', 'in', 'b.l.google.com' ],
470     ],
471     'tc' => '',
472     'ra' => 1,
473     'qr' => 1,
474     'id' => 64265,
475     'aa' => '',
476     'an' => [
477     [ 'www.google.de', 'cname', 'in', 'www.google.com' ],
478     [ 'www.google.com', 'cname', 'in', 'www.l.google.com' ],
479     [ 'www.l.google.com', 'a', 'in', '66.249.93.104' ],
480     [ 'www.l.google.com', 'a', 'in', '66.249.93.147' ],
481     ],
482     'rd' => 1,
483     'op' => 0
484     }
485    
486     =cut
487    
488     sub dns_unpack($) {
489     local $pkt = shift;
490     my ($id, $flags, $qd, $an, $ns, $ar)
491     = unpack "nn nnnn A*", $pkt;
492    
493     local $ofs = 6 * 2;
494    
495     {
496     id => $id,
497     qr => ! ! ($flags & 0x8000),
498     aa => ! ! ($flags & 0x0400),
499     tc => ! ! ($flags & 0x0200),
500     rd => ! ! ($flags & 0x0100),
501     ra => ! ! ($flags & 0x0080),
502 root 1.5 ad => ! ! ($flags & 0x0020),
503     cd => ! ! ($flags & 0x0010),
504 root 1.1 op => $opcode_str{($flags & 0x001e) >> 11},
505     rc => $rcode_str{($flags & 0x000f)},
506    
507     qd => [map _dec_qd, 1 .. $qd],
508     an => [map _dec_rr, 1 .. $an],
509     ns => [map _dec_rr, 1 .. $ns],
510     ar => [map _dec_rr, 1 .. $ar],
511     }
512     }
513    
514     #############################################################################
515    
516     =back
517    
518     =head2 THE AnyEvent::DNS RESOLVER CLASS
519    
520 root 1.13 This is the class which does the actual protocol work.
521 root 1.1
522     =over 4
523    
524     =cut
525    
526     use Carp ();
527     use Scalar::Util ();
528     use Socket ();
529    
530     our $NOW;
531    
532 root 1.2 =item AnyEvent::DNS::resolver
533    
534     This function creates and returns a resolver that is ready to use and
535     should mimic the default resolver for your system as good as possible.
536    
537     It only ever creates one resolver and returns this one on subsequent
538     calls.
539    
540     Unless you have special needs, prefer this function over creating your own
541     resolver object.
542    
543     =cut
544    
545     our $RESOLVER;
546    
547     sub resolver() {
548     $RESOLVER || do {
549     $RESOLVER = new AnyEvent::DNS;
550 root 1.14 $RESOLVER->os_config;
551 root 1.2 $RESOLVER
552     }
553     }
554    
555 root 1.1 =item $resolver = new AnyEvent::DNS key => value...
556    
557 root 1.6 Creates and returns a new resolver.
558 root 1.2
559     The following options are supported:
560 root 1.1
561     =over 4
562    
563     =item server => [...]
564    
565 root 1.41 A list of server addresses (default: C<v127.0.0.1>) in network format
566 root 1.42 (i.e. as returned by C<AnyEvent::Socket::parse_address> - both IPv4 and
567 root 1.41 IPv6 are supported).
568 root 1.1
569     =item timeout => [...]
570    
571     A list of timeouts to use (also determines the number of retries). To make
572     three retries with individual time-outs of 2, 5 and 5 seconds, use C<[2,
573     5, 5]>, which is also the default.
574    
575     =item search => [...]
576    
577     The default search list of suffixes to append to a domain name (default: none).
578    
579 root 1.2 =item ndots => $integer
580 root 1.1
581     The number of dots (default: C<1>) that a name must have so that the resolver
582     tries to resolve the name without any suffixes first.
583    
584 root 1.2 =item max_outstanding => $integer
585 root 1.1
586 root 1.43 Most name servers do not handle many parallel requests very well. This
587     option limits the number of outstanding requests to C<$integer>
588     (default: C<10>), that means if you request more than this many requests,
589     then the additional requests will be queued until some other requests have
590     been resolved.
591 root 1.1
592 root 1.13 =item reuse => $seconds
593    
594 root 1.22 The number of seconds (default: C<300>) that a query id cannot be re-used
595     after a timeout. If there as no time-out then query id's can be reused
596     immediately.
597 root 1.13
598 root 1.1 =back
599    
600     =cut
601    
602     sub new {
603     my ($class, %arg) = @_;
604    
605 root 1.38 # try to create a ipv4 and an ipv6 socket
606     # only fail when we cnanot create either
607 root 1.1
608 root 1.38 socket my $fh4, AF_INET , &Socket::SOCK_DGRAM, 0;
609     socket my $fh6, AF_INET6, &Socket::SOCK_DGRAM, 0;
610    
611     $fh4 || $fh6
612     or Carp::croak "unable to create either an IPv6 or an IPv4 socket";
613 root 1.1
614     my $self = bless {
615 root 1.32 server => [],
616 root 1.1 timeout => [2, 5, 5],
617     search => [],
618     ndots => 1,
619     max_outstanding => 10,
620 root 1.22 reuse => 300, # reuse id's after 5 minutes only, if possible
621 root 1.1 %arg,
622     reuse_q => [],
623     }, $class;
624    
625     # search should default to gethostname's domain
626     # but perl lacks a good posix module
627    
628     Scalar::Util::weaken (my $wself = $self);
629 root 1.38
630     if ($fh4) {
631     AnyEvent::Util::fh_nonblocking $fh4, 1;
632     $self->{fh4} = $fh4;
633     $self->{rw4} = AnyEvent->io (fh => $fh4, poll => "r", cb => sub {
634     if (my $peer = recv $fh4, my $pkt, MAX_PKT, 0) {
635     $wself->_recv ($pkt, $peer);
636     }
637     });
638     }
639    
640     if ($fh6) {
641     $self->{fh6} = $fh6;
642     AnyEvent::Util::fh_nonblocking $fh6, 1;
643     $self->{rw6} = AnyEvent->io (fh => $fh6, poll => "r", cb => sub {
644     if (my $peer = recv $fh6, my $pkt, MAX_PKT, 0) {
645     $wself->_recv ($pkt, $peer);
646     }
647     });
648     }
649 root 1.1
650     $self->_compile;
651    
652     $self
653     }
654    
655     =item $resolver->parse_resolv_conv ($string)
656    
657 root 1.24 Parses the given string as if it were a F<resolv.conf> file. The following
658     directives are supported (but not necessarily implemented).
659 root 1.1
660     C<#>-style comments, C<nameserver>, C<domain>, C<search>, C<sortlist>,
661     C<options> (C<timeout>, C<attempts>, C<ndots>).
662    
663     Everything else is silently ignored.
664    
665     =cut
666    
667     sub parse_resolv_conf {
668     my ($self, $resolvconf) = @_;
669    
670     $self->{server} = [];
671     $self->{search} = [];
672    
673     my $attempts;
674    
675     for (split /\n/, $resolvconf) {
676     if (/^\s*#/) {
677     # comment
678     } elsif (/^\s*nameserver\s+(\S+)\s*$/i) {
679     my $ip = $1;
680 root 1.36 if (my $ipn = AnyEvent::Socket::parse_address ($ip)) {
681 root 1.25 push @{ $self->{server} }, $ipn;
682 root 1.1 } else {
683     warn "nameserver $ip invalid and ignored\n";
684     }
685     } elsif (/^\s*domain\s+(\S*)\s+$/i) {
686     $self->{search} = [$1];
687     } elsif (/^\s*search\s+(.*?)\s*$/i) {
688     $self->{search} = [split /\s+/, $1];
689     } elsif (/^\s*sortlist\s+(.*?)\s*$/i) {
690     # ignored, NYI
691     } elsif (/^\s*options\s+(.*?)\s*$/i) {
692     for (split /\s+/, $1) {
693     if (/^timeout:(\d+)$/) {
694     $self->{timeout} = [$1];
695     } elsif (/^attempts:(\d+)$/) {
696     $attempts = $1;
697     } elsif (/^ndots:(\d+)$/) {
698     $self->{ndots} = $1;
699     } else {
700     # debug, rotate, no-check-names, inet6
701     }
702     }
703     }
704     }
705    
706     $self->{timeout} = [($self->{timeout}[0]) x $attempts]
707     if $attempts;
708    
709     $self->_compile;
710     }
711    
712 root 1.14 =item $resolver->os_config
713 root 1.1
714 root 1.24 Tries so load and parse F</etc/resolv.conf> on portable operating systems. Tries various
715     egregious hacks on windows to force the DNS servers and searchlist out of the system.
716 root 1.1
717     =cut
718    
719 root 1.14 sub os_config {
720 root 1.1 my ($self) = @_;
721    
722 root 1.32 $self->{server} = [];
723     $self->{search} = [];
724    
725 root 1.35 if (AnyEvent::WIN32 || $^O =~ /cygwin/i) {
726 root 1.32 no strict 'refs';
727    
728     # there are many options to find the current nameservers etc. on windows
729     # all of them don't work consistently:
730     # - the registry thing needs separate code on win32 native vs. cygwin
731     # - the registry layout differs between windows versions
732     # - calling windows api functions doesn't work on cygwin
733     # - ipconfig uses locale-specific messages
734    
735     # we use ipconfig parsing because, despite all it's brokenness,
736     # it seems most stable in practise.
737     # for good measure, we append a fallback nameserver to our list.
738 root 1.14
739     if (open my $fh, "ipconfig /all |") {
740 root 1.32 # parsing strategy: we go through the output and look for
741     # :-lines with DNS in them. everything in those is regarded as
742     # either a nameserver (if it parses as an ip address), or a suffix
743     # (all else).
744 root 1.14
745 root 1.32 my $dns;
746 root 1.14 while (<$fh>) {
747 root 1.32 if (s/^\s.*\bdns\b.*://i) {
748     $dns = 1;
749     } elsif (/^\S/ || /^\s[^:]{16,}: /) {
750     $dns = 0;
751     }
752     if ($dns && /^\s*(\S+)\s*$/) {
753     my $s = $1;
754     $s =~ s/%\d+(?!\S)//; # get rid of scope id
755 root 1.36 if (my $ipn = AnyEvent::Socket::parse_address ($s)) {
756 root 1.32 push @{ $self->{server} }, $ipn;
757     } else {
758     push @{ $self->{search} }, $s;
759 root 1.14 }
760     }
761     }
762    
763 root 1.32 # always add one fallback server
764     push @{ $self->{server} }, $DNS_FALLBACK[rand @DNS_FALLBACK];
765 root 1.14
766     $self->_compile;
767     }
768     } else {
769     # try resolv.conf everywhere
770 root 1.1
771 root 1.14 if (open my $fh, "</etc/resolv.conf") {
772     local $/;
773     $self->parse_resolv_conf (<$fh>);
774     }
775     }
776 root 1.1 }
777    
778     sub _compile {
779     my $self = shift;
780    
781 root 1.38 my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
782     my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
783 root 1.32
784     unless (@{ $self->{server} }) {
785     # use 127.0.0.1 by default, and one opendns nameserver as fallback
786     $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
787     }
788    
789 root 1.1 my @retry;
790    
791     for my $timeout (@{ $self->{timeout} }) {
792     for my $server (@{ $self->{server} }) {
793     push @retry, [$server, $timeout];
794     }
795     }
796    
797     $self->{retry} = \@retry;
798     }
799    
800 root 1.6 sub _feed {
801     my ($self, $res) = @_;
802    
803     $res = dns_unpack $res
804     or return;
805    
806     my $id = $self->{id}{$res->{id}};
807    
808     return unless ref $id;
809    
810     $NOW = time;
811     $id->[1]->($res);
812     }
813    
814 root 1.1 sub _recv {
815 root 1.38 my ($self, $pkt, $peer) = @_;
816 root 1.1
817 root 1.32 # we ignore errors (often one gets port unreachable, but there is
818     # no good way to take advantage of that.
819 root 1.1
820 root 1.38 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
821    
822     return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
823 root 1.1
824 root 1.38 $self->_feed ($pkt);
825 root 1.1 }
826    
827 root 1.22 sub _free_id {
828     my ($self, $id, $timeout) = @_;
829    
830     if ($timeout) {
831     # we need to block the id for a while
832     $self->{id}{$id} = 1;
833     push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
834     } else {
835     # we can quickly recycle the id
836     delete $self->{id}{$id};
837     }
838    
839     --$self->{outstanding};
840     $self->_scheduler;
841     }
842    
843     # execute a single request, involves sending it with timeouts to multiple servers
844 root 1.1 sub _exec {
845 root 1.22 my ($self, $req) = @_;
846    
847     my $retry; # of retries
848     my $do_retry;
849    
850     $do_retry = sub {
851     my $retry_cfg = $self->{retry}[$retry++]
852     or do {
853     # failure
854     $self->_free_id ($req->[2], $retry > 1);
855     undef $do_retry; return $req->[1]->();
856     };
857 root 1.1
858     my ($server, $timeout) = @$retry_cfg;
859    
860     $self->{id}{$req->[2]} = [AnyEvent->timer (after => $timeout, cb => sub {
861     $NOW = time;
862    
863     # timeout, try next
864 root 1.22 &$do_retry;
865 root 1.1 }), sub {
866     my ($res) = @_;
867    
868 root 1.6 if ($res->{tc}) {
869     # success, but truncated, so use tcp
870 root 1.38 AnyEvent::Socket::tcp_connect (AnyEvent::Socket::format_address ($server), DOMAIN_PORT, sub {
871 root 1.6 my ($fh) = @_
872 root 1.22 or return &$do_retry;
873 root 1.6
874     my $handle = new AnyEvent::Handle
875     fh => $fh,
876     on_error => sub {
877     # failure, try next
878 root 1.22 &$do_retry;
879 root 1.6 };
880    
881     $handle->push_write (pack "n/a", $req->[0]);
882 root 1.27 $handle->push_read (chunk => 2, sub {
883     $handle->unshift_read (chunk => (unpack "n", $_[1]), sub {
884 root 1.6 $self->_feed ($_[1]);
885     });
886     });
887     shutdown $fh, 1;
888    
889 root 1.17 }, sub { $timeout });
890 root 1.1
891 root 1.6 } else {
892     # success
893 root 1.22 $self->_free_id ($req->[2], $retry > 1);
894     undef $do_retry; return $req->[1]->($res);
895 root 1.6 }
896 root 1.1 }];
897 root 1.38
898     my $sa = AnyEvent::Socket::pack_sockaddr (DOMAIN_PORT, $server);
899    
900 root 1.39 my $fh = AF_INET == Socket::sockaddr_family ($sa)
901 root 1.38 ? $self->{fh4} : $self->{fh6}
902     or return &$do_retry;
903 root 1.1
904 root 1.38 send $fh, $req->[0], 0, $sa;
905 root 1.22 };
906 root 1.1
907 root 1.22 &$do_retry;
908 root 1.1 }
909    
910     sub _scheduler {
911     my ($self) = @_;
912    
913     $NOW = time;
914    
915     # first clear id reuse queue
916     delete $self->{id}{ (shift @{ $self->{reuse_q} })->[1] }
917 root 1.13 while @{ $self->{reuse_q} } && $self->{reuse_q}[0][0] <= $NOW;
918 root 1.1
919     while ($self->{outstanding} < $self->{max_outstanding}) {
920 root 1.13
921     if (@{ $self->{reuse_q} } >= 30000) {
922     # we ran out of ID's, wait a bit
923     $self->{reuse_to} ||= AnyEvent->timer (after => $self->{reuse_q}[0][0] - $NOW, cb => sub {
924     delete $self->{reuse_to};
925     $self->_scheduler;
926     });
927     last;
928     }
929    
930 root 1.1 my $req = shift @{ $self->{queue} }
931     or last;
932    
933     while () {
934     $req->[2] = int rand 65536;
935     last unless exists $self->{id}{$req->[2]};
936     }
937    
938 root 1.22 ++$self->{outstanding};
939 root 1.1 $self->{id}{$req->[2]} = 1;
940     substr $req->[0], 0, 2, pack "n", $req->[2];
941    
942 root 1.22 $self->_exec ($req);
943 root 1.1 }
944     }
945    
946     =item $resolver->request ($req, $cb->($res))
947    
948     Sends a single request (a hash-ref formated as specified for
949 root 1.3 C<dns_pack>) to the configured nameservers including
950 root 1.1 retries. Calls the callback with the decoded response packet if a reply
951     was received, or no arguments on timeout.
952    
953     =cut
954    
955     sub request($$) {
956     my ($self, $req, $cb) = @_;
957    
958 root 1.3 push @{ $self->{queue} }, [dns_pack $req, $cb];
959 root 1.1 $self->_scheduler;
960     }
961    
962     =item $resolver->resolve ($qname, $qtype, %options, $cb->($rcode, @rr))
963    
964     Queries the DNS for the given domain name C<$qname> of type C<$qtype> (a
965     qtype of "*" is supported and means "any").
966    
967     The callback will be invoked with a list of matching result records or
968     none on any error or if the name could not be found.
969    
970     CNAME chains (although illegal) are followed up to a length of 8.
971    
972 root 1.24 Note that this resolver is just a stub resolver: it requires a name server
973 root 1.3 supporting recursive queries, will not do any recursive queries itself and
974     is not secure when used against an untrusted name server.
975    
976 root 1.1 The following options are supported:
977    
978     =over 4
979    
980     =item search => [$suffix...]
981    
982     Use the given search list (which might be empty), by appending each one
983     in turn to the C<$qname>. If this option is missing then the configured
984     C<ndots> and C<search> define its value. If the C<$qname> ends in a dot,
985 root 1.2 then the searchlist will be ignored.
986 root 1.1
987     =item accept => [$type...]
988    
989     Lists the acceptable result types: only result types in this set will be
990     accepted and returned. The default includes the C<$qtype> and nothing
991     else.
992    
993     =item class => "class"
994    
995     Specify the query class ("in" for internet, "ch" for chaosnet and "hs" for
996 root 1.2 hesiod are the only ones making sense). The default is "in", of course.
997 root 1.1
998     =back
999    
1000     Examples:
1001    
1002     $res->resolve ("ruth.plan9.de", "a", sub {
1003     warn Dumper [@_];
1004     });
1005    
1006     [
1007     [
1008     'ruth.schmorp.de',
1009     'a',
1010     'in',
1011     '129.13.162.95'
1012     ]
1013     ]
1014    
1015     $res->resolve ("test1.laendle", "*",
1016     accept => ["a", "aaaa"],
1017     sub {
1018     warn Dumper [@_];
1019     }
1020     );
1021    
1022     [
1023     [
1024     'test1.laendle',
1025     'a',
1026     'in',
1027     '10.0.0.255'
1028     ],
1029     [
1030     'test1.laendle',
1031     'aaaa',
1032     'in',
1033     '3ffe:1900:4545:0002:0240:0000:0000:f7e1'
1034     ]
1035     ]
1036    
1037     =cut
1038    
1039     sub resolve($%) {
1040     my $cb = pop;
1041     my ($self, $qname, $qtype, %opt) = @_;
1042    
1043     my @search = $qname =~ s/\.$//
1044     ? ""
1045     : $opt{search}
1046     ? @{ $opt{search} }
1047     : ($qname =~ y/.//) >= $self->{ndots}
1048     ? ("", @{ $self->{search} })
1049     : (@{ $self->{search} }, "");
1050    
1051     my $class = $opt{class} || "in";
1052    
1053     my %atype = $opt{accept}
1054     ? map +($_ => 1), @{ $opt{accept} }
1055     : ($qtype => 1);
1056    
1057     # advance in searchlist
1058 root 1.22 my ($do_search, $do_req);
1059    
1060     $do_search = sub {
1061 root 1.1 @search
1062 root 1.22 or (undef $do_search), (undef $do_req), return $cb->();
1063 root 1.1
1064 root 1.4 (my $name = lc "$qname." . shift @search) =~ s/\.$//;
1065 root 1.1 my $depth = 2;
1066    
1067     # advance in cname-chain
1068 root 1.22 $do_req = sub {
1069 root 1.1 $self->request ({
1070     rd => 1,
1071     qd => [[$name, $qtype, $class]],
1072     }, sub {
1073     my ($res) = @_
1074     or return $do_search->();
1075    
1076     my $cname;
1077    
1078     while () {
1079 root 1.2 # results found?
1080 root 1.4 my @rr = grep $name eq lc $_->[0] && ($atype{"*"} || $atype{$_->[1]}), @{ $res->{an} };
1081 root 1.1
1082 root 1.22 (undef $do_search), (undef $do_req), return $cb->(@rr)
1083 root 1.1 if @rr;
1084    
1085     # see if there is a cname we can follow
1086 root 1.4 my @rr = grep $name eq lc $_->[0] && $_->[1] eq "cname", @{ $res->{an} };
1087 root 1.1
1088     if (@rr) {
1089     $depth--
1090     or return $do_search->(); # cname chain too long
1091    
1092     $cname = 1;
1093     $name = $rr[0][3];
1094    
1095     } elsif ($cname) {
1096     # follow the cname
1097     return $do_req->();
1098    
1099     } else {
1100 root 1.2 # no, not found anything
1101 root 1.1 return $do_search->();
1102     }
1103     }
1104     });
1105     };
1106    
1107     $do_req->();
1108     };
1109    
1110     $do_search->();
1111     }
1112    
1113 root 1.17 use AnyEvent::Socket (); # circular dependency, so do not import anything and do it at the end
1114    
1115 root 1.1 1;
1116    
1117     =back
1118    
1119     =head1 AUTHOR
1120    
1121     Marc Lehmann <schmorp@schmorp.de>
1122     http://home.schmorp.de/
1123    
1124     =cut
1125