ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.39
Committed: Thu May 29 03:45:37 2008 UTC (16 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-4_1
Changes since 1.38: +3 -1 lines
Log Message:
work around perl 5.8 bug, add some notes into makefile.pl

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.21 C<$ENV{PERL_ANYEVENT_EDNS0>), but when set to C<1>, AnyEvent::DNS will use
193     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.24 A list of server addresses (default: C<v127.0.0.1>) in network format (4
566 root 1.1 octets for IPv4, 16 octets for IPv6 - not yet supported).
567    
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     Most name servers do not handle many parallel requests very well. This option
586 root 1.24 limits the number of outstanding requests to C<$n> (default: C<10>), that means
587 root 1.1 if you request more than this many requests, then the additional requests will be queued
588     until some other requests have been resolved.
589    
590 root 1.13 =item reuse => $seconds
591    
592 root 1.22 The number of seconds (default: C<300>) that a query id cannot be re-used
593     after a timeout. If there as no time-out then query id's can be reused
594     immediately.
595 root 1.13
596 root 1.1 =back
597    
598     =cut
599    
600     sub new {
601     my ($class, %arg) = @_;
602    
603 root 1.38 # try to create a ipv4 and an ipv6 socket
604     # only fail when we cnanot create either
605 root 1.1
606 root 1.38 socket my $fh4, AF_INET , &Socket::SOCK_DGRAM, 0;
607     socket my $fh6, AF_INET6, &Socket::SOCK_DGRAM, 0;
608    
609     $fh4 || $fh6
610     or Carp::croak "unable to create either an IPv6 or an IPv4 socket";
611 root 1.1
612     my $self = bless {
613 root 1.32 server => [],
614 root 1.1 timeout => [2, 5, 5],
615     search => [],
616     ndots => 1,
617     max_outstanding => 10,
618 root 1.22 reuse => 300, # reuse id's after 5 minutes only, if possible
619 root 1.1 %arg,
620     reuse_q => [],
621     }, $class;
622    
623     # search should default to gethostname's domain
624     # but perl lacks a good posix module
625    
626     Scalar::Util::weaken (my $wself = $self);
627 root 1.38
628     if ($fh4) {
629     AnyEvent::Util::fh_nonblocking $fh4, 1;
630     $self->{fh4} = $fh4;
631     $self->{rw4} = AnyEvent->io (fh => $fh4, poll => "r", cb => sub {
632     if (my $peer = recv $fh4, my $pkt, MAX_PKT, 0) {
633     $wself->_recv ($pkt, $peer);
634     }
635     });
636     }
637    
638     if ($fh6) {
639     $self->{fh6} = $fh6;
640     AnyEvent::Util::fh_nonblocking $fh6, 1;
641     $self->{rw6} = AnyEvent->io (fh => $fh6, poll => "r", cb => sub {
642     if (my $peer = recv $fh6, my $pkt, MAX_PKT, 0) {
643     $wself->_recv ($pkt, $peer);
644     }
645     });
646     }
647 root 1.1
648     $self->_compile;
649    
650     $self
651     }
652    
653     =item $resolver->parse_resolv_conv ($string)
654    
655 root 1.24 Parses the given string as if it were a F<resolv.conf> file. The following
656     directives are supported (but not necessarily implemented).
657 root 1.1
658     C<#>-style comments, C<nameserver>, C<domain>, C<search>, C<sortlist>,
659     C<options> (C<timeout>, C<attempts>, C<ndots>).
660    
661     Everything else is silently ignored.
662    
663     =cut
664    
665     sub parse_resolv_conf {
666     my ($self, $resolvconf) = @_;
667    
668     $self->{server} = [];
669     $self->{search} = [];
670    
671     my $attempts;
672    
673     for (split /\n/, $resolvconf) {
674     if (/^\s*#/) {
675     # comment
676     } elsif (/^\s*nameserver\s+(\S+)\s*$/i) {
677     my $ip = $1;
678 root 1.36 if (my $ipn = AnyEvent::Socket::parse_address ($ip)) {
679 root 1.25 push @{ $self->{server} }, $ipn;
680 root 1.1 } else {
681     warn "nameserver $ip invalid and ignored\n";
682     }
683     } elsif (/^\s*domain\s+(\S*)\s+$/i) {
684     $self->{search} = [$1];
685     } elsif (/^\s*search\s+(.*?)\s*$/i) {
686     $self->{search} = [split /\s+/, $1];
687     } elsif (/^\s*sortlist\s+(.*?)\s*$/i) {
688     # ignored, NYI
689     } elsif (/^\s*options\s+(.*?)\s*$/i) {
690     for (split /\s+/, $1) {
691     if (/^timeout:(\d+)$/) {
692     $self->{timeout} = [$1];
693     } elsif (/^attempts:(\d+)$/) {
694     $attempts = $1;
695     } elsif (/^ndots:(\d+)$/) {
696     $self->{ndots} = $1;
697     } else {
698     # debug, rotate, no-check-names, inet6
699     }
700     }
701     }
702     }
703    
704     $self->{timeout} = [($self->{timeout}[0]) x $attempts]
705     if $attempts;
706    
707     $self->_compile;
708     }
709    
710 root 1.14 =item $resolver->os_config
711 root 1.1
712 root 1.24 Tries so load and parse F</etc/resolv.conf> on portable operating systems. Tries various
713     egregious hacks on windows to force the DNS servers and searchlist out of the system.
714 root 1.1
715     =cut
716    
717 root 1.14 sub os_config {
718 root 1.1 my ($self) = @_;
719    
720 root 1.32 $self->{server} = [];
721     $self->{search} = [];
722    
723 root 1.35 if (AnyEvent::WIN32 || $^O =~ /cygwin/i) {
724 root 1.32 no strict 'refs';
725    
726     # there are many options to find the current nameservers etc. on windows
727     # all of them don't work consistently:
728     # - the registry thing needs separate code on win32 native vs. cygwin
729     # - the registry layout differs between windows versions
730     # - calling windows api functions doesn't work on cygwin
731     # - ipconfig uses locale-specific messages
732    
733     # we use ipconfig parsing because, despite all it's brokenness,
734     # it seems most stable in practise.
735     # for good measure, we append a fallback nameserver to our list.
736 root 1.14
737     if (open my $fh, "ipconfig /all |") {
738 root 1.32 # parsing strategy: we go through the output and look for
739     # :-lines with DNS in them. everything in those is regarded as
740     # either a nameserver (if it parses as an ip address), or a suffix
741     # (all else).
742 root 1.14
743 root 1.32 my $dns;
744 root 1.14 while (<$fh>) {
745 root 1.32 if (s/^\s.*\bdns\b.*://i) {
746     $dns = 1;
747     } elsif (/^\S/ || /^\s[^:]{16,}: /) {
748     $dns = 0;
749     }
750     if ($dns && /^\s*(\S+)\s*$/) {
751     my $s = $1;
752     $s =~ s/%\d+(?!\S)//; # get rid of scope id
753 root 1.36 if (my $ipn = AnyEvent::Socket::parse_address ($s)) {
754 root 1.32 push @{ $self->{server} }, $ipn;
755     } else {
756     push @{ $self->{search} }, $s;
757 root 1.14 }
758     }
759     }
760    
761 root 1.32 # always add one fallback server
762     push @{ $self->{server} }, $DNS_FALLBACK[rand @DNS_FALLBACK];
763 root 1.14
764     $self->_compile;
765     }
766     } else {
767     # try resolv.conf everywhere
768 root 1.1
769 root 1.14 if (open my $fh, "</etc/resolv.conf") {
770     local $/;
771     $self->parse_resolv_conf (<$fh>);
772     }
773     }
774 root 1.1 }
775    
776     sub _compile {
777     my $self = shift;
778    
779 root 1.38 my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
780     my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
781 root 1.32
782     unless (@{ $self->{server} }) {
783     # use 127.0.0.1 by default, and one opendns nameserver as fallback
784     $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
785     }
786    
787 root 1.1 my @retry;
788    
789     for my $timeout (@{ $self->{timeout} }) {
790     for my $server (@{ $self->{server} }) {
791     push @retry, [$server, $timeout];
792     }
793     }
794    
795     $self->{retry} = \@retry;
796     }
797    
798 root 1.6 sub _feed {
799     my ($self, $res) = @_;
800    
801     $res = dns_unpack $res
802     or return;
803    
804     my $id = $self->{id}{$res->{id}};
805    
806     return unless ref $id;
807    
808     $NOW = time;
809     $id->[1]->($res);
810     }
811    
812 root 1.1 sub _recv {
813 root 1.38 my ($self, $pkt, $peer) = @_;
814 root 1.1
815 root 1.32 # we ignore errors (often one gets port unreachable, but there is
816     # no good way to take advantage of that.
817 root 1.1
818 root 1.38 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
819    
820     return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
821 root 1.1
822 root 1.38 $self->_feed ($pkt);
823 root 1.1 }
824    
825 root 1.22 sub _free_id {
826     my ($self, $id, $timeout) = @_;
827    
828     if ($timeout) {
829     # we need to block the id for a while
830     $self->{id}{$id} = 1;
831     push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
832     } else {
833     # we can quickly recycle the id
834     delete $self->{id}{$id};
835     }
836    
837     --$self->{outstanding};
838     $self->_scheduler;
839     }
840    
841     # execute a single request, involves sending it with timeouts to multiple servers
842 root 1.1 sub _exec {
843 root 1.22 my ($self, $req) = @_;
844    
845     my $retry; # of retries
846     my $do_retry;
847    
848     $do_retry = sub {
849     my $retry_cfg = $self->{retry}[$retry++]
850     or do {
851     # failure
852     $self->_free_id ($req->[2], $retry > 1);
853     undef $do_retry; return $req->[1]->();
854     };
855 root 1.1
856     my ($server, $timeout) = @$retry_cfg;
857    
858     $self->{id}{$req->[2]} = [AnyEvent->timer (after => $timeout, cb => sub {
859     $NOW = time;
860    
861     # timeout, try next
862 root 1.22 &$do_retry;
863 root 1.1 }), sub {
864     my ($res) = @_;
865    
866 root 1.6 if ($res->{tc}) {
867     # success, but truncated, so use tcp
868 root 1.38 AnyEvent::Socket::tcp_connect (AnyEvent::Socket::format_address ($server), DOMAIN_PORT, sub {
869 root 1.6 my ($fh) = @_
870 root 1.22 or return &$do_retry;
871 root 1.6
872     my $handle = new AnyEvent::Handle
873     fh => $fh,
874     on_error => sub {
875     # failure, try next
876 root 1.22 &$do_retry;
877 root 1.6 };
878    
879     $handle->push_write (pack "n/a", $req->[0]);
880 root 1.27 $handle->push_read (chunk => 2, sub {
881     $handle->unshift_read (chunk => (unpack "n", $_[1]), sub {
882 root 1.6 $self->_feed ($_[1]);
883     });
884     });
885     shutdown $fh, 1;
886    
887 root 1.17 }, sub { $timeout });
888 root 1.1
889 root 1.6 } else {
890     # success
891 root 1.22 $self->_free_id ($req->[2], $retry > 1);
892     undef $do_retry; return $req->[1]->($res);
893 root 1.6 }
894 root 1.1 }];
895 root 1.38
896     my $sa = AnyEvent::Socket::pack_sockaddr (DOMAIN_PORT, $server);
897    
898 root 1.39 my $fh = AF_INET == Socket::sockaddr_family ($sa)
899 root 1.38 ? $self->{fh4} : $self->{fh6}
900     or return &$do_retry;
901 root 1.1
902 root 1.38 send $fh, $req->[0], 0, $sa;
903 root 1.22 };
904 root 1.1
905 root 1.22 &$do_retry;
906 root 1.1 }
907    
908     sub _scheduler {
909     my ($self) = @_;
910    
911     $NOW = time;
912    
913     # first clear id reuse queue
914     delete $self->{id}{ (shift @{ $self->{reuse_q} })->[1] }
915 root 1.13 while @{ $self->{reuse_q} } && $self->{reuse_q}[0][0] <= $NOW;
916 root 1.1
917     while ($self->{outstanding} < $self->{max_outstanding}) {
918 root 1.13
919     if (@{ $self->{reuse_q} } >= 30000) {
920     # we ran out of ID's, wait a bit
921     $self->{reuse_to} ||= AnyEvent->timer (after => $self->{reuse_q}[0][0] - $NOW, cb => sub {
922     delete $self->{reuse_to};
923     $self->_scheduler;
924     });
925     last;
926     }
927    
928 root 1.1 my $req = shift @{ $self->{queue} }
929     or last;
930    
931     while () {
932     $req->[2] = int rand 65536;
933     last unless exists $self->{id}{$req->[2]};
934     }
935    
936 root 1.22 ++$self->{outstanding};
937 root 1.1 $self->{id}{$req->[2]} = 1;
938     substr $req->[0], 0, 2, pack "n", $req->[2];
939    
940 root 1.22 $self->_exec ($req);
941 root 1.1 }
942     }
943    
944     =item $resolver->request ($req, $cb->($res))
945    
946     Sends a single request (a hash-ref formated as specified for
947 root 1.3 C<dns_pack>) to the configured nameservers including
948 root 1.1 retries. Calls the callback with the decoded response packet if a reply
949     was received, or no arguments on timeout.
950    
951     =cut
952    
953     sub request($$) {
954     my ($self, $req, $cb) = @_;
955    
956 root 1.3 push @{ $self->{queue} }, [dns_pack $req, $cb];
957 root 1.1 $self->_scheduler;
958     }
959    
960     =item $resolver->resolve ($qname, $qtype, %options, $cb->($rcode, @rr))
961    
962     Queries the DNS for the given domain name C<$qname> of type C<$qtype> (a
963     qtype of "*" is supported and means "any").
964    
965     The callback will be invoked with a list of matching result records or
966     none on any error or if the name could not be found.
967    
968     CNAME chains (although illegal) are followed up to a length of 8.
969    
970 root 1.24 Note that this resolver is just a stub resolver: it requires a name server
971 root 1.3 supporting recursive queries, will not do any recursive queries itself and
972     is not secure when used against an untrusted name server.
973    
974 root 1.1 The following options are supported:
975    
976     =over 4
977    
978     =item search => [$suffix...]
979    
980     Use the given search list (which might be empty), by appending each one
981     in turn to the C<$qname>. If this option is missing then the configured
982     C<ndots> and C<search> define its value. If the C<$qname> ends in a dot,
983 root 1.2 then the searchlist will be ignored.
984 root 1.1
985     =item accept => [$type...]
986    
987     Lists the acceptable result types: only result types in this set will be
988     accepted and returned. The default includes the C<$qtype> and nothing
989     else.
990    
991     =item class => "class"
992    
993     Specify the query class ("in" for internet, "ch" for chaosnet and "hs" for
994 root 1.2 hesiod are the only ones making sense). The default is "in", of course.
995 root 1.1
996     =back
997    
998     Examples:
999    
1000     $res->resolve ("ruth.plan9.de", "a", sub {
1001     warn Dumper [@_];
1002     });
1003    
1004     [
1005     [
1006     'ruth.schmorp.de',
1007     'a',
1008     'in',
1009     '129.13.162.95'
1010     ]
1011     ]
1012    
1013     $res->resolve ("test1.laendle", "*",
1014     accept => ["a", "aaaa"],
1015     sub {
1016     warn Dumper [@_];
1017     }
1018     );
1019    
1020     [
1021     [
1022     'test1.laendle',
1023     'a',
1024     'in',
1025     '10.0.0.255'
1026     ],
1027     [
1028     'test1.laendle',
1029     'aaaa',
1030     'in',
1031     '3ffe:1900:4545:0002:0240:0000:0000:f7e1'
1032     ]
1033     ]
1034    
1035     =cut
1036    
1037     sub resolve($%) {
1038     my $cb = pop;
1039     my ($self, $qname, $qtype, %opt) = @_;
1040    
1041     my @search = $qname =~ s/\.$//
1042     ? ""
1043     : $opt{search}
1044     ? @{ $opt{search} }
1045     : ($qname =~ y/.//) >= $self->{ndots}
1046     ? ("", @{ $self->{search} })
1047     : (@{ $self->{search} }, "");
1048    
1049     my $class = $opt{class} || "in";
1050    
1051     my %atype = $opt{accept}
1052     ? map +($_ => 1), @{ $opt{accept} }
1053     : ($qtype => 1);
1054    
1055     # advance in searchlist
1056 root 1.22 my ($do_search, $do_req);
1057    
1058     $do_search = sub {
1059 root 1.1 @search
1060 root 1.22 or (undef $do_search), (undef $do_req), return $cb->();
1061 root 1.1
1062 root 1.4 (my $name = lc "$qname." . shift @search) =~ s/\.$//;
1063 root 1.1 my $depth = 2;
1064    
1065     # advance in cname-chain
1066 root 1.22 $do_req = sub {
1067 root 1.1 $self->request ({
1068     rd => 1,
1069     qd => [[$name, $qtype, $class]],
1070     }, sub {
1071     my ($res) = @_
1072     or return $do_search->();
1073    
1074     my $cname;
1075    
1076     while () {
1077 root 1.2 # results found?
1078 root 1.4 my @rr = grep $name eq lc $_->[0] && ($atype{"*"} || $atype{$_->[1]}), @{ $res->{an} };
1079 root 1.1
1080 root 1.22 (undef $do_search), (undef $do_req), return $cb->(@rr)
1081 root 1.1 if @rr;
1082    
1083     # see if there is a cname we can follow
1084 root 1.4 my @rr = grep $name eq lc $_->[0] && $_->[1] eq "cname", @{ $res->{an} };
1085 root 1.1
1086     if (@rr) {
1087     $depth--
1088     or return $do_search->(); # cname chain too long
1089    
1090     $cname = 1;
1091     $name = $rr[0][3];
1092    
1093     } elsif ($cname) {
1094     # follow the cname
1095     return $do_req->();
1096    
1097     } else {
1098 root 1.2 # no, not found anything
1099 root 1.1 return $do_search->();
1100     }
1101     }
1102     });
1103     };
1104    
1105     $do_req->();
1106     };
1107    
1108     $do_search->();
1109     }
1110    
1111 root 1.17 use AnyEvent::Socket (); # circular dependency, so do not import anything and do it at the end
1112    
1113 root 1.1 1;
1114    
1115     =back
1116    
1117     =head1 AUTHOR
1118    
1119     Marc Lehmann <schmorp@schmorp.de>
1120     http://home.schmorp.de/
1121    
1122     =cut
1123