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   195809 use version; our $VERSION = version->declare("v1.1.5");
  26         5458  
  26         180  
4              
5 26     26   2778 use 5.014002;
  26         105  
6 26     26   1493 use Moose;
  26         1659286  
  26         148  
7 26     26   150210 use Moose::Util::TypeConstraints;
  26         59  
  26         236  
8              
9 26     26   57796 use Zonemaster::Engine::DNSName;
  26         104  
  26         1358  
10 26     26   1943 use Zonemaster::Engine;
  26         76  
  26         867  
11 26     26   10556 use Zonemaster::Engine::Packet;
  26         94  
  26         1009  
12 26     26   8780 use Zonemaster::Engine::Nameserver::Cache;
  26         102  
  26         957  
13 26     26   8454 use Zonemaster::Engine::Recursor;
  26         87  
  26         1018  
14 26     26   9156 use Zonemaster::Engine::Constants ':misc';
  26         117  
  26         5464  
15              
16 26     26   9009 use Zonemaster::LDNS;
  26         619229  
  26         1426  
17              
18 26     26   215 use Zonemaster::Engine::Net::IP qw(:PROC);
  26         58  
  26         7569  
19 26     26   6935 use Time::HiRes qw[time];
  26         19263  
  26         149  
20 26     26   3498 use JSON::PP;
  26         62  
  26         1486  
21 26     26   196 use MIME::Base64;
  26         54  
  26         1395  
22 26     26   5813 use Module::Find qw[useall];
  26         22122  
  26         1321  
23 26     26   177 use Carp;
  26         61  
  26         1274  
24 26     26   151 use List::Util qw[max min sum];
  26         59  
  26         1473  
25 26     26   5894 use POSIX ();
  26         101330  
  26         1149  
26              
27             use overload
28 26         250 '""' => \&string,
29 26     26   187 'cmp' => \&compare;
  26         59  
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   9 my ( $self ) = @_;
75              
76 3         102 my $res = Zonemaster::LDNS->new( $self->address->ip );
77 3         92 $res->recurse( 0 );
78              
79 3         10 my %defaults = %{ Zonemaster::Engine->config->resolver_defaults };
  3         23  
80 3         15 foreach my $flag ( keys %defaults ) {
81 24         83 $res->$flag( $defaults{$flag} );
82             }
83              
84 3 100       115 if ( $self->source_address ) {
85 2         52 $res->source( $self->source_address );
86             }
87              
88 3         157 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 79715 my ( $self, $name, $type, $href ) = @_;
103 21429   100     65407 $type //= 'A';
104              
105 21429 100 100     604846 if ( $self->address->version == 4 and not Zonemaster::Engine->config->ipv4_ok ) {
106 1         8 Zonemaster::Engine->logger->add( IPV4_BLOCKED => { ns => $self->string } );
107 1         9 return;
108             }
109              
110 21428 100 100     650986 if ( $self->address->version == 6 and not Zonemaster::Engine->config->ipv6_ok ) {
111 16         65 Zonemaster::Engine->logger->add( IPV6_BLOCKED => { ns => $self->string } );
112 16         70 return;
113             }
114              
115             Zonemaster::Engine->logger->add(
116 21412         127296 'query',
117             {
118             name => "$name",
119             type => $type,
120             flags => $href,
121             ip => $self->address->short
122             }
123             );
124              
125 21412         54741 my %defaults = %{ Zonemaster::Engine->config->resolver_defaults };
  21412         82604  
126              
127 21412   100     114266 my $class = $href->{class} // 'IN';
128 21412   66     114427 my $dnssec = $href->{dnssec} // $defaults{dnssec};
129 21412   66     94068 my $usevc = $href->{usevc} // $defaults{usevc};
130 21412   66     97815 my $recurse = $href->{recurse} // $defaults{recurse};
131 21412   66     87002 my $edns_size = $href->{edns_size} // $defaults{edns_size};
132              
133             # Fake a DS answer
134 21412 100 66     81235 if ( $type eq 'DS' and $class eq 'IN' and $self->fake_ds->{ lc( $name ) } ) {
      100        
135 2         44 my $p = Zonemaster::LDNS::Packet->new( $name, $type, $class );
136 2         19 $p->aa( 1 );
137 2         12 $p->do( $dnssec );
138 2         10 $p->rd( $recurse );
139 2         4 foreach my $rr ( @{ $self->fake_ds->{ lc( $name ) } } ) {
  2         79  
140 2         27 $p->unique_push( 'answer', $rr );
141             }
142 2         86 my $res = Zonemaster::Engine::Packet->new( { packet => $p } );
143 2         16 Zonemaster::Engine->logger->add( FAKE_DS_RETURNED => { name => "$name", from => "$self" } );
144 2         17 return $res;
145             }
146              
147             # Fake a delegation
148 21410         43899 foreach my $fname ( sort keys %{ $self->fake_delegations } ) {
  21410         675686  
149 84 100       1829 if ( $name =~ m/([.]|\A)\Q$fname\E\z/xi ) {
150 7         139 my $p = Zonemaster::LDNS::Packet->new( $name, $type, $class );
151              
152 7 100 100     67 if ( lc( $name ) eq lc( $fname ) and $type eq 'NS' ) {
153 1         52 my $name = $self->fake_delegations->{$fname}{authority};
154 1         48 my $addr = $self->fake_delegations->{$fname}{additional};
155 1         4 $p->unique_push( 'answer', $_ ) for @{$name};
  1         46  
156 1         6 $p->unique_push( 'additional', $_ ) for @{$addr};
  1         39  
157             }
158             else {
159 6         24 while ( my ( $section, $aref ) = each %{ $self->fake_delegations->{$fname} } ) {
  18         495  
160 12         22 $p->unique_push( $section, $_ ) for @{$aref};
  12         333  
161             }
162             }
163              
164 7         40 $p->aa( 0 );
165 7         29 $p->do( $dnssec );
166 7         24 $p->rd( $recurse );
167 7         211 $p->answerfrom( $self->address->ip );
168 7         137 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         225 my $res = Zonemaster::Engine::Packet->new( { packet => $p } );
179 7         38 Zonemaster::Engine->logger->add( FAKED_RETURN => { packet => $res->string } );
180 7         142 return $res;
181             } ## end if ( $name =~ m/([.]|\A)\Q$fname\E\z/xi)
182             } ## end foreach my $fname ( sort keys...)
183              
184 21403 100       614312 if ( not exists( $self->cache->data->{"$name"}{"\U$type"}{"\U$class"}{$dnssec}{$usevc}{$recurse}{$edns_size} ) ) {
185 2         16 $self->cache->data->{"$name"}{"\U$type"}{"\U$class"}{$dnssec}{$usevc}{$recurse}{$edns_size} =
186             $self->_query( $name, $type, $href );
187             }
188              
189 21401         566903 my $p = $self->cache->data->{"$name"}{"\U$type"}{"\U$class"}{$dnssec}{$usevc}{$recurse}{$edns_size};
190 21401 100       78747 Zonemaster::Engine->logger->add( CACHED_RETURN => { packet => ( $p ? $p->string : 'undef' ) } );
191              
192 21401         106868 return $p;
193             } ## end sub query
194              
195             sub add_fake_delegation {
196 48     48 1 125 my ( $self, $domain, $href ) = @_;
197 48         75 my %delegation;
198              
199 48         1232 $domain = q{} . Zonemaster::Engine::DNSName->new( $domain );
200 48         1264 foreach my $name ( keys %{$href} ) {
  48         168  
201 166         8027 push @{ $delegation{authority} }, Zonemaster::LDNS::RR->new( sprintf( '%s IN NS %s', $domain, $name ) );
  166         846  
202 166         4355 foreach my $ip ( @{ $href->{$name} } ) {
  166         397  
203 282 100       6689 if ( Zonemaster::Engine::Net::IP->new( $ip )->ip eq $self->address->ip ) {
204 4         33 Zonemaster::Engine->logger->add(
205             FAKE_DELEGATION_TO_SELF => { ns => "$self", domain => $domain, data => $href } );
206 4         69 return;
207             }
208              
209 278 100       1888 push @{ $delegation{additional} },
  278         865  
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         4380 $self->fake_delegations->{$domain} = \%delegation;
215 44         246 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         248 Zonemaster::Engine::Recursor->clear_cache;
219              
220 44         255 return;
221             } ## end sub add_fake_delegation
222              
223             sub add_fake_ds {
224 7     7 1 828 my ( $self, $domain, $aref ) = @_;
225 7         13 my @ds;
226              
227 7 50       25 if ( not ref $domain ) {
228 7         226 $domain = Zonemaster::Engine::DNSName->new( $domain );
229             }
230              
231 7         32 Zonemaster::Engine->logger->add( FAKE_DS => { domain => lc( "$domain" ), data => $aref, ns => "$self" } );
232 7         19 foreach my $href ( @{$aref} ) {
  7         20  
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         29 );
240             }
241              
242 7         591 $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         206 return;
248             } ## end sub add_fake_ds
249              
250             sub _query {
251 3     3   20 my ( $self, $name, $type, $href ) = @_;
252 3         8 my %flags;
253              
254 3   50     15 $type //= 'A';
255 3   50     31 $href->{class} //= 'IN';
256              
257 3 100       13 if ( Zonemaster::Engine->config->no_network ) {
258 2         15 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         4 '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         5  
274              
275             # Make sure we have a value for each flag
276 1         5 foreach my $flag ( keys %defaults ) {
277 8   66     26 $flags{$flag} = $href->{$flag} // $defaults{$flag};
278             }
279              
280             # Set flags for this query
281 1         3 foreach my $flag ( keys %flags ) {
282 8         191 $self->dns->$flag( $flags{$flag} );
283             }
284              
285 1         5 my $before = time();
286 1         3 my $res;
287 1 50       64 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         4 $res = eval { $self->dns->query( "$name", $type, $href->{class} ) };
  1         44  
302 1 50       8 if ( $@ ) {
303 1         4 my $msg = "$@";
304 1         4 chomp( $msg );
305             Zonemaster::Engine->logger->add( LOOKUP_ERROR =>
306 1         5 { message => $msg, ns => "$self", name => "$name", type => $type, class => $href->{class} } );
307 1         26 $self->blacklisted->{ $flags{usevc} }{ $flags{dnssec} } = 1;
308 1 50       5 if ( !$flags{dnssec} ) {
309 1         25 $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         176 $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         4 Zonemaster::Engine->logger->add( EMPTY_RETURN => {} );
334 1         5 return;
335             }
336             } ## end sub _query
337              
338             sub string {
339 60143     60143 1 1988658 my ( $self ) = @_;
340              
341 60143         1625311 return $self->name->string . q{/} . $self->address->short;
342             }
343              
344             sub compare {
345 2     2 1 19 my ( $self, $other, $reverse ) = @_;
346              
347 2         10 return $self->string cmp $other->string;
348             }
349              
350             sub save {
351 2     2 1 6 my ( $class, $filename ) = @_;
352              
353 2         33 my $old = POSIX::setlocale( POSIX::LC_ALL, 'C' );
354 2         21 my $json = JSON::PP->new->allow_blessed->convert_blessed;
355 2 50       414 open my $fh, '>', $filename or die "Cache save failed: $!";
356 2         50 foreach my $name ( keys %object_cache ) {
357 94         9551 foreach my $addr ( keys %{ $object_cache{$name} } ) {
  94         389  
358 151         10456 say $fh "$name $addr " . $json->encode( $object_cache{$name}{$addr}->cache->data );
359             }
360             }
361              
362 2 50       603 close $fh or die $!;
363              
364 2         30 Zonemaster::Engine->logger->add( SAVED_NS_CACHE => { file => $filename } );
365              
366 2         34 POSIX::setlocale( POSIX::LC_ALL, $old );
367 2         26 return;
368             }
369              
370             sub restore {
371 20     20 1 3198 my ( $class, $filename ) = @_;
372              
373 20         150 useall 'Zonemaster::LDNS::RR';
374             my $decode = JSON::PP->new->filter_json_single_key_object(
375             'Zonemaster::LDNS::Packet' => sub {
376 4183     4183   17413666 my ( $ref ) = @_;
377             ## no critic (Modules::RequireExplicitInclusion)
378 4183         94935 my $obj = Zonemaster::LDNS::Packet->new_from_wireformat( decode_base64( $ref->{data} ) );
379 4183         70874 $obj->answerfrom( $ref->{answerfrom} );
380 4183         15137 $obj->timestamp( $ref->{timestamp} );
381              
382 4183         12519 return $obj;
383             }
384             )->filter_json_single_key_object(
385             'Zonemaster::Engine::Packet' => sub {
386 4183     4183   122303 my ( $ref ) = @_;
387              
388 4183         159613 return Zonemaster::Engine::Packet->new( { packet => $ref } );
389             }
390 20         210706 );
391              
392 20 50       1543 open my $fh, '<', $filename or die "Failed to open restore data file: $!\n";
393 20         354 while ( my $line = <$fh> ) {
394 2255         40879 my ( $name, $addr, $data ) = split( / /, $line, 3 );
395 2255         10548 my $ref = $decode->decode( $data );
396 2255         296764 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         830 close $fh;
405              
406 20         109 Zonemaster::Engine->logger->add( RESTORED_NS_CACHE => { file => $filename } );
407              
408 20         431 return;
409             } ## end sub restore
410              
411             sub max_time {
412 1     1 1 5 my ( $self ) = @_;
413              
414 1   50     5 return max( @{ $self->times } ) // 0;
  1         57  
415             }
416              
417             sub min_time {
418 1     1 1 7 my ( $self ) = @_;
419              
420 1   50     3 return min( @{ $self->times } ) // 0;
  1         55  
421             }
422              
423             sub sum_time {
424 2     2 1 8 my ( $self ) = @_;
425              
426 2   50     6 return sum( @{ $self->times } ) // 0;
  2         96  
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         99  
433              
434 2         11 return ( $self->sum_time / scalar( @{ $self->times } ) );
  2         94  
435             }
436              
437             sub median_time {
438 2     2 1 12 my ( $self ) = @_;
439              
440 2         7 my @t = sort { $a <=> $b } @{ $self->times };
  23         64  
  2         102  
441 2         9 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         16 return ( $t[ $c / 2 ] + $t[ ( $c / 2 ) - 1 ] ) / 2;
447             }
448             else {
449 1         12 return $t[ int( $c / 2 ) ];
450             }
451             }
452              
453             sub stddev_time {
454 1     1 1 9 my ( $self ) = @_;
455              
456 1         8 my $avg = $self->average_time;
457 1         4 my $c = scalar( @{ $self->times } );
  1         48  
458              
459 1 50       7 return 0 if $c == 0;
460              
461 1         3 return sqrt( sum( map { ( $_ - $avg )**2 } @{ $self->times } ) / $c );
  8         40  
  1         47  
462             }
463              
464             sub all_known_nameservers {
465 2     2 1 2794 my @res;
466              
467 2         23 foreach my $n ( values %object_cache ) {
468 89         124 push @res, values %{$n};
  89         264  
469             }
470              
471 2         14 return @res;
472             }
473              
474             sub axfr {
475 16     16 1 44 my ( $self, $domain, $callback, $class ) = @_;
476 16   50     67 $class //= 'IN';
477              
478 16 50       48 if ( Zonemaster::Engine->config->no_network ) {
479 16         49 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 72 %object_cache = ();
499              
500 2         11 Zonemaster::Engine::Nameserver::Cache::empty_cache();
501              
502 2         4 return;
503             }
504              
505 26     26   70511 no Moose;
  26         58  
  26         250  
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