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