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