ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.101
Committed: Mon Jul 6 21:47:14 2009 UTC (14 years, 11 months ago) by root
Branch: MAIN
CVS Tags: rel-4_8
Changes since 1.100: +1 -1 lines
Log Message:
4.8

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