ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.122
Committed: Wed Oct 14 20:38:28 2009 UTC (14 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-5_202
Changes since 1.121: +1 -0 lines
Log Message:
5.202

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