File Coverage

blib/lib/Zonemaster/Engine/Test/Address.pm
Criterion Covered Total %
statement 112 115 97.3
branch 34 42 80.9
condition 17 26 65.3
subroutine 20 20 100.0
pod 8 8 100.0
total 191 211 90.5


line stmt bran cond sub pod time code
1             package Zonemaster::Engine::Test::Address;
2              
3 26     26   154 use version; our $VERSION = version->declare("v1.0.3");
  26         57  
  26         130  
4              
5 26     26   1917 use strict;
  26         57  
  26         430  
6 26     26   110 use warnings;
  26         54  
  26         543  
7              
8 26     26   353 use 5.014002;
  26         161  
9              
10 26     26   129 use Zonemaster::Engine;
  26         65  
  26         482  
11 26     26   107 use Zonemaster::Engine::Util;
  26         62  
  26         1291  
12 26     26   138 use Zonemaster::Engine::TestMethods;
  26         51  
  26         563  
13 26     26   1108 use Zonemaster::Engine::Constants qw[:addresses :ip];
  26         64  
  26         4349  
14 26     26   186 use List::MoreUtils qw[none any];
  26         56  
  26         197  
15              
16 26     26   16519 use Carp;
  26         64  
  26         27061  
17              
18             ###
19             ### Entry Points
20             ###
21              
22             sub all {
23 6     6 1 21 my ( $class, $zone ) = @_;
24 6         13 my @results;
25              
26 6 50       27 push @results, $class->address01( $zone ) if Zonemaster::Engine->config->should_run( 'address01' );
27 5 50       30 push @results, $class->address02( $zone ) if Zonemaster::Engine->config->should_run( 'address02' );
28             # Perform ADDRESS03 if ADDRESS02 passed
29 5 100   10   61 if ( any { $_->tag eq q{NAMESERVERS_IP_WITH_REVERSE} } @results ) {
  10         312  
30 3 50       18 push @results, $class->address03( $zone ) if Zonemaster::Engine->config->should_run( 'address03' );
31             }
32              
33 5         46 return @results;
34             }
35              
36             ###
37             ### Metadata Exposure
38             ###
39              
40             sub metadata {
41 5     5 1 11 my ( $class ) = @_;
42              
43             return {
44 5         41 address01 => [
45             qw(
46             NAMESERVER_IP_PRIVATE_NETWORK
47             NO_IP_PRIVATE_NETWORK
48             )
49             ],
50             address02 => [
51             qw(
52             NAMESERVER_IP_WITHOUT_REVERSE
53             NAMESERVERS_IP_WITH_REVERSE
54             NO_RESPONSE_PTR_QUERY
55             )
56             ],
57             address03 => [
58             qw(
59             NAMESERVER_IP_WITHOUT_REVERSE
60             NAMESERVER_IP_PTR_MISMATCH
61             NAMESERVER_IP_PTR_MATCH
62             NO_RESPONSE_PTR_QUERY
63             )
64             ],
65             };
66             } ## end sub metadata
67              
68             sub translation {
69             return {
70 1     1 1 9 'NAMESERVER_IP_WITHOUT_REVERSE' => 'Nameserver {ns} has an IP address ({address}) without PTR configured.',
71             'NAMESERVER_IP_PTR_MISMATCH' =>
72             'Nameserver {ns} has an IP address ({address}) with mismatched PTR result ({names}).',
73             'NAMESERVER_IP_PRIVATE_NETWORK' =>
74             'Nameserver {ns} has an IP address ({address}) with prefix {prefix} referenced in {reference} as a \'{name}\'.',
75             'NO_IP_PRIVATE_NETWORK' => 'All Nameserver addresses are in the routable public addressing space.',
76             'NAMESERVERS_IP_WITH_REVERSE' => 'Reverse DNS entry exist for all Nameserver IP addresses.',
77             'NAMESERVER_IP_PTR_MATCH' => 'All reverse DNS entry matches name server name.',
78             'NO_RESPONSE_PTR_QUERY' => 'No response from nameserver(s) on PTR query ({reverse}).',
79             };
80             }
81              
82             sub version {
83 9     9 1 112 return "$Zonemaster::Engine::Test::Address::VERSION";
84             }
85              
86             sub find_special_address {
87 63     63 1 153 my ( $class, $ip ) = @_;
88 63         98 my @special_addresses;
89              
90 63 100       157 if ( $ip->version == $IP_VERSION_4 ) {
    50          
91 38         479 @special_addresses = @IPV4_SPECIAL_ADDRESSES;
92             }
93             elsif ( $ip->version == $IP_VERSION_6 ) {
94 25         487 @special_addresses = @IPV6_SPECIAL_ADDRESSES;
95             }
96              
97 63         4783 foreach my $ip_details ( @special_addresses ) {
98 987 100       151245 if ( $ip->overlaps( ${$ip_details}{ip} ) ) {
  987         3149  
99 32         9732 return $ip_details;
100             }
101             }
102              
103 31         2894 return;
104             }
105              
106             sub address01 {
107 6     6 1 20 my ( $class, $zone ) = @_;
108 6         16 my @results;
109             my %ips;
110              
111 6         14 foreach
112 6         42 my $local_ns ( @{ Zonemaster::Engine::TestMethods->method4( $zone ) }, @{ Zonemaster::Engine::TestMethods->method5( $zone ) } )
  6         37  
113             {
114              
115 60 100       4826 next if $ips{ $local_ns->address->short };
116              
117 31         2692 my $ip_details_ref = $class->find_special_address( $local_ns->address );
118              
119 31 100       88 if ( $ip_details_ref ) {
120             push @results,
121             info(
122             NAMESERVER_IP_PRIVATE_NETWORK => {
123             ns => $local_ns->name->string,
124             address => $local_ns->address->short,
125 1         33 prefix => ${$ip_details_ref}{ip}->print,
126 1         52 name => ${$ip_details_ref}{name},
127 1         8 reference => ${$ip_details_ref}{reference},
128             }
129 1         39 );
130             }
131              
132 31         1088 $ips{ $local_ns->address->short }++;
133              
134             } ## end foreach my $local_ns ( @{ Zonemaster::Engine::TestMethods...})
135              
136 6 100 66     502 if ( scalar keys %ips and not scalar @results ) {
137 5         36 push @results, info( NO_IP_PRIVATE_NETWORK => {} );
138             }
139              
140 5         33 return @results;
141             } ## end sub address01
142              
143             sub address02 {
144 6     6 1 22 my ( $class, $zone ) = @_;
145 6         22 my @results;
146              
147             my %ips;
148 6         0 my $ptr_query;
149              
150 6         14 foreach
151 6         35 my $local_ns ( @{ Zonemaster::Engine::TestMethods->method4( $zone ) }, @{ Zonemaster::Engine::TestMethods->method5( $zone ) } )
  6         36  
152             {
153              
154 54 100       4622 next if $ips{ $local_ns->address->short };
155              
156 28         2456 my $reverse_ip_query = $local_ns->address->reverse_ip;
157 28         2238 $ptr_query = $reverse_ip_query;
158              
159 28         157 my $p = Zonemaster::Engine::Recursor->recurse( $ptr_query, q{PTR} );
160              
161             # In case of Classless IN-ADDR.ARPA delegation, query returns
162             # CNAME records. A PTR query is done on the CNAME.
163 28 100 66     232 if ( $p and $p->rcode eq q{NOERROR} and $p->get_records( q{CNAME}, q{answer} ) ) {
      100        
164 3         15 my ( $cname ) = $p->get_records( q{CNAME}, q{answer} );
165 3         74 $ptr_query = $cname->cname;
166 3         19 $p = Zonemaster::Engine::Recursor->recurse( $ptr_query, q{PTR} );
167             }
168              
169 28 50       144 if ( $p ) {
170 28 100 66     107 if ( $p->rcode ne q{NOERROR} or not $p->get_records( q{PTR}, q{answer} ) ) {
171 2         75 push @results,
172             info(
173             NAMESERVER_IP_WITHOUT_REVERSE => {
174             ns => $local_ns->name->string,
175             address => $local_ns->address->short,
176             }
177             );
178             }
179             }
180             else {
181 0         0 push @results,
182             info(
183             NO_RESPONSE_PTR_QUERY => {
184             reverse => $ptr_query,
185             }
186             );
187             }
188              
189 28         859 $ips{ $local_ns->address->short }++;
190              
191             } ## end foreach my $local_ns ( @{ Zonemaster::Engine::TestMethods...})
192              
193 6 100 66     423 if ( scalar keys %ips and not scalar @results ) {
194 4         24 push @results, info( NAMESERVERS_IP_WITH_REVERSE => {} );
195             }
196              
197 6         34 return @results;
198             } ## end sub address02
199              
200             sub address03 {
201 5     5 1 18 my ( $class, $zone ) = @_;
202 5         237 my @results;
203             my $ptr_query;
204              
205 5         0 my %ips;
206              
207 5         12 foreach my $local_ns ( @{ Zonemaster::Engine::TestMethods->method5( $zone ) } ) {
  5         30  
208              
209 25 50       113 next if $ips{ $local_ns->address->short };
210              
211 25         2313 my $reverse_ip_query = $local_ns->address->reverse_ip;
212 25         412 $ptr_query = $reverse_ip_query;
213              
214 25         121 my $p = Zonemaster::Engine::Recursor->recurse( $ptr_query, q{PTR} );
215              
216             # In case of Classless IN-ADDR.ARPA delegation, query returns
217             # CNAME records. A PTR query is done on the CNAME.
218 25 100 33     150 if ( $p and $p->rcode eq q{NOERROR} and $p->get_records( q{CNAME}, q{answer} ) ) {
      66        
219 3         11 my ( $cname ) = $p->get_records( q{CNAME}, q{answer} );
220 3         33 $ptr_query = $cname->cname;
221 3         14 $p = Zonemaster::Engine::Recursor->recurse( $ptr_query, q{PTR} );
222             }
223              
224 25 50       78 if ( $p ) {
225 25         92 my @ptr = $p->get_records_for_name( q{PTR}, $ptr_query );
226 25 50 50     102 if ( $p->rcode eq q{NOERROR} and scalar @ptr ) {
227 25 100   26   589 if ( none { name( $_->ptrdname ) eq $local_ns->name->string . q{.} } @ptr ) {
  26         415  
228             push @results,
229             info(
230             NAMESERVER_IP_PTR_MISMATCH => {
231             ns => $local_ns->name->string,
232             address => $local_ns->address->short,
233 7         216 names => join( q{/}, map { $_->ptrdname } @ptr ),
  7         442  
234             }
235             );
236             }
237             }
238             else {
239 0         0 push @results,
240             info(
241             NAMESERVER_IP_WITHOUT_REVERSE => {
242             ns => $local_ns->name->string,
243             address => $local_ns->address->short,
244             }
245             );
246             }
247             } ## end if ( $p )
248             else {
249 0         0 push @results,
250             info(
251             NO_RESPONSE_PTR_QUERY => {
252             reverse => $ptr_query,
253             }
254             );
255             }
256              
257 25         684 $ips{ $local_ns->address->short }++;
258              
259             } ## end foreach my $local_ns ( @{ Zonemaster::Engine::TestMethods...})
260              
261 5 100 66     53 if ( scalar keys %ips and not scalar @results ) {
262 3         15 push @results, info( NAMESERVER_IP_PTR_MATCH => {} );
263             }
264              
265 5         31 return @results;
266             } ## end sub address03
267              
268             1;
269              
270             =head1 NAME
271              
272             Zonemaster::Engine::Test::Address - module implementing tests focused on the Address specific test cases of the DNS tests
273              
274             =head1 SYNOPSIS
275              
276             my @results = Zonemaster::Engine::Test::Address->all($zone);
277              
278             =head1 METHODS
279              
280             =over
281              
282             =item all($zone)
283              
284             Runs the default set of tests and returns a list of log entries made by the tests
285              
286             =item metadata()
287              
288             Returns a reference to a hash, the keys of which are the names of all test methods in the module, and the corresponding values are references to
289             lists with all the tags that the method can use in log entries.
290              
291             =item translation()
292              
293             Returns a refernce to a hash with translation data. Used by the builtin translation system.
294              
295             =item version()
296              
297             Returns a version string for the module.
298              
299             =back
300              
301             =head1 TESTS
302              
303             =over
304              
305             =item address01($zone)
306              
307             Verify that IPv4 addresse are not in private networks.
308              
309             =item address02($zone)
310              
311             Verify reverse DNS entries exist for nameservers IP addresses.
312              
313             =item address03($zone)
314              
315             Verify that reverse DNS entries match nameservers names.
316              
317             =item find_special_address($ip)
318              
319             Verify that an address (Net::IP::XS) given is a special (private, reserved, ...) one.
320              
321             =back
322              
323             =cut
324