File Coverage

blib/lib/Metabrik/Network/Dns.pm
Criterion Covered Total %
statement 9 162 5.5
branch 0 96 0.0
condition 0 41 0.0
subroutine 3 10 30.0
pod 1 7 14.2
total 13 316 4.1


line stmt bran cond sub pod time code
1             #
2             # $Id$
3             #
4             # network::dns Brik
5             #
6             package Metabrik::Network::Dns;
7 2     2   728 use strict;
  2         5  
  2         57  
8 2     2   11 use warnings;
  2         3  
  2         53  
9              
10 2     2   10 use base qw(Metabrik);
  2         3  
  2         2406  
11              
12             # Default attribute values put here will BE inherited by subclasses
13             sub brik_properties {
14             return {
15 0     0 1   revision => '$Revision$',
16             tags => [ qw(unstable ns nameserver) ],
17             author => 'GomoR ',
18             license => 'http://opensource.org/licenses/BSD-3-Clause',
19             attributes => {
20             nameserver => [ qw(ip_address|$ip_address_list) ],
21             port => [ qw(port) ],
22             use_recursion => [ qw(0|1) ],
23             try => [ qw(try_number) ],
24             rtimeout => [ qw(timeout) ],
25             type => [ qw(query_type) ],
26             resolver => [ qw(INTERNAL) ],
27             use_persistence => [ qw(0|1) ],
28             src_ip_address => [ qw(ip_address) ],
29             src_port => [ qw(port) ],
30             },
31             attributes_default => {
32             use_recursion => 0,
33             port => 53,
34             try => 3,
35             rtimeout => 2,
36             type => 'A',
37             use_persistence => 0,
38             },
39             commands => {
40             create_resolver => [ qw(nameserver|OPTIONAL port|OPTIONAL) ],
41             reset_resolver => [ ],
42             lookup => [ qw(hostname|ip_address type|OPTIONAL nameserver|OPTIONAL port|OPTIONAL) ],
43             background_lookup => [ qw(hostname|ip_address type|OPTIONAL nameserver|OPTIONAL port|OPTIONAL) ],
44             background_read => [ qw(handle) ],
45             version_bind => [ qw(hostname|ip_address) ],
46             },
47             require_modules => {
48             'Net::DNS::Resolver' => [ ],
49             },
50             };
51             }
52              
53             sub create_resolver {
54 0     0 0   my $self = shift;
55 0           my ($nameserver, $port, $timeout) = @_;
56              
57 0   0       $nameserver ||= $self->nameserver;
58 0   0       $port ||= $self->port;
59 0   0       $timeout ||= $self->rtimeout;
60 0 0         $self->brik_help_run_undef_arg('create_resolver', $nameserver) or return;
61 0 0         my $ref = $self->brik_help_run_invalid_arg('create_resolver', $nameserver, 'ARRAY', 'SCALAR')
62             or return;
63              
64 0           my $try = $self->try;
65 0           my $persist = $self->use_persistence;
66 0           my $src_ip_address = $self->src_ip_address;
67 0           my $src_port = $self->src_port;
68              
69 0 0         my %args = (
70             recurse => $self->use_recursion,
71             searchlist => [],
72             debug => $self->log->level > 2 ? 1 : 0,
73             tcp_timeout => $timeout,
74             udp_timeout => $timeout,
75             port => $port,
76             persistent_udp => $persist,
77             persistent_tcp => $persist,
78             retrans => $timeout,
79             retry => $try,
80             );
81              
82 0 0         if (defined($src_ip_address)) {
83 0           $self->log->debug("create_resolver: using source IP [$src_ip_address]");
84 0           $args{srcaddr} = $src_ip_address;
85             }
86 0 0         if (defined($src_port)) {
87 0           $self->log->debug("create_resolver: using source port [$src_port]");
88 0           $args{srcport} = $src_port;
89             }
90              
91 0 0         if ($ref eq 'ARRAY') {
92 0           $self->log->debug("create_resolver: using nameserver [".join('|', @$nameserver)."]");
93 0           $args{nameservers} = $nameserver;
94             }
95             else {
96 0           $self->log->debug("create_resolver: using nameserver [$nameserver]");
97 0           $args{nameservers} = [ $nameserver ];
98             }
99              
100 0           my $resolver = Net::DNS::Resolver->new(%args);
101 0 0         if (! defined($resolver)) {
102 0           return $self->log->error("create_resolver: Net::DNS::Resolver new failed");
103             }
104              
105 0           $self->resolver($resolver);
106              
107 0           return 1;
108             }
109              
110             sub reset_resolver {
111 0     0 0   my $self = shift;
112              
113 0           $self->resolver(undef);
114              
115 0           return 1;
116             }
117              
118             sub lookup {
119 0     0 0   my $self = shift;
120 0           my ($host, $type, $nameserver, $port) = @_;
121              
122 0   0       $type ||= $self->type;
123 0   0       $nameserver ||= $self->nameserver;
124 0   0       $port ||= $self->port;
125 0 0         $self->brik_help_run_undef_arg('lookup', $host) or return;
126 0 0         $self->brik_help_run_undef_arg('lookup', $nameserver) or return;
127              
128 0           my $resolver = $self->resolver;
129 0 0         if (! defined($resolver)) {
130 0 0         $self->create_resolver($nameserver, $port) or return;
131 0           $resolver = $self->resolver;
132             }
133              
134 0           $self->log->debug("lookup: host [$host] for type [$type]");
135              
136 0           my $packet;
137 0           eval {
138 0           $packet = $resolver->send($host, $type);
139             };
140 0 0         if ($@) {
    0          
141 0           chomp($@);
142 0           return $self->log->error("lookup: send exception [$@]");
143             }
144             elsif (! defined($packet)) {
145 0           return $self->log->error("lookup: query failed [".$resolver->errorstring."]");
146             }
147              
148 0           $self->log->debug("lookup: ".$packet->string);
149              
150 0           my @res = ();
151 0           my @answers = $packet->answer;
152 0           for my $rr (@answers) {
153 0           $self->log->debug("lookup: ".$rr->string);
154              
155 0           my $h = {
156             type => $rr->type,
157             ttl => $rr->ttl,
158             name => $rr->name,
159             string => $rr->string,
160             raw => $rr,
161             };
162 0 0         if ($rr->can('address')) {
163 0           $h->{address} = $rr->address;
164             }
165 0 0         if ($rr->can('cname')) {
166 0           $h->{cname} = $rr->cname;
167             }
168 0 0         if ($rr->can('exchange')) {
169 0           $h->{exchange} = $rr->exchange;
170             }
171 0 0         if ($rr->can('nsdname')) {
172 0           $h->{nsdname} = $rr->nsdname;
173             }
174 0 0         if ($rr->can('ptrdname')) {
175 0           $h->{ptrdname} = $rr->ptrdname;
176             }
177 0 0         if ($rr->can('rdatastr')) {
178 0           $h->{rdatastr} = $rr->rdatastr;
179             }
180 0 0         if ($rr->can('dummy')) {
181 0           $h->{dummy} = $rr->dummy;
182             }
183 0 0         if ($rr->can('target')) {
184 0           $h->{target} = $rr->target;
185             }
186              
187 0           push @res, $h;
188             }
189              
190 0           return \@res;
191             }
192              
193             sub background_lookup {
194 0     0 0   my $self = shift;
195 0           my ($host, $type, $nameserver, $port) = @_;
196              
197 0   0       $type ||= $self->type;
198 0   0       $nameserver ||= $self->nameserver;
199 0   0       $port ||= $self->port;
200 0 0         $self->brik_help_run_undef_arg('background_lookup', $host) or return;
201 0 0         $self->brik_help_run_undef_arg('background_lookup', $nameserver) or return;
202              
203 0           my $resolver = $self->resolver;
204 0 0         if (! defined($resolver)) {
205 0 0         $self->create_resolver($nameserver, $port) or return;
206 0           $resolver = $self->resolver;
207             }
208              
209 0           $self->log->debug("background_lookup: host [$host] for type [$type]");
210              
211 0           my $handle;
212 0           eval {
213 0           $handle = $resolver->bgsend($host, $type);
214             };
215 0 0         if ($@) {
    0          
216 0           chomp($@);
217 0 0         my $ns = ref($nameserver) eq 'ARRAY' ? join('|', @$nameserver)
218             : $nameserver;
219 0           return $self->log->error("background_lookup: bgsend exception [$@], ".
220             "with nameservers [$ns] and port [$port]");
221             }
222             elsif (! defined($handle)) {
223 0 0         my $ns = ref($nameserver) eq 'ARRAY' ? join('|', @$nameserver)
224             : $nameserver;
225 0           return $self->log->error("background_lookup: query failed [".
226             $resolver->errorstring."], with nameservers [$ns] and ".
227             "port [$port]");
228             }
229              
230 0           return $handle;
231             }
232              
233             sub background_read {
234 0     0 0   my $self = shift;
235 0           my ($handle) = @_;
236              
237 0           my $resolver = $self->resolver;
238 0 0         $self->brik_help_set_undef_arg('resolver', $resolver) or return;
239 0 0         $self->brik_help_run_undef_arg('background_read', $handle) or return;
240 0 0         $self->brik_help_run_invalid_arg('background_read', $handle, 'IO::Socket::IP')
241             or return;
242              
243             # Answer not ready
244 0 0         if ($resolver->bgbusy($handle)) {
245 0           return 0;
246             }
247              
248 0           my $packet;
249 0           eval {
250 0           $packet = $resolver->bgread($handle);
251             };
252 0 0         if ($@) {
    0          
253 0           chomp($@);
254 0           return $self->log->error("background_read: bgread exception [$@]");
255             }
256             elsif (! defined($packet)) {
257 0           return []; # No error checking possible, undef means no response or timeout.
258             }
259              
260 0           $self->log->debug("background_read: ".$packet->string);
261              
262 0           my @res = ();
263 0           my @answers = $packet->answer;
264 0           for my $rr (@answers) {
265 0           $self->log->debug("background_read: ".$rr->string);
266              
267 0           my $h = {
268             type => $rr->type,
269             ttl => $rr->ttl,
270             name => $rr->name,
271             string => $rr->string,
272             raw => $rr,
273             };
274 0 0         if ($rr->can('address')) {
275 0           $h->{address} = $rr->address;
276             }
277 0 0         if ($rr->can('cname')) {
278 0           $h->{cname} = $rr->cname;
279             }
280 0 0         if ($rr->can('exchange')) {
281 0           $h->{exchange} = $rr->exchange;
282             }
283 0 0         if ($rr->can('nsdname')) {
284 0           $h->{nsdname} = $rr->nsdname;
285             }
286 0 0         if ($rr->can('ptrdname')) {
287 0           $h->{ptrdname} = $rr->ptrdname;
288             }
289 0 0         if ($rr->can('rdatastr')) {
290 0           $h->{rdatastr} = $rr->rdatastr;
291             }
292 0 0         if ($rr->can('dummy')) {
293 0           $h->{dummy} = $rr->dummy;
294             }
295 0 0         if ($rr->can('target')) {
296 0           $h->{target} = $rr->target;
297             }
298              
299 0           push @res, $h;
300             }
301              
302 0           return \@res;
303             }
304              
305             sub version_bind {
306 0     0 0   my $self = shift;
307 0           my ($nameserver, $port) = @_;
308              
309 0   0       $nameserver ||= $self->nameserver;
310 0   0       $port ||= $self->port || 53;
      0        
311 0 0         $self->brik_help_run_undef_arg('version_bind', $nameserver) or return;
312              
313 0           my $timeout = $self->rtimeout;
314              
315 0 0         my $resolver = Net::DNS::Resolver->new(
316             nameservers => [ $nameserver, ],
317             recurse => $self->use_recursion,
318             searchlist => [],
319             tcp_timeout => $timeout,
320             udp_timeout => $timeout,
321             port => $port,
322             debug => $self->log->level > 2 ? 1 : 0,
323             );
324 0 0         if (! defined($resolver)) {
325 0           return $self->log->error("version_bind: Net::DNS::Resolver new failed");
326             }
327              
328 0           my $version = 0;
329 0           my $res = $resolver->send('version.bind', 'TXT', 'CH');
330 0 0 0       if (defined($res) && exists($res->{answer})) {
331 0           my $rr = $res->{answer}->[0];
332 0 0 0       if (defined($rr) && exists($rr->{rdata})) {
333 0           $version = unpack('H*', $rr->{rdata});
334             }
335             }
336              
337 0           $self->log->verbose("version_bind: version [$version]");
338              
339 0           return $version;
340             }
341              
342             1;
343              
344             __END__