ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.93
Committed: Mon Jun 22 11:57:05 2009 UTC (15 years ago) by root
Branch: MAIN
Changes since 1.92: +13 -4 lines
Log Message:
*** empty log message ***

File Contents

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