ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
(Generate patch)

Comparing AnyEvent/lib/AnyEvent/DNS.pm (file contents):
Revision 1.36 by root, Wed May 28 21:07:07 2008 UTC vs.
Revision 1.100 by root, Sun Jul 5 01:38:43 2009 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines