line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Zonemaster::Engine::Config; |
2
|
|
|
|
|
|
|
|
3
|
26
|
|
|
26
|
|
67309
|
use version; our $VERSION = version->declare("v1.0.6"); |
|
26
|
|
|
|
|
2030
|
|
|
26
|
|
|
|
|
197
|
|
4
|
|
|
|
|
|
|
|
5
|
26
|
|
|
26
|
|
2943
|
use 5.014002; |
|
26
|
|
|
|
|
105
|
|
6
|
26
|
|
|
26
|
|
140
|
use warnings; |
|
26
|
|
|
|
|
52
|
|
|
26
|
|
|
|
|
785
|
|
7
|
|
|
|
|
|
|
|
8
|
26
|
|
|
26
|
|
559
|
use Moose; |
|
26
|
|
|
|
|
521924
|
|
|
26
|
|
|
|
|
198
|
|
9
|
26
|
|
|
26
|
|
162187
|
use JSON::PP; |
|
26
|
|
|
|
|
11196
|
|
|
26
|
|
|
|
|
1908
|
|
10
|
26
|
|
|
26
|
|
2065
|
use File::ShareDir qw[dist_dir dist_file]; |
|
26
|
|
|
|
|
24402
|
|
|
26
|
|
|
|
|
1483
|
|
11
|
26
|
|
|
26
|
|
9971
|
use File::Slurp; |
|
26
|
|
|
|
|
160831
|
|
|
26
|
|
|
|
|
1673
|
|
12
|
26
|
|
|
26
|
|
8361
|
use Hash::Merge; |
|
26
|
|
|
|
|
52527
|
|
|
26
|
|
|
|
|
1110
|
|
13
|
26
|
|
|
26
|
|
188
|
use File::Spec; |
|
26
|
|
|
|
|
61
|
|
|
26
|
|
|
|
|
616
|
|
14
|
|
|
|
|
|
|
|
15
|
26
|
|
|
26
|
|
473
|
use Zonemaster::Engine; |
|
26
|
|
|
|
|
60
|
|
|
26
|
|
|
|
|
30764
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
has 'cfiles' => ( is => 'ro', isa => 'ArrayRef', default => sub { [] } ); |
18
|
|
|
|
|
|
|
has 'pfiles' => ( is => 'ro', isa => 'ArrayRef', default => sub { [] } ); |
19
|
|
|
|
|
|
|
has 'testcases' => ( is => 'ro', isa => 'HashRef', default => sub { {} } ); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
my $merger = Hash::Merge->new; |
22
|
|
|
|
|
|
|
$merger->specify_behavior( |
23
|
|
|
|
|
|
|
{ |
24
|
|
|
|
|
|
|
'SCALAR' => { |
25
|
|
|
|
|
|
|
'SCALAR' => sub { $_[1] }, |
26
|
|
|
|
|
|
|
'ARRAY' => sub { [ $_[0], @{ $_[1] } ] }, |
27
|
|
|
|
|
|
|
'HASH' => sub { $_[1] }, |
28
|
|
|
|
|
|
|
}, |
29
|
|
|
|
|
|
|
'ARRAY' => { |
30
|
|
|
|
|
|
|
'SCALAR' => sub { $_[1] }, |
31
|
|
|
|
|
|
|
'ARRAY' => sub { [ @{ $_[1] } ] }, |
32
|
|
|
|
|
|
|
'HASH' => sub { $_[1] }, |
33
|
|
|
|
|
|
|
}, |
34
|
|
|
|
|
|
|
'HASH' => { |
35
|
|
|
|
|
|
|
'SCALAR' => sub { $_[1] }, |
36
|
|
|
|
|
|
|
'ARRAY' => sub { [ values %{ $_[0] }, @{ $_[1] } ] }, |
37
|
|
|
|
|
|
|
'HASH' => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) }, |
38
|
|
|
|
|
|
|
}, |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
our $config; |
43
|
|
|
|
|
|
|
_load_base_config(); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
our $policy = {}; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub BUILD { |
48
|
24
|
|
|
24
|
1
|
63
|
my ( $self ) = @_; |
49
|
|
|
|
|
|
|
|
50
|
24
|
|
|
|
|
95
|
foreach my $dir ( _config_directory_list() ) { |
51
|
96
|
|
|
|
|
1348
|
my $cfile = File::Spec->catfile( $dir, 'config.json' ); |
52
|
96
|
|
|
|
|
264
|
my $new = eval { decode_json scalar read_file $cfile }; |
|
96
|
|
|
|
|
456
|
|
53
|
96
|
100
|
|
|
|
87692
|
if ( $new ) { |
54
|
24
|
|
|
|
|
196
|
$config = $merger->merge( $config, $new ); |
55
|
24
|
|
|
|
|
488
|
push @{ $self->cfiles }, $cfile; |
|
24
|
|
|
|
|
993
|
|
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
96
|
|
|
|
|
1074
|
my $pfile = File::Spec->catfile( $dir, 'policy.json' ); |
59
|
96
|
|
|
|
|
260
|
$new = eval { decode_json scalar read_file $pfile }; |
|
96
|
|
|
|
|
324
|
|
60
|
96
|
100
|
|
|
|
1530018
|
if ( $new ) { |
61
|
24
|
|
|
|
|
100
|
my $tc = $new->{__testcases__}; |
62
|
24
|
|
|
|
|
75
|
delete $new->{__testcases__}; |
63
|
24
|
|
|
|
|
65
|
foreach my $case ( keys %{$tc} ) { |
|
24
|
|
|
|
|
401
|
|
64
|
1368
|
|
|
|
|
35292
|
$self->testcases->{$case} = $tc->{$case}; |
65
|
|
|
|
|
|
|
} |
66
|
24
|
|
|
|
|
272
|
$policy = $merger->merge( $policy, $new ); |
67
|
24
|
|
|
|
|
1814
|
push @{ $self->pfiles }, $pfile; |
|
24
|
|
|
|
|
891
|
|
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
} ## end foreach my $dir ( _config_directory_list...) |
71
|
|
|
|
|
|
|
|
72
|
24
|
|
|
|
|
881
|
return $self; |
73
|
|
|
|
|
|
|
} ## end sub BUILD |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub get { |
76
|
136306
|
|
|
136306
|
1
|
226834
|
my ( $class ) = @_; |
77
|
|
|
|
|
|
|
|
78
|
136306
|
|
|
|
|
601805
|
return $config; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub policy { |
82
|
29
|
|
|
29
|
1
|
68
|
my ( $class ) = @_; |
83
|
|
|
|
|
|
|
|
84
|
29
|
50
|
|
|
|
94
|
if ( not $policy ) { |
85
|
0
|
|
|
|
|
0
|
_load_base_policy(); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
29
|
|
|
|
|
497
|
return $policy; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub _config_directory_list { |
92
|
24
|
|
|
24
|
|
49
|
my @dirlist; |
93
|
24
|
|
|
|
|
64
|
my $makefile_name = 'Zonemaster-Engine'; # This must be the same name as "name" in Makefile.PL |
94
|
24
|
|
|
|
|
151
|
push @dirlist, dist_dir( $makefile_name ); |
95
|
24
|
|
|
|
|
2154
|
push @dirlist, '/etc/zonemaster'; |
96
|
24
|
|
|
|
|
69
|
push @dirlist, '/usr/local/etc/zonemaster'; |
97
|
|
|
|
|
|
|
|
98
|
24
|
|
|
|
|
11832
|
my $dir = ( getpwuid( $> ) )[7]; |
99
|
24
|
50
|
|
|
|
173
|
if ( $dir ) { |
100
|
24
|
|
|
|
|
104
|
push @dirlist, $dir . '/.zonemaster'; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
24
|
|
|
|
|
124
|
return @dirlist; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub _load_base_config { |
107
|
26
|
|
|
26
|
|
670
|
my $internal = decode_json( join( q{}, <DATA> ) ); |
108
|
|
|
|
|
|
|
# my $filename = dist_file( 'Zonemaster', 'config.json' ); |
109
|
|
|
|
|
|
|
# my $default = eval { decode_json scalar read_file $filename }; |
110
|
|
|
|
|
|
|
# |
111
|
|
|
|
|
|
|
# $internal = $merger->merge( $internal, $default ) if $default; |
112
|
|
|
|
|
|
|
|
113
|
26
|
|
|
|
|
71397
|
$config = $internal; |
114
|
|
|
|
|
|
|
|
115
|
26
|
|
|
|
|
76
|
return; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub load_module_policy { |
119
|
218
|
|
|
218
|
1
|
682
|
my ( $class, $mod ) = @_; |
120
|
|
|
|
|
|
|
|
121
|
218
|
|
|
|
|
632
|
my $m = 'Zonemaster::Engine::Test::' . $mod; |
122
|
218
|
100
|
66
|
|
|
2745
|
if ( $m->can( 'policy' ) and $m->policy ) { |
123
|
76
|
|
|
|
|
268
|
$policy = $merger->merge( $policy, { $mod => $m->policy } ); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
218
|
|
|
|
|
8896
|
return; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub load_config_file { |
130
|
2
|
|
|
2
|
1
|
8
|
my ( $self, $filename ) = @_; |
131
|
2
|
|
|
|
|
12
|
my $new = decode_json scalar read_file $filename; |
132
|
|
|
|
|
|
|
|
133
|
2
|
50
|
|
|
|
7950
|
if ( $new ) { |
134
|
2
|
|
|
|
|
21
|
$config = $merger->merge( $config, $new ); |
135
|
2
|
100
|
66
|
|
|
71
|
push @{ $self->cfiles }, $filename if ( ref( $self ) and $self->isa( __PACKAGE__ ) ); |
|
1
|
|
|
|
|
45
|
|
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
2
|
|
|
|
|
17
|
return !!$new; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub load_policy_file { |
142
|
31
|
|
|
31
|
1
|
97
|
my ( $self, $filename ) = @_; |
143
|
|
|
|
|
|
|
|
144
|
31
|
50
|
|
|
|
1026
|
if ( not -r $filename ) { |
145
|
0
|
|
|
|
|
0
|
foreach my $dir ( _config_directory_list() ) { |
146
|
0
|
|
|
|
|
0
|
my $name = File::Spec->catfile( $dir, $filename ); |
147
|
0
|
0
|
|
|
|
0
|
if ( -r $name ) { |
148
|
0
|
|
|
|
|
0
|
$filename = $name; |
149
|
0
|
|
|
|
|
0
|
last; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
else { |
152
|
0
|
0
|
|
|
|
0
|
if ( -r $name . '.json' ) { |
153
|
0
|
|
|
|
|
0
|
$filename = $name . '.json'; |
154
|
0
|
|
|
|
|
0
|
last; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
31
|
|
|
|
|
191
|
my $new = decode_json scalar read_file $filename; |
161
|
31
|
50
|
|
|
|
54625
|
if ( $new ) { |
162
|
31
|
|
|
|
|
93
|
my $tc = $new->{__testcases__}; |
163
|
31
|
|
|
|
|
74
|
delete $new->{__testcases__}; |
164
|
31
|
|
|
|
|
63
|
foreach my $case ( keys %{$tc} ) { |
|
31
|
|
|
|
|
168
|
|
165
|
229
|
|
|
|
|
5615
|
$self->testcases->{$case} = $tc->{$case}; |
166
|
|
|
|
|
|
|
} |
167
|
31
|
|
|
|
|
224
|
$policy = $merger->merge( $policy, $new ); |
168
|
31
|
100
|
66
|
|
|
2469
|
push @{ $self->pfiles }, $filename if ( ref( $self ) and $self->isa( __PACKAGE__ ) ); |
|
30
|
|
|
|
|
985
|
|
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
31
|
|
|
|
|
117
|
return !!$new; |
172
|
|
|
|
|
|
|
} ## end sub load_policy_file |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub no_network { |
175
|
52
|
|
|
52
|
1
|
157
|
my ( $class, $value ) = @_; |
176
|
|
|
|
|
|
|
|
177
|
52
|
100
|
|
|
|
183
|
if ( defined( $value ) ) { |
178
|
32
|
|
|
|
|
109
|
$class->get->{no_network} = $value; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
52
|
|
|
|
|
155
|
return $class->get->{no_network}; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub ipv4_ok { |
185
|
11058
|
|
|
11058
|
1
|
30473
|
my ( $class, $value ) = @_; |
186
|
|
|
|
|
|
|
|
187
|
11058
|
100
|
|
|
|
35165
|
if ( defined( $value ) ) { |
188
|
14
|
|
|
|
|
45
|
$class->get->{net}{ipv4} = $value; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
11058
|
|
|
|
|
28970
|
return $class->get->{net}{ipv4}; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub ipv6_ok { |
195
|
14468
|
|
|
14468
|
1
|
39266
|
my ( $class, $value ) = @_; |
196
|
|
|
|
|
|
|
|
197
|
14468
|
100
|
|
|
|
39721
|
if ( defined( $value ) ) { |
198
|
14
|
|
|
|
|
70
|
$class->get->{net}{ipv6} = $value; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
14468
|
|
|
|
|
38063
|
return $class->get->{net}{ipv6}; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub resolver_defaults { |
205
|
21418
|
|
|
21418
|
1
|
55729
|
my ( $class ) = @_; |
206
|
|
|
|
|
|
|
|
207
|
21418
|
|
|
|
|
61282
|
return $class->get->{resolver}{defaults}; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub resolver_source { |
211
|
7
|
|
|
7
|
1
|
26
|
my ( $class, $sourceaddr ) = @_; |
212
|
|
|
|
|
|
|
|
213
|
7
|
100
|
|
|
|
27
|
if ( defined( $sourceaddr ) ) { |
214
|
2
|
|
|
|
|
10
|
$class->get->{resolver}{source} = $sourceaddr; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
7
|
|
|
|
|
27
|
return $class->get->{resolver}{source}; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub logfilter { |
221
|
89236
|
|
|
89236
|
1
|
170978
|
my ( $class ) = @_; |
222
|
|
|
|
|
|
|
|
223
|
89236
|
|
|
|
|
224024
|
return $class->get->{logfilter}; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub asnroots { |
227
|
3
|
|
|
3
|
1
|
12
|
my ( $class ) = @_; |
228
|
|
|
|
|
|
|
|
229
|
3
|
|
|
|
|
11
|
return $class->get->{asnroots}; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub should_run { |
233
|
409
|
|
|
409
|
1
|
1001
|
my ( $self, $name ) = @_; |
234
|
|
|
|
|
|
|
|
235
|
409
|
100
|
|
|
|
11249
|
if ( not defined $self->testcases->{$name} ) { |
|
|
100
|
|
|
|
|
|
236
|
1
|
|
|
|
|
4
|
return 1; # Default to runnings test |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
elsif ( $self->testcases->{$name} ) { |
239
|
244
|
|
|
|
|
2939
|
return 1; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
else { |
242
|
164
|
|
|
|
|
587
|
return; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
26
|
|
|
26
|
|
209
|
no Moose; |
|
26
|
|
|
|
|
57
|
|
|
26
|
|
|
|
|
216
|
|
247
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
1; |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head1 NAME |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Zonemaster::Engine::Config - configuration access module for Zonemaster::Engine |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head1 SYNOPSIS |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Zonemaster::Engine->config->no_network(1); # Forbid network traffic |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
my $value = Zonemaster::Engine::Config->get->{key}{subkey}; # Not really recommended way to access config data |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head1 LOADING CONFIGURATION |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Configuration data is loaded in several stages, each one overlaying the result |
264
|
|
|
|
|
|
|
from the previous one (that is, the later in the list take priority over the |
265
|
|
|
|
|
|
|
earlier). The first stage is hardcoded into the source code and loaded while it |
266
|
|
|
|
|
|
|
is being compiled, to make sure that there will always be some basic |
267
|
|
|
|
|
|
|
information available. Later, when the configuration object is first used, the |
268
|
|
|
|
|
|
|
system will look for a file named F<config.json> in each of a list of |
269
|
|
|
|
|
|
|
directories. If the file exists, is readable and contains proper JSON data, it |
270
|
|
|
|
|
|
|
will be loaded and overlaid on the current internal config. The directories |
271
|
|
|
|
|
|
|
are, in order from first checked to last: |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=over |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=item The L<Zonemaster::Engine> perl module installation directory |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
This is where the installation process puts the default configuration. It is |
278
|
|
|
|
|
|
|
not meant to be modified by the user, and it will be overwritten when the |
279
|
|
|
|
|
|
|
module is upgraded (or reinstalled for any other reason). If you really need to |
280
|
|
|
|
|
|
|
know where it is, you can either check the log message left when loading it or |
281
|
|
|
|
|
|
|
run this command to find the path: |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
perl -MFile::ShareDir=dist_dir -E 'say dist_dir( "Zonemaster" )' |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=item /etc/zonemaster |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Intended to hold system-global configuration changes. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=item /usr/local/etc/zonemaster |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Basically the same as the previous one, but for those who like to keep their |
292
|
|
|
|
|
|
|
locally installed software inside F</usr/local>. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=item ~/.zonemaster |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
That is, a F<.zonemaster> directory in the home directory of the current user. |
297
|
|
|
|
|
|
|
Intended, obviously, for configuration changes local to one particular user. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=back |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
The possible contents of the JSON data is described further down in this manual |
302
|
|
|
|
|
|
|
page. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head1 METHODS FOR CONFIGURATION ITEMS |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=over |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=item no_network([$value]) |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Returns the value of the C<no_network> flag. If given a defined value, sets the value to that value. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=item ipv4_ok([$value]) |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Returns the value of the C<ipv4> flag. If given a defined value, sets the value to that value. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item ipv6_ok([$value]) |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Returns the value of the C<ipv6> flag. If given a defined value, sets the value to that value. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item resolver_defaults() |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Returns a reference to the resolver_defaults hash. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item resolver_source([$addr]) |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Returns the source address all resolver objects should use when sending |
327
|
|
|
|
|
|
|
queries, if one is set. If given an argument, sets the source address to the |
328
|
|
|
|
|
|
|
argument. |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item logfilter() |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
Returns a reference to the logfilter hash. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=item asnroots() |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
Returns a reference to the list of ASN lookup domains. |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=back |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head1 METHODS |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=over |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item get() |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Returns a reference to a hash with configuration values. |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=item policy() |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Returns a reference to the current policy data. The format of that data is described further down in this document. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=item load_policy_file($filename) |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Load policy information from the given file and merge it into the pre-loaded |
355
|
|
|
|
|
|
|
policy. Information from the loaded file overrides the pre-loaded information |
356
|
|
|
|
|
|
|
when the same keys exist in both places. |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
If the given name does not lead directly to a readable file, each of the usual |
359
|
|
|
|
|
|
|
directories will be checked if the name is there. If the plain name isn't, the |
360
|
|
|
|
|
|
|
suffix C<.json> will be appended and another try will be done. For example, a |
361
|
|
|
|
|
|
|
file F<$HOME/.zonemaster/Example.json> may be loaded by calling this method |
362
|
|
|
|
|
|
|
with the string C<"Example">. |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=item load_config_file($filename) |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Load configuration information from the given file and merge it into the pre-loaded config. Information from the loaded file overrides the pre-loaded information when the same keys exist in both places. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=item load_module_policy($module) |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
Loads policy data included in a test module. The argument must be the short |
371
|
|
|
|
|
|
|
form (without the initial C<Zonemaster::Engine::Test::>) and correctly capitalized. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=item BUILD |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
Internal method only mentioned here to please L<Pod::Coverage>. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=item should_run($name) |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Given a test case name, it returns true if that test case should be included in |
380
|
|
|
|
|
|
|
a test run according to the currently active policy or false if not. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=back |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head1 CONFIGURATION DATA |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
The configuration data is stored internally in a nested hash (possibly with arrays as values in places). As of this writing, the file format used is JSON. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
The interesting keys are as follows. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=head2 resolver |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=head3 defaults |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
These are the default flag and timing values used for the resolver objects used to actually send DNS queries. |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=over |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=item usevc |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
If set, only use TCP. Default not set. |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=item retrans |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
The number of seconds between retries. Default 3. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=item dnssec |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
If set, sets the DO flag in queries. Default not set. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=item recurse |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
If set, sets the RD flag in queries. Default not set (and almost certainly should remain that way). |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=item retry |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
The number of times a query is sent before we give up. Can be set to zero, although that's not very useful (since no queries will be sent at all). Defaults to 2. |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=item igntc |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
If set, queries that get truncated UDP responses will be automatically retried over TCP. Default not set. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=back |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head2 net |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=over |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=item ipv4 |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
If set, resolver objects are allowed to send queries over IPv4. Default set. |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=item ipv6 |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
If set, resolver objects are allowed to send queries over IPv6. Default set. |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=back |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head2 no_network |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
If set to a true value, network traffic is forbidden. Use when you want to be sure that any data is only taken from a preloaded cache. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head2 asnroots |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
This key must be a list of domain names. The domains will be assumed to be |
445
|
|
|
|
|
|
|
Cymru-style AS lookup zones. Normally only the first name in the list will be |
446
|
|
|
|
|
|
|
used, the rest are backups in case the earlier ones don't work. |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=head2 logfilter |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
By using this key, the log level of messages can be set in a much more fine-grained way than by the policy file. The intended use is to remove known erroneous results. If you, for example, know that a certain name server is recursive and for some reason should be, you can use this functionality to lower the severity of the complaint about it to a lower level than normal. |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
The data under the C<logfilter> key should be structured like this: |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
Module |
455
|
|
|
|
|
|
|
Tag |
456
|
|
|
|
|
|
|
Array of exceptions |
457
|
|
|
|
|
|
|
"when" |
458
|
|
|
|
|
|
|
Hash with conditions |
459
|
|
|
|
|
|
|
"set" |
460
|
|
|
|
|
|
|
Level to set if all conditions match |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
The hash with conditions should have keys matching the attributes of the log entry that's being filtered (check the translation files to see what they are). The values for the keys should be either a single value that the attribute should be, or an array of values any one of which the attribute should be. |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
A complete entry might could look like this: |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
"SYSTEM": { |
467
|
|
|
|
|
|
|
"FILTER_THIS": [ |
468
|
|
|
|
|
|
|
{ |
469
|
|
|
|
|
|
|
"when": { |
470
|
|
|
|
|
|
|
"count": 1, |
471
|
|
|
|
|
|
|
"type": ["this", "or"] |
472
|
|
|
|
|
|
|
}, |
473
|
|
|
|
|
|
|
"set": "INFO" |
474
|
|
|
|
|
|
|
}, |
475
|
|
|
|
|
|
|
{ |
476
|
|
|
|
|
|
|
"when": { |
477
|
|
|
|
|
|
|
"count": 128, |
478
|
|
|
|
|
|
|
"type": ["that"] |
479
|
|
|
|
|
|
|
}, |
480
|
|
|
|
|
|
|
"set": "INFO" |
481
|
|
|
|
|
|
|
}, |
482
|
|
|
|
|
|
|
{ |
483
|
|
|
|
|
|
|
"when": { |
484
|
|
|
|
|
|
|
"count": 0 |
485
|
|
|
|
|
|
|
}, |
486
|
|
|
|
|
|
|
"set": "WARNING" |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
] |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
This would set the level to C<INFO> for any C<SYSTEM:FILTER_THIS> messages that had a C<count> attribute set to 1 and a C<type> attribute set to either C<this> or C<or>. |
492
|
|
|
|
|
|
|
This also would set the level to C<INFO> for any C<SYSTEM:FILTER_THIS> messages that had a C<count> attribute set to 128 and a C<type> attribute set to C<that>. |
493
|
|
|
|
|
|
|
And this would set the level to C<WARNING> for any C<SYSTEM:FILTER_THIS> messages that had a C<count> attribute set to 0. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=head1 POLICY DATA |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
Like the configuration data, policy data is stored in JSON format. Structurally, it's a bit less complex. All the keys on the top level, with one exception, are names of test implementation modules (without the C<Zonemaster::Engine::Test::> prefix). Each of those keys hold another hash, where the keys are the tags that the module in question can emit and the values are the the severity levels that should apply to the tags. Any tags that are not found in the policy data will default to level C<DEBUG>. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
The one exception is a top-level key C<__testcases__>. The value of that must be a hash where the keys are names of test cases from the test specifications, and the corresponding values are booleans specifying if the test case in question should be executed or not. Any missing test cases are treated as if they had the value C<true> set. The test cases C<basic00>, C<basic01> and C<basic02> will be executed even if their values are set to C<false>, since part of their function is to verify that the given name can be tested at all. The values here only apply when test modules are asked to run all their tests. A test case that is set to C<false> here will still run if asked for specifically. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
The easiest way to create a modified policy is to copy the default one and change the relevant values. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=cut |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
__DATA__ |
506
|
|
|
|
|
|
|
{ |
507
|
|
|
|
|
|
|
"asnroots" : [ "asnlookup.zonemaster.net", "asnlookup.iis.se"], |
508
|
|
|
|
|
|
|
"net" : { |
509
|
|
|
|
|
|
|
"ipv4" : 1, |
510
|
|
|
|
|
|
|
"ipv6" : 1 |
511
|
|
|
|
|
|
|
}, |
512
|
|
|
|
|
|
|
"no_network" : 0, |
513
|
|
|
|
|
|
|
"resolver" : { |
514
|
|
|
|
|
|
|
"defaults" : { |
515
|
|
|
|
|
|
|
"debug" : 0, |
516
|
|
|
|
|
|
|
"dnssec" : 0, |
517
|
|
|
|
|
|
|
"edns_size" : 0, |
518
|
|
|
|
|
|
|
"igntc" : 0, |
519
|
|
|
|
|
|
|
"recurse" : 0, |
520
|
|
|
|
|
|
|
"retrans" : 3, |
521
|
|
|
|
|
|
|
"retry" : 2, |
522
|
|
|
|
|
|
|
"usevc" : 0 |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
} |