ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.102
Committed: Mon Jul 6 23:32:49 2009 UTC (14 years, 11 months ago) by root
Branch: MAIN
Changes since 1.101: +35 -9 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 Carp ();
35 use Socket qw(AF_INET SOCK_DGRAM SOCK_STREAM);
36
37 use AnyEvent ();
38 use AnyEvent::Util qw(AF_INET6);
39
40 our $VERSION = 4.8;
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_ipv6 ($_) }, # 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 The resolver is created with the following parameters:
655
656 untaint enabled
657 max_outstanding $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}
658
659 C<os_config> will be used for OS-specific configuration, unless
660 C<$ENV{PERL_ANYEVENT_RESOLV_CONF}> is specified, in which case that file
661 gets parsed.
662
663 =cut
664
665 our $RESOLVER;
666
667 sub resolver() {
668 $RESOLVER || do {
669 $RESOLVER = new AnyEvent::DNS
670 untaint => 1,
671 exists $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}
672 ? (max_outstanding => $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}*1 || 1) : (),
673 ;
674
675 exists $ENV{PERL_ANYEVENT_RESOLV_CONF}
676 ? length $ENV{PERL_ANYEVENT_RESOLV_CONF} && $RESOLVER->_parse_resolv_conf_file ($ENV{PERL_ANYEVENT_RESOLV_CONF})
677 : $RESOLVER->os_config;
678
679 $RESOLVER
680 }
681 }
682
683 =item $resolver = new AnyEvent::DNS key => value...
684
685 Creates and returns a new resolver.
686
687 The following options are supported:
688
689 =over 4
690
691 =item server => [...]
692
693 A list of server addresses (default: C<v127.0.0.1>) in network format
694 (i.e. as returned by C<AnyEvent::Socket::parse_address> - both IPv4 and
695 IPv6 are supported).
696
697 =item timeout => [...]
698
699 A list of timeouts to use (also determines the number of retries). To make
700 three retries with individual time-outs of 2, 5 and 5 seconds, use C<[2,
701 5, 5]>, which is also the default.
702
703 =item search => [...]
704
705 The default search list of suffixes to append to a domain name (default: none).
706
707 =item ndots => $integer
708
709 The number of dots (default: C<1>) that a name must have so that the resolver
710 tries to resolve the name without any suffixes first.
711
712 =item max_outstanding => $integer
713
714 Most name servers do not handle many parallel requests very well. This
715 option limits the number of outstanding requests to C<$integer>
716 (default: C<10>), that means if you request more than this many requests,
717 then the additional requests will be queued until some other requests have
718 been resolved.
719
720 =item reuse => $seconds
721
722 The number of seconds (default: C<300>) that a query id cannot be re-used
723 after a timeout. If there was no time-out then query ids can be reused
724 immediately.
725
726 =item untaint => $boolean
727
728 When true, then the resolver will automatically untaint results, and might
729 also ignore certain environment variables.
730
731 =back
732
733 =cut
734
735 sub new {
736 my ($class, %arg) = @_;
737
738 my $self = bless {
739 server => [],
740 timeout => [2, 5, 5],
741 search => [],
742 ndots => 1,
743 max_outstanding => 10,
744 reuse => 300,
745 %arg,
746 reuse_q => [],
747 }, $class;
748
749 # search should default to gethostname's domain
750 # but perl lacks a good posix module
751
752 # try to create an ipv4 and an ipv6 socket
753 # only fail when we cannot create either
754 my $got_socket;
755
756 Scalar::Util::weaken (my $wself = $self);
757
758 if (socket my $fh4, AF_INET , &Socket::SOCK_DGRAM, 0) {
759 ++$got_socket;
760
761 AnyEvent::Util::fh_nonblocking $fh4, 1;
762 $self->{fh4} = $fh4;
763 $self->{rw4} = AnyEvent->io (fh => $fh4, poll => "r", cb => sub {
764 if (my $peer = recv $fh4, my $pkt, MAX_PKT, 0) {
765 $wself->_recv ($pkt, $peer);
766 }
767 });
768 }
769
770 if (AF_INET6 && socket my $fh6, AF_INET6, &Socket::SOCK_DGRAM, 0) {
771 ++$got_socket;
772
773 $self->{fh6} = $fh6;
774 AnyEvent::Util::fh_nonblocking $fh6, 1;
775 $self->{rw6} = AnyEvent->io (fh => $fh6, poll => "r", cb => sub {
776 if (my $peer = recv $fh6, my $pkt, MAX_PKT, 0) {
777 $wself->_recv ($pkt, $peer);
778 }
779 });
780 }
781
782 $got_socket
783 or Carp::croak "unable to create either an IPv4 or an IPv6 socket";
784
785 $self->_compile;
786
787 $self
788 }
789
790 =item $resolver->parse_resolv_conf ($string)
791
792 Parses the given string as if it were a F<resolv.conf> file. The following
793 directives are supported (but not necessarily implemented).
794
795 C<#>-style comments, C<nameserver>, C<domain>, C<search>, C<sortlist>,
796 C<options> (C<timeout>, C<attempts>, C<ndots>).
797
798 Everything else is silently ignored.
799
800 =cut
801
802 sub parse_resolv_conf {
803 my ($self, $resolvconf) = @_;
804
805 $self->{server} = [];
806 $self->{search} = [];
807
808 my $attempts;
809
810 for (split /\n/, $resolvconf) {
811 if (/^\s*#/) {
812 # comment
813 } elsif (/^\s*nameserver\s+(\S+)\s*$/i) {
814 my $ip = $1;
815 if (my $ipn = AnyEvent::Socket::parse_address ($ip)) {
816 push @{ $self->{server} }, $ipn;
817 } else {
818 warn "nameserver $ip invalid and ignored\n";
819 }
820 } elsif (/^\s*domain\s+(\S*)\s+$/i) {
821 $self->{search} = [$1];
822 } elsif (/^\s*search\s+(.*?)\s*$/i) {
823 $self->{search} = [split /\s+/, $1];
824 } elsif (/^\s*sortlist\s+(.*?)\s*$/i) {
825 # ignored, NYI
826 } elsif (/^\s*options\s+(.*?)\s*$/i) {
827 for (split /\s+/, $1) {
828 if (/^timeout:(\d+)$/) {
829 $self->{timeout} = [$1];
830 } elsif (/^attempts:(\d+)$/) {
831 $attempts = $1;
832 } elsif (/^ndots:(\d+)$/) {
833 $self->{ndots} = $1;
834 } else {
835 # debug, rotate, no-check-names, inet6
836 }
837 }
838 }
839 }
840
841 $self->{timeout} = [($self->{timeout}[0]) x $attempts]
842 if $attempts;
843
844 $self->_compile;
845 }
846
847 sub _parse_resolv_conf_file {
848 my ($self, $resolv_conf) = @_;
849
850 open my $fh, "<:perlio", $resolv_conf
851 or Carp::croak "$resolv_conf: $!";
852
853 local $/;
854 $self->parse_resolv_conf (<$fh>);
855 }
856
857 =item $resolver->os_config
858
859 Tries so load and parse F</etc/resolv.conf> on portable operating
860 systems. Tries various egregious hacks on windows to force the DNS servers
861 and searchlist out of the system.
862
863 =cut
864
865 sub os_config {
866 my ($self) = @_;
867
868 $self->{server} = [];
869 $self->{search} = [];
870
871 if ((AnyEvent::WIN32 || $^O =~ /cygwin/i)) {
872 no strict 'refs';
873
874 # there are many options to find the current nameservers etc. on windows
875 # all of them don't work consistently:
876 # - the registry thing needs separate code on win32 native vs. cygwin
877 # - the registry layout differs between windows versions
878 # - calling windows api functions doesn't work on cygwin
879 # - ipconfig uses locale-specific messages
880
881 # we use ipconfig parsing because, despite all its brokenness,
882 # it seems most stable in practise.
883 # for good measure, we append a fallback nameserver to our list.
884
885 if (open my $fh, "ipconfig /all |") {
886 # parsing strategy: we go through the output and look for
887 # :-lines with DNS in them. everything in those is regarded as
888 # either a nameserver (if it parses as an ip address), or a suffix
889 # (all else).
890
891 my $dns;
892 while (<$fh>) {
893 if (s/^\s.*\bdns\b.*://i) {
894 $dns = 1;
895 } elsif (/^\S/ || /^\s[^:]{16,}: /) {
896 $dns = 0;
897 }
898 if ($dns && /^\s*(\S+)\s*$/) {
899 my $s = $1;
900 $s =~ s/%\d+(?!\S)//; # get rid of ipv6 scope id
901 if (my $ipn = AnyEvent::Socket::parse_address ($s)) {
902 push @{ $self->{server} }, $ipn;
903 } else {
904 push @{ $self->{search} }, $s;
905 }
906 }
907 }
908
909 # always add one fallback server
910 push @{ $self->{server} }, $DNS_FALLBACK[rand @DNS_FALLBACK];
911
912 $self->_compile;
913 }
914 } else {
915 # try resolv.conf everywhere else
916
917 $self->_parse_resolv_conf_file ("/etc/resolv.conf")
918 if -e "/etc/resolv.conf";
919 }
920 }
921
922 =item $resolver->timeout ($timeout, ...)
923
924 Sets the timeout values. See the C<timeout> constructor argument (and note
925 that this method uses the values itself, not an array-reference).
926
927 =cut
928
929 sub timeout {
930 my ($self, @timeout) = @_;
931
932 $self->{timeout} = \@timeout;
933 $self->_compile;
934 }
935
936 =item $resolver->max_outstanding ($nrequests)
937
938 Sets the maximum number of outstanding requests to C<$nrequests>. See the
939 C<max_outstanding> constructor argument.
940
941 =cut
942
943 sub max_outstanding {
944 my ($self, $max) = @_;
945
946 $self->{max_outstanding} = $max;
947 $self->_scheduler;
948 }
949
950 sub _compile {
951 my $self = shift;
952
953 my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
954 my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
955
956 unless (@{ $self->{server} }) {
957 # use 127.0.0.1 by default, and one opendns nameserver as fallback
958 $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
959 }
960
961 my @retry;
962
963 for my $timeout (@{ $self->{timeout} }) {
964 for my $server (@{ $self->{server} }) {
965 push @retry, [$server, $timeout];
966 }
967 }
968
969 $self->{retry} = \@retry;
970 }
971
972 sub _feed {
973 my ($self, $res) = @_;
974
975 ($res) = $res =~ /^(.*)$/s
976 if AnyEvent::TAINT && $self->{untaint};
977
978 $res = dns_unpack $res
979 or return;
980
981 my $id = $self->{id}{$res->{id}};
982
983 return unless ref $id;
984
985 $NOW = time;
986 $id->[1]->($res);
987 }
988
989 sub _recv {
990 my ($self, $pkt, $peer) = @_;
991
992 # we ignore errors (often one gets port unreachable, but there is
993 # no good way to take advantage of that.
994
995 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
996
997 return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
998
999 $self->_feed ($pkt);
1000 }
1001
1002 sub _free_id {
1003 my ($self, $id, $timeout) = @_;
1004
1005 if ($timeout) {
1006 # we need to block the id for a while
1007 $self->{id}{$id} = 1;
1008 push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
1009 } else {
1010 # we can quickly recycle the id
1011 delete $self->{id}{$id};
1012 }
1013
1014 --$self->{outstanding};
1015 $self->_scheduler;
1016 }
1017
1018 # execute a single request, involves sending it with timeouts to multiple servers
1019 sub _exec {
1020 my ($self, $req) = @_;
1021
1022 my $retry; # of retries
1023 my $do_retry;
1024
1025 $do_retry = sub {
1026 my $retry_cfg = $self->{retry}[$retry++]
1027 or do {
1028 # failure
1029 $self->_free_id ($req->[2], $retry > 1);
1030 undef $do_retry; return $req->[1]->();
1031 };
1032
1033 my ($server, $timeout) = @$retry_cfg;
1034
1035 $self->{id}{$req->[2]} = [AnyEvent->timer (after => $timeout, cb => sub {
1036 $NOW = time;
1037
1038 # timeout, try next
1039 &$do_retry if $do_retry;
1040 }), sub {
1041 my ($res) = @_;
1042
1043 if ($res->{tc}) {
1044 # success, but truncated, so use tcp
1045 AnyEvent::Socket::tcp_connect (AnyEvent::Socket::format_address ($server), DOMAIN_PORT, sub {
1046 return unless $do_retry; # some other request could have invalidated us already
1047
1048 my ($fh) = @_
1049 or return &$do_retry;
1050
1051 require AnyEvent::Handle;
1052
1053 my $handle; $handle = new AnyEvent::Handle
1054 fh => $fh,
1055 timeout => $timeout,
1056 on_error => sub {
1057 undef $handle;
1058 return unless $do_retry; # some other request could have invalidated us already
1059 # failure, try next
1060 &$do_retry;
1061 };
1062
1063 $handle->push_write (pack "n/a", $req->[0]);
1064 $handle->push_read (chunk => 2, sub {
1065 $handle->unshift_read (chunk => (unpack "n", $_[1]), sub {
1066 undef $handle;
1067 $self->_feed ($_[1]);
1068 });
1069 });
1070
1071 }, sub { $timeout });
1072
1073 } else {
1074 # success
1075 $self->_free_id ($req->[2], $retry > 1);
1076 undef $do_retry; return $req->[1]->($res);
1077 }
1078 }];
1079
1080 my $sa = AnyEvent::Socket::pack_sockaddr (DOMAIN_PORT, $server);
1081
1082 my $fh = AF_INET == Socket::sockaddr_family ($sa)
1083 ? $self->{fh4} : $self->{fh6}
1084 or return &$do_retry;
1085
1086 send $fh, $req->[0], 0, $sa;
1087 };
1088
1089 &$do_retry;
1090 }
1091
1092 sub _scheduler {
1093 my ($self) = @_;
1094
1095 no strict 'refs';
1096
1097 $NOW = time;
1098
1099 # first clear id reuse queue
1100 delete $self->{id}{ (shift @{ $self->{reuse_q} })->[1] }
1101 while @{ $self->{reuse_q} } && $self->{reuse_q}[0][0] <= $NOW;
1102
1103 while ($self->{outstanding} < $self->{max_outstanding}) {
1104
1105 if (@{ $self->{reuse_q} } >= 30000) {
1106 # we ran out of ID's, wait a bit
1107 $self->{reuse_to} ||= AnyEvent->timer (after => $self->{reuse_q}[0][0] - $NOW, cb => sub {
1108 delete $self->{reuse_to};
1109 $self->_scheduler;
1110 });
1111 last;
1112 }
1113
1114 if (my $req = shift @{ $self->{queue} }) {
1115 # found a request in the queue, execute it
1116 while () {
1117 $req->[2] = int rand 65536;
1118 last unless exists $self->{id}{$req->[2]};
1119 }
1120
1121 ++$self->{outstanding};
1122 $self->{id}{$req->[2]} = 1;
1123 substr $req->[0], 0, 2, pack "n", $req->[2];
1124
1125 $self->_exec ($req);
1126
1127 } elsif (my $cb = shift @{ $self->{wait} }) {
1128 # found a wait_for_slot callback, call that one first
1129 $cb->($self);
1130
1131 } else {
1132 # nothing to do, just exit
1133 last;
1134 }
1135 }
1136 }
1137
1138 =item $resolver->request ($req, $cb->($res))
1139
1140 This is the main low-level workhorse for sending DNS requests.
1141
1142 This function sends a single request (a hash-ref formated as specified
1143 for C<dns_pack>) to the configured nameservers in turn until it gets a
1144 response. It handles timeouts, retries and automatically falls back to
1145 virtual circuit mode (TCP) when it receives a truncated reply.
1146
1147 Calls the callback with the decoded response packet if a reply was
1148 received, or no arguments in case none of the servers answered.
1149
1150 =cut
1151
1152 sub request($$) {
1153 my ($self, $req, $cb) = @_;
1154
1155 push @{ $self->{queue} }, [dns_pack $req, $cb];
1156 $self->_scheduler;
1157 }
1158
1159 =item $resolver->resolve ($qname, $qtype, %options, $cb->(@rr))
1160
1161 Queries the DNS for the given domain name C<$qname> of type C<$qtype>.
1162
1163 A C<$qtype> is either a numerical query type (e.g. C<1> for A records) or
1164 a lowercase name (you have to look at the source to see which aliases are
1165 supported, but all types from RFC 1035, C<aaaa>, C<srv>, C<spf> and a few
1166 more are known to this module). A C<$qtype> of "*" is supported and means
1167 "any" record type.
1168
1169 The callback will be invoked with a list of matching result records or
1170 none on any error or if the name could not be found.
1171
1172 CNAME chains (although illegal) are followed up to a length of 10.
1173
1174 The callback will be invoked with arraryefs of the form C<[$name, $type,
1175 $class, @data>], where C<$name> is the domain name, C<$type> a type string
1176 or number, C<$class> a class name and @data is resource-record-dependent
1177 data. For C<a> records, this will be the textual IPv4 addresses, for C<ns>
1178 or C<cname> records this will be a domain name, for C<txt> records these
1179 are all the strings and so on.
1180
1181 All types mentioned in RFC 1035, C<aaaa>, C<srv>, C<naptr> and C<spf> are
1182 decoded. All resource records not known to this module will have
1183 the raw C<rdata> field as fourth entry.
1184
1185 Note that this resolver is just a stub resolver: it requires a name server
1186 supporting recursive queries, will not do any recursive queries itself and
1187 is not secure when used against an untrusted name server.
1188
1189 The following options are supported:
1190
1191 =over 4
1192
1193 =item search => [$suffix...]
1194
1195 Use the given search list (which might be empty), by appending each one
1196 in turn to the C<$qname>. If this option is missing then the configured
1197 C<ndots> and C<search> values define its value (depending on C<ndots>, the
1198 empty suffix will be prepended or appended to that C<search> value). If
1199 the C<$qname> ends in a dot, then the searchlist will be ignored.
1200
1201 =item accept => [$type...]
1202
1203 Lists the acceptable result types: only result types in this set will be
1204 accepted and returned. The default includes the C<$qtype> and nothing
1205 else. If this list includes C<cname>, then CNAME-chains will not be
1206 followed (because you asked for the CNAME record).
1207
1208 =item class => "class"
1209
1210 Specify the query class ("in" for internet, "ch" for chaosnet and "hs" for
1211 hesiod are the only ones making sense). The default is "in", of course.
1212
1213 =back
1214
1215 Examples:
1216
1217 # full example, you can paste this into perl:
1218 use Data::Dumper;
1219 use AnyEvent::DNS;
1220 AnyEvent::DNS::resolver->resolve (
1221 "google.com", "*", my $cv = AnyEvent->condvar);
1222 warn Dumper [$cv->recv];
1223
1224 # shortened result:
1225 # [
1226 # [ 'google.com', 'soa', 'in', 'ns1.google.com', 'dns-admin.google.com',
1227 # 2008052701, 7200, 1800, 1209600, 300 ],
1228 # [
1229 # 'google.com', 'txt', 'in',
1230 # 'v=spf1 include:_netblocks.google.com ~all'
1231 # ],
1232 # [ 'google.com', 'a', 'in', '64.233.187.99' ],
1233 # [ 'google.com', 'mx', 'in', 10, 'smtp2.google.com' ],
1234 # [ 'google.com', 'ns', 'in', 'ns2.google.com' ],
1235 # ]
1236
1237 # resolve a records:
1238 $res->resolve ("ruth.plan9.de", "a", sub { warn Dumper [@_] });
1239
1240 # result:
1241 # [
1242 # [ 'ruth.schmorp.de', 'a', 'in', '129.13.162.95' ]
1243 # ]
1244
1245 # resolve any records, but return only a and aaaa records:
1246 $res->resolve ("test1.laendle", "*",
1247 accept => ["a", "aaaa"],
1248 sub {
1249 warn Dumper [@_];
1250 }
1251 );
1252
1253 # result:
1254 # [
1255 # [ 'test1.laendle', 'a', 'in', '10.0.0.255' ],
1256 # [ 'test1.laendle', 'aaaa', 'in', '3ffe:1900:4545:0002:0240:0000:0000:f7e1' ]
1257 # ]
1258
1259 =cut
1260
1261 sub resolve($%) {
1262 my $cb = pop;
1263 my ($self, $qname, $qtype, %opt) = @_;
1264
1265 my @search = $qname =~ s/\.$//
1266 ? ""
1267 : $opt{search}
1268 ? @{ $opt{search} }
1269 : ($qname =~ y/.//) >= $self->{ndots}
1270 ? ("", @{ $self->{search} })
1271 : (@{ $self->{search} }, "");
1272
1273 my $class = $opt{class} || "in";
1274
1275 my %atype = $opt{accept}
1276 ? map +($_ => 1), @{ $opt{accept} }
1277 : ($qtype => 1);
1278
1279 # advance in searchlist
1280 my ($do_search, $do_req);
1281
1282 $do_search = sub {
1283 @search
1284 or (undef $do_search), (undef $do_req), return $cb->();
1285
1286 (my $name = lc "$qname." . shift @search) =~ s/\.$//;
1287 my $depth = 10;
1288
1289 # advance in cname-chain
1290 $do_req = sub {
1291 $self->request ({
1292 rd => 1,
1293 qd => [[$name, $qtype, $class]],
1294 }, sub {
1295 my ($res) = @_
1296 or return $do_search->();
1297
1298 my $cname;
1299
1300 while () {
1301 # results found?
1302 my @rr = grep $name eq lc $_->[0] && ($atype{"*"} || $atype{$_->[1]}), @{ $res->{an} };
1303
1304 (undef $do_search), (undef $do_req), return $cb->(@rr)
1305 if @rr;
1306
1307 # see if there is a cname we can follow
1308 my @rr = grep $name eq lc $_->[0] && $_->[1] eq "cname", @{ $res->{an} };
1309
1310 if (@rr) {
1311 $depth--
1312 or return $do_search->(); # cname chain too long
1313
1314 $cname = 1;
1315 $name = lc $rr[0][3];
1316
1317 } elsif ($cname) {
1318 # follow the cname
1319 return $do_req->();
1320
1321 } else {
1322 # no, not found anything
1323 return $do_search->();
1324 }
1325 }
1326 });
1327 };
1328
1329 $do_req->();
1330 };
1331
1332 $do_search->();
1333 }
1334
1335 =item $resolver->wait_for_slot ($cb->($resolver))
1336
1337 Wait until a free request slot is available and call the callback with the
1338 resolver object.
1339
1340 A request slot is used each time a request is actually sent to the
1341 nameservers: There are never more than C<max_outstanding> of them.
1342
1343 Although you can submit more requests (they will simply be queued until
1344 a request slot becomes available), sometimes, usually for rate-limiting
1345 purposes, it is useful to instead wait for a slot before generating the
1346 request (or simply to know when the request load is low enough so one can
1347 submit requests again).
1348
1349 This is what this method does: The callback will be called when submitting
1350 a DNS request will not result in that request being queued. The callback
1351 may or may not generate any requests in response.
1352
1353 Note that the callback will only be invoked when the request queue is
1354 empty, so this does not play well if somebody else keeps the request queue
1355 full at all times.
1356
1357 =cut
1358
1359 sub wait_for_slot {
1360 my ($self, $cb) = @_;
1361
1362 push @{ $self->{wait} }, $cb;
1363 $self->_scheduler;
1364 }
1365
1366 use AnyEvent::Socket (); # circular dependency, so do not import anything and do it at the end
1367
1368 1;
1369
1370 =back
1371
1372 =head1 AUTHOR
1373
1374 Marc Lehmann <schmorp@schmorp.de>
1375 http://home.schmorp.de/
1376
1377 =cut
1378