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