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