ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
Revision: 1.20
Committed: Fri May 23 23:44:55 2008 UTC (16 years, 1 month ago) by root
Branch: MAIN
Changes since 1.19: +8 -5 lines
Log Message:
*** empty log message ***

File Contents

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