File Coverage

blib/lib/Zonemaster/Engine/Nameserver.pm
Criterion Covered Total %
statement 264 282 93.6
branch 36 58 62.0
condition 34 52 65.3
subroutine 41 42 97.6
pod 16 16 100.0
total 391 450 86.8


line stmt bran cond sub pod time code
1             package Zonemaster::Engine::Nameserver;
2              
3 26     26   197895 use version; our $VERSION = version->declare("v1.1.5");
  26         6168  
  26         180  
4              
5 26     26   2730 use 5.014002;
  26         99  
6 26     26   1570 use Moose;
  26         1608441  
  26         143  
7 26     26   154859 use Moose::Util::TypeConstraints;
  26         62  
  26         220  
8              
9 26     26   59205 use Zonemaster::Engine::DNSName;
  26         106  
  26         1368  
10 26     26   1888 use Zonemaster::Engine;
  26         69  
  26         953  
11 26     26   10568 use Zonemaster::Engine::Packet;
  26         90  
  26         1020  
12 26     26   8499 use Zonemaster::Engine::Nameserver::Cache;
  26         88  
  26         968  
13 26     26   8234 use Zonemaster::Engine::Recursor;
  26         82  
  26         965  
14 26     26   8593 use Zonemaster::Engine::Constants ':misc';
  26         97  
  26         5445  
15              
16 26     26   8372 use Zonemaster::LDNS;
  26         599381  
  26         1349  
17              
18 26     26   347 use Zonemaster::Engine::Net::IP qw(:PROC);
  26         70  
  26         7251  
19 26     26   7041 use Time::HiRes qw[time];
  26         19714  
  26         136  
20 26     26   3406 use JSON::PP;
  26         65  
  26         1429  
21 26     26   146 use MIME::Base64;
  26         60  
  26         1367  
22 26     26   5772 use Module::Find qw[useall];
  26         22067  
  26         1297  
23 26     26   173 use Carp;
  26         55  
  26         1524  
24 26     26   156 use List::Util qw[max min sum];
  26         60  
  26         1548  
25 26     26   5729 use POSIX ();
  26         97565  
  26         1025  
26              
27             use overload
28 26         247 '""' => \&string,
29 26     26   169 'cmp' => \&compare;
  26         56  
30              
31             coerce 'Zonemaster::Engine::Net::IP', from 'Str', via { Zonemaster::Engine::Net::IP->new( $_ ) };
32              
33             has 'name' => ( is => 'ro', isa => 'Zonemaster::Engine::DNSName', coerce => 1, required => 0 );
34             has 'address' => ( is => 'ro', isa => 'Zonemaster::Engine::Net::IP', coerce => 1, required => 1 );
35              
36             has 'dns' => ( is => 'ro', isa => 'Zonemaster::LDNS', lazy_build => 1 );
37             has 'cache' => ( is => 'ro', isa => 'Zonemaster::Engine::Nameserver::Cache', lazy_build => 1 );
38             has 'times' => ( is => 'ro', isa => 'ArrayRef', default => sub { [] } );
39              
40             has 'source_address' =>
41             ( is => 'ro', isa => 'Maybe[Str]', lazy => 1, default => sub { return Zonemaster::Engine->config->resolver_source } );
42              
43             has 'fake_delegations' => ( is => 'ro', isa => 'HashRef', default => sub { {} } );
44             has 'fake_ds' => ( is => 'ro', isa => 'HashRef', default => sub { {} } );
45              
46             has 'blacklisted' => ( is => 'rw', isa => 'HashRef', default => sub { {} }, required => 1 );
47              
48             ###
49             ### Variables
50             ###
51              
52             our %object_cache;
53              
54             ###
55             ### Build methods for attributes
56             ###
57              
58             around 'new' => sub {
59             my $orig = shift;
60             my $self = shift;
61              
62             my $obj = $self->$orig( @_ );
63             my $name = lc( q{} . $obj->name );
64             $name = '$$$NONAME' unless $name;
65             if ( not exists $object_cache{$name}{ $obj->address->ip } ) {
66             Zonemaster::Engine->logger->add( NS_CREATED => { name => $name, ip => $obj->address->ip } );
67             $object_cache{$name}{ $obj->address->ip } = $obj;
68             }
69              
70             return $object_cache{$name}{ $obj->address->ip };
71             };
72              
73             sub _build_dns {
74 3     3   10 my ( $self ) = @_;
75              
76 3         98 my $res = Zonemaster::LDNS->new( $self->address->ip );
77 3         88 $res->recurse( 0 );
78              
79 3         6 my %defaults = %{ Zonemaster::Engine->config->resolver_defaults };
  3         18  
80 3         14 foreach my $flag ( keys %defaults ) {
81 24         79 $res->$flag( $defaults{$flag} );
82             }
83              
84 3 100       114 if ( $self->source_address ) {
85 2         52 $res->source( $self->source_address );
86             }
87              
88 3         83 return $res;
89             }
90              
91             sub _build_cache {
92 0     0   0 my ( $self ) = @_;
93              
94 0         0 Zonemaster::Engine::Nameserver::Cache->new( { address => $self->address } );
95             }
96              
97             ###
98             ### Public Methods (and helpers)
99             ###
100              
101             sub query {
102 21429     21429 1 73157 my ( $self, $name, $type, $href ) = @_;
103 21429   100     60822 $type //= 'A';
104              
105 21429 100 100     597179 if ( $self->address->version == 4 and not Zonemaster::Engine->config->ipv4_ok ) {
106 1         5 Zonemaster::Engine->logger->add( IPV4_BLOCKED => { ns => $self->string } );
107 1         5 return;
108             }
109              
110 21428 100 100     638199 if ( $self->address->version == 6 and not Zonemaster::Engine->config->ipv6_ok ) {
111 16         72 Zonemaster::Engine->logger->add( IPV6_BLOCKED => { ns => $self->string } );
112 16         90 return;
113             }
114              
115             Zonemaster::Engine->logger->add(
116 21412         125689 'query',
117             {
118             name => "$name",
119             type => $type,
120             flags => $href,
121             ip => $self->address->short
122             }
123             );
124              
125 21412         57661 my %defaults = %{ Zonemaster::Engine->config->resolver_defaults };
  21412         73565  
126              
127 21412   100     113424 my $class = $href->{class} // 'IN';
128 21412   66     116742 my $dnssec = $href->{dnssec} // $defaults{dnssec};
129 21412   66     93751 my $usevc = $href->{usevc} // $defaults{usevc};
130 21412   66     89009 my $recurse = $href->{recurse} // $defaults{recurse};
131 21412   66     87552 my $edns_size = $href->{edns_size} // $defaults{edns_size};
132              
133             # Fake a DS answer
134 21412 100 66     90176 if ( $type eq 'DS' and $class eq 'IN' and $self->fake_ds->{ lc( $name ) } ) {
      100        
135 2         41 my $p = Zonemaster::LDNS::Packet->new( $name, $type, $class );
136 2         15 $p->aa( 1 );
137 2         11 $p->do( $dnssec );
138 2         10 $p->rd( $recurse );
139 2         5 foreach my $rr ( @{ $self->fake_ds->{ lc( $name ) } } ) {
  2         77  
140 2         31 $p->unique_push( 'answer', $rr );
141             }
142 2         81 my $res = Zonemaster::Engine::Packet->new( { packet => $p } );
143 2         12 Zonemaster::Engine->logger->add( FAKE_DS_RETURNED => { name => "$name", from => "$self" } );
144 2         13 return $res;
145             }
146              
147             # Fake a delegation
148 21410         42989 foreach my $fname ( sort keys %{ $self->fake_delegations } ) {
  21410         665554  
149 84 100       1381 if ( $name =~ m/([.]|\A)\Q$fname\E\z/xi ) {
150 7         112 my $p = Zonemaster::LDNS::Packet->new( $name, $type, $class );
151              
152 7 100 100     45 if ( lc( $name ) eq lc( $fname ) and $type eq 'NS' ) {
153 1         38 my $name = $self->fake_delegations->{$fname}{authority};
154 1         26 my $addr = $self->fake_delegations->{$fname}{additional};
155 1         2 $p->unique_push( 'answer', $_ ) for @{$name};
  1         24  
156 1         3 $p->unique_push( 'additional', $_ ) for @{$addr};
  1         21  
157             }
158             else {
159 6         13 while ( my ( $section, $aref ) = each %{ $self->fake_delegations->{$fname} } ) {
  18         487  
160 12         19 $p->unique_push( $section, $_ ) for @{$aref};
  12         327  
161             }
162             }
163              
164 7         31 $p->aa( 0 );
165 7         25 $p->do( $dnssec );
166 7         24 $p->rd( $recurse );
167 7         173 $p->answerfrom( $self->address->ip );
168 7         105 Zonemaster::Engine->logger->add(
169             'FAKE_DELEGATION',
170             {
171             name => "$name",
172             type => $type,
173             class => $class,
174             from => "$self",
175             }
176             );
177              
178 7         194 my $res = Zonemaster::Engine::Packet->new( { packet => $p } );
179 7         31 Zonemaster::Engine->logger->add( FAKED_RETURN => { packet => $res->string } );
180 7         43 return $res;
181             } ## end if ( $name =~ m/([.]|\A)\Q$fname\E\z/xi)
182             } ## end foreach my $fname ( sort keys...)
183              
184 21403 100       604713 if ( not exists( $self->cache->data->{"$name"}{"\U$type"}{"\U$class"}{$dnssec}{$usevc}{$recurse}{$edns_size} ) ) {
185 2         15 $self->cache->data->{"$name"}{"\U$type"}{"\U$class"}{$dnssec}{$usevc}{$recurse}{$edns_size} =
186             $self->_query( $name, $type, $href );
187             }
188              
189 21401         557649 my $p = $self->cache->data->{"$name"}{"\U$type"}{"\U$class"}{$dnssec}{$usevc}{$recurse}{$edns_size};
190 21401 100       82920 Zonemaster::Engine->logger->add( CACHED_RETURN => { packet => ( $p ? $p->string : 'undef' ) } );
191              
192 21401         113555 return $p;
193             } ## end sub query
194              
195             sub add_fake_delegation {
196 48     48 1 107 my ( $self, $domain, $href ) = @_;
197 48         74 my %delegation;
198              
199 48         1160 $domain = q{} . Zonemaster::Engine::DNSName->new( $domain );
200 48         1181 foreach my $name ( keys %{$href} ) {
  48         149  
201 162         6886 push @{ $delegation{authority} }, Zonemaster::LDNS::RR->new( sprintf( '%s IN NS %s', $domain, $name ) );
  162         796  
202 162         4265 foreach my $ip ( @{ $href->{$name} } ) {
  162         389  
203 278 100       6206 if ( Zonemaster::Engine::Net::IP->new( $ip )->ip eq $self->address->ip ) {
204 4         31 Zonemaster::Engine->logger->add(
205             FAKE_DELEGATION_TO_SELF => { ns => "$self", domain => $domain, data => $href } );
206 4         55 return;
207             }
208              
209 274 100       1835 push @{ $delegation{additional} },
  274         793  
210             Zonemaster::LDNS::RR->new( sprintf( '%s IN %s %s', $name, ( Zonemaster::Engine::Net::IP::ip_is_ipv6( $ip ) ? 'AAAA' : 'A' ), $ip ) );
211             }
212             }
213              
214 44         4659 $self->fake_delegations->{$domain} = \%delegation;
215 44         199 Zonemaster::Engine->logger->add( ADDED_FAKE_DELEGATION => { ns => "$self", domain => $domain, data => $href } );
216              
217             # We're changing the world, so the cache can't be trusted
218 44         180 Zonemaster::Engine::Recursor->clear_cache;
219              
220 44         200 return;
221             } ## end sub add_fake_delegation
222              
223             sub add_fake_ds {
224 7     7 1 623 my ( $self, $domain, $aref ) = @_;
225 7         13 my @ds;
226              
227 7 50       19 if ( not ref $domain ) {
228 7         189 $domain = Zonemaster::Engine::DNSName->new( $domain );
229             }
230              
231 7         30 Zonemaster::Engine->logger->add( FAKE_DS => { domain => lc( "$domain" ), data => $aref, ns => "$self" } );
232 7         17 foreach my $href ( @{$aref} ) {
  7         21  
233             push @ds,
234             Zonemaster::LDNS::RR->new(
235             sprintf(
236             '%s IN DS %d %d %d %s',
237             "$domain", $href->{keytag}, $href->{algorithm}, $href->{type}, $href->{digest}
238             )
239 7         24 );
240             }
241              
242 7         558 $self->fake_ds->{ lc( "$domain" ) } = \@ds;
243              
244             # We're changing the world, so the cache can't be trusted
245 7         42 Zonemaster::Engine::Recursor->clear_cache;
246              
247 7         203 return;
248             } ## end sub add_fake_ds
249              
250             sub _query {
251 3     3   22 my ( $self, $name, $type, $href ) = @_;
252 3         9 my %flags;
253              
254 3   50     12 $type //= 'A';
255 3   50     33 $href->{class} //= 'IN';
256              
257 3 100       13 if ( Zonemaster::Engine->config->no_network ) {
258 2         18 croak sprintf
259             "External query for %s, %s attempted to %s while running with no_network",
260             $name, $type, $self->string;
261             }
262              
263             Zonemaster::Engine->logger->add(
264 1         5 'external_query',
265             {
266             name => "$name",
267             type => $type,
268             flags => $href,
269             ip => $self->address->short
270             }
271             );
272              
273 1         3 my %defaults = %{ Zonemaster::Engine->config->resolver_defaults };
  1         4  
274              
275             # Make sure we have a value for each flag
276 1         5 foreach my $flag ( keys %defaults ) {
277 8   66     24 $flags{$flag} = $href->{$flag} // $defaults{$flag};
278             }
279              
280             # Set flags for this query
281 1         5 foreach my $flag ( keys %flags ) {
282 8         188 $self->dns->$flag( $flags{$flag} );
283             }
284              
285 1         5 my $before = time();
286 1         2 my $res;
287 1 50       27 if ( $self->blacklisted->{ $flags{usevc} }{ $flags{dnssec} } ) {
288             Zonemaster::Engine->logger->add(
289             IS_BLACKLISTED => {
290             message => "Server transport has been blacklisted due to previous failure",
291             ns => "$self",
292             name => "$name",
293             type => $type,
294             class => $href->{class},
295             proto => $flags{usevc} ? q{TCP} : q{UDP},
296             dnssec => $flags{dnssec}
297             }
298 0 0       0 );
299             }
300             else {
301 1         2 $res = eval { $self->dns->query( "$name", $type, $href->{class} ) };
  1         30  
302 1 50       7 if ( $@ ) {
303 1         3 my $msg = "$@";
304 1         4 chomp( $msg );
305             Zonemaster::Engine->logger->add( LOOKUP_ERROR =>
306 1         7 { message => $msg, ns => "$self", name => "$name", type => $type, class => $href->{class} } );
307 1         28 $self->blacklisted->{ $flags{usevc} }{ $flags{dnssec} } = 1;
308 1 50       4 if ( !$flags{dnssec} ) {
309 1         27 $self->blacklisted->{ $flags{usevc} }{ !$flags{dnssec} } = 1;
310             }
311             }
312             }
313 1         2 push @{ $self->times }, ( time() - $before );
  1         27  
314              
315             # Reset to defaults
316 1         5 foreach my $flag ( keys %flags ) {
317 8         191 $self->dns->$flag( $defaults{$flag} );
318             }
319              
320 1 50       5 if ( $res ) {
321 0         0 my $p = Zonemaster::Engine::Packet->new( { packet => $res } );
322 0         0 my $size = length( $p->data );
323 0 0       0 if ( $size > $UDP_COMMON_EDNS_LIMIT ) {
324 0 0       0 my $command = sprintf q{dig @%s %s%s %s}, $self->address->short, $flags{dnssec} ? q{+dnssec } : q{},
325             "$name", $type;
326 0         0 Zonemaster::Engine->logger->add(
327             PACKET_BIG => { size => $size, maxsize => $UDP_COMMON_EDNS_LIMIT, command => $command } );
328             }
329 0         0 Zonemaster::Engine->logger->add( EXTERNAL_RESPONSE => { packet => $p->string } );
330 0         0 return $p;
331             }
332             else {
333 1         5 Zonemaster::Engine->logger->add( EMPTY_RETURN => {} );
334 1         5 return;
335             }
336             } ## end sub _query
337              
338             sub string {
339 60143     60143 1 2005701 my ( $self ) = @_;
340              
341 60143         1607477 return $self->name->string . q{/} . $self->address->short;
342             }
343              
344             sub compare {
345 2     2 1 31 my ( $self, $other, $reverse ) = @_;
346              
347 2         12 return $self->string cmp $other->string;
348             }
349              
350             sub save {
351 2     2 1 8 my ( $class, $filename ) = @_;
352              
353 2         37 my $old = POSIX::setlocale( POSIX::LC_ALL, 'C' );
354 2         29 my $json = JSON::PP->new->allow_blessed->convert_blessed;
355 2 50       497 open my $fh, '>', $filename or die "Cache save failed: $!";
356 2         52 foreach my $name ( keys %object_cache ) {
357 94         10139 foreach my $addr ( keys %{ $object_cache{$name} } ) {
  94         439  
358 151         10766 say $fh "$name $addr " . $json->encode( $object_cache{$name}{$addr}->cache->data );
359             }
360             }
361              
362 2 50       5162 close $fh or die $!;
363              
364 2         40 Zonemaster::Engine->logger->add( SAVED_NS_CACHE => { file => $filename } );
365              
366 2         44 POSIX::setlocale( POSIX::LC_ALL, $old );
367 2         34 return;
368             }
369              
370             sub restore {
371 20     20 1 4350 my ( $class, $filename ) = @_;
372              
373 20         143 useall 'Zonemaster::LDNS::RR';
374             my $decode = JSON::PP->new->filter_json_single_key_object(
375             'Zonemaster::LDNS::Packet' => sub {
376 4183     4183   17561647 my ( $ref ) = @_;
377             ## no critic (Modules::RequireExplicitInclusion)
378 4183         102236 my $obj = Zonemaster::LDNS::Packet->new_from_wireformat( decode_base64( $ref->{data} ) );
379 4183         77275 $obj->answerfrom( $ref->{answerfrom} );
380 4183         15833 $obj->timestamp( $ref->{timestamp} );
381              
382 4183         13273 return $obj;
383             }
384             )->filter_json_single_key_object(
385             'Zonemaster::Engine::Packet' => sub {
386 4183     4183   124872 my ( $ref ) = @_;
387              
388 4183         172905 return Zonemaster::Engine::Packet->new( { packet => $ref } );
389             }
390 20         220669 );
391              
392 20 50       1473 open my $fh, '<', $filename or die "Failed to open restore data file: $!\n";
393 20         345 while ( my $line = <$fh> ) {
394 2255         43591 my ( $name, $addr, $data ) = split( / /, $line, 3 );
395 2255         11885 my $ref = $decode->decode( $data );
396 2255         313899 my $ns = Zonemaster::Engine::Nameserver->new(
397             {
398             name => $name,
399             address => $addr,
400             cache => Zonemaster::Engine::Nameserver::Cache->new( { data => $ref, address => Zonemaster::Engine::Net::IP->new( $addr ) } )
401             }
402             );
403             }
404 20         818 close $fh;
405              
406 20         120 Zonemaster::Engine->logger->add( RESTORED_NS_CACHE => { file => $filename } );
407              
408 20         442 return;
409             } ## end sub restore
410              
411             sub max_time {
412 1     1 1 4 my ( $self ) = @_;
413              
414 1   50     5 return max( @{ $self->times } ) // 0;
  1         53  
415             }
416              
417             sub min_time {
418 1     1 1 4 my ( $self ) = @_;
419              
420 1   50     3 return min( @{ $self->times } ) // 0;
  1         49  
421             }
422              
423             sub sum_time {
424 2     2 1 8 my ( $self ) = @_;
425              
426 2   50     7 return sum( @{ $self->times } ) // 0;
  2         76  
427             }
428              
429             sub average_time {
430 2     2 1 9 my ( $self ) = @_;
431              
432 2 50       6 return 0 if @{ $self->times } == 0;
  2         92  
433              
434 2         14 return ( $self->sum_time / scalar( @{ $self->times } ) );
  2         76  
435             }
436              
437             sub median_time {
438 2     2 1 14 my ( $self ) = @_;
439              
440 2         6 my @t = sort { $a <=> $b } @{ $self->times };
  23         51  
  2         108  
441 2         6 my $c = scalar( @t );
442 2 50       16 if ( $c == 0 ) {
    100          
443 0         0 return 0;
444             }
445             elsif ( $c % 2 == 0 ) {
446 1         13 return ( $t[ $c / 2 ] + $t[ ( $c / 2 ) - 1 ] ) / 2;
447             }
448             else {
449 1         11 return $t[ int( $c / 2 ) ];
450             }
451             }
452              
453             sub stddev_time {
454 1     1 1 12 my ( $self ) = @_;
455              
456 1         7 my $avg = $self->average_time;
457 1         3 my $c = scalar( @{ $self->times } );
  1         38  
458              
459 1 50       6 return 0 if $c == 0;
460              
461 1         4 return sqrt( sum( map { ( $_ - $avg )**2 } @{ $self->times } ) / $c );
  8         32  
  1         38  
462             }
463              
464             sub all_known_nameservers {
465 2     2 1 1886 my @res;
466              
467 2         30 foreach my $n ( values %object_cache ) {
468 89         123 push @res, values %{$n};
  89         277  
469             }
470              
471 2         10 return @res;
472             }
473              
474             sub axfr {
475 16     16 1 46 my ( $self, $domain, $callback, $class ) = @_;
476 16   50     78 $class //= 'IN';
477              
478 16 50       47 if ( Zonemaster::Engine->config->no_network ) {
479 16         48 croak sprintf
480             "External AXFR query for %s attempted to %s while running with no_network",
481             $domain, $self->string;
482             }
483              
484 0 0 0     0 if ( $self->address->version == 4 and not Zonemaster::Engine->config->ipv4_ok ) {
485 0         0 Zonemaster::Engine->logger->add( IPV4_BLOCKED => { ns => $self->string } );
486 0         0 return;
487             }
488              
489 0 0 0     0 if ( $self->address->version == 6 and not Zonemaster::Engine->config->ipv6_ok ) {
490 0         0 Zonemaster::Engine->logger->add( IPV6_BLOCKED => { ns => $self->string } );
491 0         0 return;
492             }
493              
494 0         0 return $self->dns->axfr( $domain, $callback, $class );
495             } ## end sub axfr
496              
497             sub empty_cache {
498 2     2 1 37 %object_cache = ();
499              
500 2         12 Zonemaster::Engine::Nameserver::Cache::empty_cache();
501              
502 2         5 return;
503             }
504              
505 26     26   68936 no Moose;
  26         64  
  26         227  
506             __PACKAGE__->meta->make_immutable( inline_constructor => 0 );
507              
508             1;
509              
510             =head1 NAME
511              
512             Zonemaster::Engine::Nameserver - object representing a DNS nameserver
513              
514             =head1 SYNOPSIS
515              
516             my $ns = Zonemaster::Engine::Nameserver->new({ name => 'ns.nic.se', address => '212.247.7.228' });
517             my $p = $ns->query('www.iis.se', 'AAAA');
518              
519             =head1 DESCRIPTION
520              
521             This is a very central object in the L<Zonemaster::Engine> framework. All DNS
522             communications with the outside world pass through here, so we can do
523             things like synthezising and recording traffic. All the objects are
524             also unique per name/IP pair, and creating a new one with an already
525             existing pair will return the existing object instead of creating a
526             new one. Queries and their responses are cached by IP address, so that
527             a specific query will only be sent once to each address (even if there
528             are multiple objects for that address with different names).
529              
530             Class methods on this class allows saving and loading cache contents.
531              
532             =head1 ATTRIBUTES
533              
534             =over
535              
536             =item name
537              
538             A L<Zonemaster::Engine::DNSName> object holding the nameserver's name.
539              
540             =item address
541              
542             A L<Zonemaster::Engine::Net::IP> object holding the nameserver's address.
543              
544             =item dns
545              
546             The L<Zonemaster::LDNS> object used to actually send and recieve DNS queries.
547              
548             =item cache
549              
550             A reference to a L<Zonemaster::Engine::Nameserver::Cache> object holding the cache of sent queries. Not meant for external use.
551              
552             =item times
553              
554             A reference to a list with elapsed time values for the queries made through this nameserver.
555              
556             =back
557              
558             =head1 CLASS METHODS
559              
560             =over
561              
562             =item save($filename)
563              
564             Save the entire object cache to the given filename, using the
565             byte-order-independent Storable format.
566              
567             =item restore($filename)
568              
569             Replace the entire object cache with the contents of the named file.
570              
571             =item all_known_nameservers()
572              
573             Class method that returns a list of all nameserver objects in the global cache.
574              
575             =item empty_cache()
576              
577             Remove all cached nameserver objects and queries.
578              
579             =back
580              
581             =head1 INSTANCE METHODS
582              
583             =over
584              
585             =item query($name, $type, $flagref)
586              
587             Send a DNS query to the nameserver the object represents. C<$name> and C<$type> are the name and type that will be queried for (C<$type> defaults
588             to 'A' if it's left undefined). C<$flagref> is a reference to a hash, the keys of which are flags and the values are their corresponding values.
589             The available flags are as follows. All but the first directly correspond to methods in the L<Zonemaster::LDNS::Resolver> object.
590              
591             =over
592              
593             =item class
594              
595             Defaults to 'IN' if not set.
596              
597             =item usevc
598              
599             Send the query via TCP (only).
600              
601             =item retrans
602              
603             The retransmission interval
604              
605             =item dnssec
606              
607             Set the DO flag in the query.
608              
609             =item debug
610              
611             Set the debug flag in the resolver, producing output on STDERR as the query process proceeds.
612              
613             =item recurse
614              
615             Set the RD flag in the query.
616              
617             =item udp_timeout
618              
619             Set the UDP timeout for the outgoing UDP socket. May or may not be observed by the underlying network stack.
620              
621             =item tcp_timeout
622              
623             Set the TCP timeout for the outgoing TCP socket. May or may not be observed by the underlying network stack.
624              
625             =item retry
626              
627             Set the number of times the query is tried.
628              
629             =item igntc
630              
631             If set to true, incoming response packets with the TC flag set are not automatically retried over TCP.
632              
633             =back
634              
635             =item string()
636              
637             Returns a string representation of the object. Normally this is just the name and IP address separated by a slash.
638              
639             =item compare($other)
640              
641             Used for overloading comparison operators.
642              
643             =item sum_time()
644              
645             Returns the total time spent sending queries and waiting for responses.
646              
647             =item min_time()
648              
649             Returns the shortest time spent on a query.
650              
651             =item max_time()
652              
653             Returns the longest time spent on a query.
654              
655             =item average_time()
656              
657             Returns the average time spent on queries.
658              
659             =item median_time()
660              
661             Returns the median query time.
662              
663             =item stddev_time()
664              
665             Returns the standard deviation for the whole set of query times.
666              
667             =item add_fake_delegation($domain,$data)
668              
669             Adds fake delegation information to this specific nameserver object. Takes the
670             same arguments as the similarly named method in L<Zonemaster::Engine>. This is
671             primarily used for internal information, and using it directly will likely give
672             confusing results (but may be useful to model certain kinds of
673             misconfigurations).
674              
675             =item add_fake_ds($domain, $data)
676              
677             Adds fake DS information to this nameserver object. Takes the same arguments as
678             the similarly named method in L<Zonemaster::Engine>.
679              
680             =item axfr( $domain, $callback, $class )
681              
682             Does an AXFR for the requested domain from the nameserver. The callback
683             function will be called once for each received RR, with that RR as its only
684             argument. To continue getting more RRs, the callback must return a true value.
685             If it returns a true value, the AXFR will be aborted. See L<Zonemaster::LDNS::axfr>
686             for more details.
687              
688             =back
689              
690             =cut