feat: add full Zonemaster stack with Docker and Spanish UI
- Clone all 5 Zonemaster component repos (LDNS, Engine, CLI, Backend, GUI) - Dockerfile.backend: 8-stage multi-stage build LDNS→Engine→CLI→Backend - Dockerfile.gui: Astro static build served via nginx - docker-compose.yml: backend (internal) + frontend (port 5353) - nginx.conf: root redirects to /es/, /api/ proxied to backend - zonemaster-gui/config.ts: defaultLanguage set to 'es' (Spanish) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
110
zonemaster-engine/util/check-msg-args
Executable file
110
zonemaster-engine/util/check-msg-args
Executable file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env perl
|
||||
use utf8;
|
||||
use strict;
|
||||
use warnings;
|
||||
use open qw(:std :utf8);
|
||||
use feature 'say';
|
||||
|
||||
use Locale::PO;
|
||||
use Try::Tiny;
|
||||
use Getopt::Long qw( GetOptions );
|
||||
use Pod::Usage qw( pod2usage );
|
||||
|
||||
sub extract_perl_braces {
|
||||
my $string = shift;
|
||||
|
||||
# Strip text before the first and after the last brace
|
||||
$string =~ s/^[^{]*{?|}?[^}]*$//g;
|
||||
|
||||
# Extract the fields
|
||||
my @fields = split /}[^{]*{/, $string;
|
||||
|
||||
return @fields;
|
||||
}
|
||||
|
||||
sub diff_perl_braces {
|
||||
my $got_string = shift // die 'undefined value for $got_string';
|
||||
my $expected_string = shift // die 'undefined value for $expected_string';
|
||||
|
||||
my %got_fields = map { $_ => 1 } extract_perl_braces( $got_string );
|
||||
my %expected_fields = map { $_ => 1 } extract_perl_braces( $expected_string );
|
||||
|
||||
my %missing = %expected_fields;
|
||||
delete @missing{ keys %got_fields };
|
||||
|
||||
my %extra = %got_fields;
|
||||
delete @extra{ keys %expected_fields };
|
||||
|
||||
return [ sort keys %missing ], [ sort keys %extra ];
|
||||
}
|
||||
|
||||
sub check_perl_braces {
|
||||
my $po = shift;
|
||||
my $filename = shift;
|
||||
|
||||
my $msgid = $po->dequote( $po->msgid );
|
||||
my $msgstr = $po->dequote( $po->msgstr );
|
||||
my ( $missing, $extra ) = diff_perl_braces( $msgstr, $msgid );
|
||||
|
||||
if ( @{$missing} or @{$extra} ) {
|
||||
say "";
|
||||
say '# ' . $filename . ' line ' . $po->loaded_line_number;
|
||||
print map { "#. $_\n" } split /\n/, $po->automatic // '';
|
||||
say "msgid ", $po->msgid;
|
||||
say "msgstr ", $po->msgstr;
|
||||
for my $field ( @{$missing} ) {
|
||||
say " Only in msgid: {$field}";
|
||||
}
|
||||
for my $field ( @{$extra} ) {
|
||||
say " Only in msgstr: {$field}";
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
my $opt_help = 0;
|
||||
my $opt_man = 0;
|
||||
GetOptions(
|
||||
"help|h" => \$opt_help,
|
||||
"man" => \$opt_man,
|
||||
) or pod2usage( 2 );
|
||||
pod2usage( 1 ) if $opt_help;
|
||||
pod2usage( -verbose => 2 ) if $opt_man;
|
||||
|
||||
for my $filename ( @ARGV ) {
|
||||
my $aref = Locale::PO->load_file_asarray( $filename, 'UTF-8' ) // die "Failed to load PO file '$filename'";
|
||||
for my $po ( @$aref ) {
|
||||
try {
|
||||
if ( $po->has_flag( 'perl-brace-format' ) ) {
|
||||
check_perl_braces( $po, $filename );
|
||||
}
|
||||
}
|
||||
catch {
|
||||
say STDERR "error processing $filename at line " . $po->loaded_line_number . ": " . $_;
|
||||
exit 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
=head1 NAME
|
||||
|
||||
check-msg-args - Verify that PO files have the same args in the msgid and msgstr of their perl-brace-format messages
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
check-msg-args [options] [file ...]
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--help>
|
||||
|
||||
Print a brief help message and exit.
|
||||
|
||||
=item B<--man>
|
||||
|
||||
Print the manual page and exit.
|
||||
|
||||
=back
|
||||
240
zonemaster-engine/util/convert_config_to_profile.pl
Executable file
240
zonemaster-engine/util/convert_config_to_profile.pl
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.14.2;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use version; our $VERSION = version->declare("v1.0.1");
|
||||
|
||||
use Carp;
|
||||
|
||||
use English qw( -no_match_vars );
|
||||
|
||||
use Zonemaster::Engine::Profile;
|
||||
use JSON::XS;
|
||||
use Scalar::Util qw( reftype );
|
||||
use File::Slurp;
|
||||
use Getopt::Long;
|
||||
use File::Basename;
|
||||
use Clone qw(clone);
|
||||
|
||||
my $DEBUG = 0;
|
||||
my $DEST_DIR = q{};
|
||||
my $CONFIG_FILE = q{};
|
||||
my $POLICY_FILE = q{};
|
||||
|
||||
my $scriptName = basename($PROGRAM_NAME);
|
||||
my $dest_dir = q{./};
|
||||
my $config_file = q{};
|
||||
my $policy_file = q{};
|
||||
|
||||
process_options();
|
||||
|
||||
if ( $DEST_DIR ) {
|
||||
$dest_dir = $DEST_DIR;
|
||||
}
|
||||
|
||||
if ( $CONFIG_FILE ) {
|
||||
$config_file = $CONFIG_FILE;
|
||||
}
|
||||
|
||||
if ( $POLICY_FILE ) {
|
||||
$policy_file = $POLICY_FILE;
|
||||
}
|
||||
|
||||
if ($DEBUG) {
|
||||
print "Debug Mode set ON\n";
|
||||
print "Destination directory : $dest_dir\n\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 0: Check Directory existence and Directory/Files permissions
|
||||
#-------------------------------------------------
|
||||
if ( ! -d $dest_dir ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
print "Directory $dest_dir does not exist.\n";
|
||||
unless ( mkdir $dest_dir ) {
|
||||
croak "Unable to create $dest_dir.";
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! -w $dest_dir ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
print "Directory $dest_dir mode must be changed.\n";
|
||||
unless ( chmod (oct(755), $dest_dir) ) {
|
||||
croak "Cannot change directory mode.";
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $config_file ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
croak "A Config file must be provided.";
|
||||
}
|
||||
|
||||
if ( ! -e $config_file ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
croak "Config file $config_file does not exists.";
|
||||
}
|
||||
|
||||
if ( ! -r $config_file ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
croak "Config file $config_file is not readable.";
|
||||
}
|
||||
|
||||
if ( ! $policy_file ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
croak "A Policy file must be provided.";
|
||||
}
|
||||
|
||||
if ( ! -e $policy_file ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
croak "Policy file $policy_file does not exists.";
|
||||
}
|
||||
|
||||
if ( ! -r $policy_file ) {
|
||||
printf "(\"%s --help\" for help)\n", $scriptName;
|
||||
croak "Policy file $policy_file is not readable.";
|
||||
}
|
||||
|
||||
my $policy_json = read_file( $policy_file ) ;
|
||||
my $policy = decode_json( $policy_json );
|
||||
my $config_json = read_file( $config_file );
|
||||
my $config = decode_json( $config_json );
|
||||
|
||||
my $default = Zonemaster::Engine::Profile->default;
|
||||
my $profile = Zonemaster::Engine::Profile->new;
|
||||
|
||||
my %paths;
|
||||
my %default_paths;
|
||||
Zonemaster::Engine::Profile::_get_profile_paths(\%paths, $config);
|
||||
Zonemaster::Engine::Profile::_get_profile_paths(\%default_paths, $default->{q{profile}});
|
||||
delete $default_paths{ q{test_cases} };
|
||||
delete $default_paths{ q{test_levels} };
|
||||
|
||||
#
|
||||
# General options part
|
||||
#
|
||||
|
||||
foreach my $property_name ( keys %default_paths ) {
|
||||
my $value = Zonemaster::Engine::Profile::_get_value_from_nested_hash( $config, split /\./, $property_name );
|
||||
if ( defined $value ) {
|
||||
$profile->set( $property_name, $value );
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Test cases part
|
||||
#
|
||||
|
||||
my @tc;
|
||||
foreach my $tc ( @{ $default->get( q{test_cases} ) } ) {
|
||||
if ( not defined $policy->{__testcases__}->{$tc} or $policy->{__testcases__}->{$tc} ) {
|
||||
push @tc, $tc;
|
||||
}
|
||||
}
|
||||
$profile->set( q{test_cases}, \@tc );
|
||||
|
||||
#
|
||||
# Test levels part
|
||||
#
|
||||
|
||||
my %tl;
|
||||
foreach my $tl ( keys %{ $default->get( q{test_levels} ) } ) {
|
||||
if ( exists $policy->{$tl} ) {
|
||||
$tl{$tl} = clone $policy->{$tl};
|
||||
}
|
||||
}
|
||||
$profile->set( q{test_levels}, \%tl );
|
||||
|
||||
my $filename = $dest_dir.q{/profile.json};
|
||||
open(my $fh, '>', $filename) or die "Could not open file '$filename' $!";
|
||||
my $json = JSON::XS->new->canonical->pretty;
|
||||
print $fh $json->encode( $profile->{q{profile}} );
|
||||
close $fh;
|
||||
|
||||
sub process_options {
|
||||
my ( $opt_dest, $opt_config, $opt_policy, $opt_help, $opt_debug, $opt_version );
|
||||
|
||||
GetOptions(
|
||||
q{dest-dir=s} => \$opt_dest, # Dest directory for generated profile file
|
||||
q{config=s} => \$opt_config, # Config File
|
||||
q{policy=s} => \$opt_policy, # Policy file
|
||||
q{help} => \$opt_help, # Print Usage
|
||||
q{debug} => \$opt_debug, # Set Debug MODE
|
||||
q{version} => \$opt_version, # Print Version
|
||||
);
|
||||
|
||||
if ( $opt_debug ) {
|
||||
$DEBUG = 1;
|
||||
}
|
||||
|
||||
if ( $opt_dest ) {
|
||||
$DEST_DIR = $opt_dest;
|
||||
}
|
||||
|
||||
if ( $opt_config ) {
|
||||
$CONFIG_FILE = $opt_config;
|
||||
}
|
||||
|
||||
if ( $opt_policy ) {
|
||||
$POLICY_FILE = $opt_policy;
|
||||
}
|
||||
|
||||
if ( $opt_help ) {
|
||||
Usage();
|
||||
}
|
||||
|
||||
if ( $opt_version ) {
|
||||
Version();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Usage {
|
||||
my $_bold = "\e[1m";
|
||||
my $_normal = "\e[0m";
|
||||
my $_ul = "\e[4m";
|
||||
my $scriptNameBlank = $scriptName;
|
||||
$scriptNameBlank =~ s/./ /smxg;
|
||||
|
||||
print << "EOM";
|
||||
|
||||
${_bold}NAME${_normal}
|
||||
${scriptName} - Convert Config/Policy files into Profile file.
|
||||
|
||||
${_bold}SYNOPSIS${_normal}
|
||||
${scriptName} [ --help ] [ --dest-dir=${_ul}alternate_destination_directory${_normal} ] [ --config=${_ul}config_file${_normal} ] [ --policy=${_ul}policy_file${_normal} ] [ --debug ]
|
||||
|
||||
|
||||
${_bold}OPTIONS${_normal}
|
||||
--help
|
||||
Print this message and exit.
|
||||
|
||||
--config
|
||||
Name of the Config file to convert.
|
||||
|
||||
--policy
|
||||
Name of the Policy file to convert.
|
||||
|
||||
--dest-dir
|
||||
Name of an alternate directory to save generated profile file.
|
||||
${_bold}DEFAULT${_normal} is $dest_dir.
|
||||
|
||||
--debug
|
||||
Set Debug mode ON.
|
||||
|
||||
--version
|
||||
Print version of this program.
|
||||
|
||||
EOM
|
||||
|
||||
exit 0;
|
||||
|
||||
}
|
||||
|
||||
sub Version {
|
||||
printf "%s %s\n", $scriptName, $VERSION;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
109
zonemaster-engine/util/data2dig
Executable file
109
zonemaster-engine/util/data2dig
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use feature 'say';
|
||||
|
||||
use Zonemaster::Engine::Packet;
|
||||
|
||||
use JSON::PP;
|
||||
use MIME::Base64;
|
||||
use Module::Find qw[useall];
|
||||
use Readonly;
|
||||
use Scalar::Util qw[blessed];
|
||||
useall 'Zonemaster::LDNS::RR';
|
||||
|
||||
# Decoder taken from Zonemaster::Engine::Nameserver->restore
|
||||
Readonly my $decoder => JSON::PP->new->filter_json_single_key_object(
|
||||
'Zonemaster::LDNS::Packet' => sub {
|
||||
my ( $ref ) = @_;
|
||||
## no critic (Modules::RequireExplicitInclusion)
|
||||
my $obj = Zonemaster::LDNS::Packet->new_from_wireformat( decode_base64( $ref->{data} ) );
|
||||
$obj->answerfrom( $ref->{answerfrom} );
|
||||
$obj->timestamp( $ref->{timestamp} );
|
||||
$obj->querytime( $ref->{querytime} );
|
||||
return $obj;
|
||||
}
|
||||
)->filter_json_single_key_object(
|
||||
'Zonemaster::Engine::Packet' => sub {
|
||||
my ( $ref ) = @_;
|
||||
return Zonemaster::Engine::Packet->new( { packet => $ref } );
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
# Decode input into packets
|
||||
my @packets;
|
||||
while ( my $line = <> ) {
|
||||
my ( $name, $addr, $data ) = split( / /, $line, 3 );
|
||||
my $tree = deserialize( $data );
|
||||
push @packets, packets( $tree );
|
||||
}
|
||||
|
||||
# Order packets chronologically
|
||||
@packets = sort { $a->timestamp cmp $b->timestamp } @packets;
|
||||
|
||||
# Print delimited packets
|
||||
my $delim = ";" x 78;
|
||||
for my $packet ( @packets ) {
|
||||
say $delim;
|
||||
say $packet->string;
|
||||
$delim = "\n" . ";" x 78;
|
||||
}
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
data2dig - Export saved Zonemaster::Engine cache files to a dig format
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
data2dig foo.data
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<data2dig> exports saved Zonemaster::Engine cache files to human readable
|
||||
format as chronologically ordered response packets in dig format.
|
||||
|
||||
|
||||
=head1 SUBROUTINES
|
||||
|
||||
|
||||
=head2 deserialize
|
||||
|
||||
Deserialize a string in Zonemaster::Engine saved cache format.
|
||||
|
||||
Returns a tree of nested HASHREFs with decoded Zonemaster::Engine::Packet
|
||||
objects.
|
||||
|
||||
=cut
|
||||
|
||||
sub deserialize {
|
||||
my $data = shift;
|
||||
return $decoder->decode( $data );
|
||||
}
|
||||
|
||||
|
||||
=head2 packets
|
||||
|
||||
Return all Zonemaster::Engine::Packet objects from a tree of nested HASHREFs.
|
||||
|
||||
=cut
|
||||
|
||||
sub packets {
|
||||
my ( $data ) = @_;
|
||||
if ( ref $data eq 'HASH' && %{$data} && not blessed $data ) {
|
||||
my @packets;
|
||||
for my $key ( sort keys %$data ) {
|
||||
push @packets, packets( $data->{$key} );
|
||||
}
|
||||
return @packets;
|
||||
}
|
||||
elsif ( blessed $data && $data->isa( 'Zonemaster::Engine::Packet' ) ) {
|
||||
return ( $data );
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
203
zonemaster-engine/util/get_iana_address_spaces_infos.pl
Executable file
203
zonemaster-engine/util/get_iana_address_spaces_infos.pl
Executable file
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.14.2;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use version; our $VERSION = version->declare("v1.0.1");
|
||||
|
||||
use Carp;
|
||||
|
||||
use English qw( -no_match_vars );
|
||||
|
||||
use LWP::Simple;
|
||||
use File::Find;
|
||||
use File::chmod;
|
||||
use File::Copy qw(copy);
|
||||
use File::Temp qw(tempfile);
|
||||
use Getopt::Long;
|
||||
use File::Basename;
|
||||
use FindBin;
|
||||
|
||||
use Text::CSV;
|
||||
|
||||
my $DEBUG = 0;
|
||||
my $DEST_DIR = q{};
|
||||
|
||||
my $iana_url = q{http://www.iana.org/assignments/};
|
||||
my $dest_dir = qq{$FindBin::Bin/../share};
|
||||
my @files_details = (
|
||||
{ name => q{iana-ipv4-special-registry.csv}, url => $iana_url.q{/iana-ipv4-special-registry/iana-ipv4-special-registry-1.csv}, ip_version => 4 },
|
||||
{ name => q{iana-ipv6-special-registry.csv}, url => $iana_url.q{/iana-ipv6-special-registry/iana-ipv6-special-registry-1.csv}, ip_version => 6 },
|
||||
);
|
||||
|
||||
process_options();
|
||||
|
||||
if ( $DEST_DIR ) {
|
||||
$dest_dir = $DEST_DIR;
|
||||
}
|
||||
|
||||
if ($DEBUG) {
|
||||
print "Debug Mode set ON\n";
|
||||
print "Destination directory : $dest_dir\n\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 0: Check Directory existence and Directory/Files permissions
|
||||
#-------------------------------------------------
|
||||
if ( ! -d $dest_dir ) {
|
||||
print "Directory $dest_dir does not exist.\n";
|
||||
unless ( mkdir $dest_dir ) {
|
||||
croak "Unable to create $dest_dir.";
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! -w $dest_dir ) {
|
||||
print "Directory $dest_dir mode must be changed.\n";
|
||||
unless ( chmod (oct(755), $dest_dir) ) {
|
||||
croak "Cannot change directory mode.";
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $file_details ( @files_details ) {
|
||||
my $fn = $dest_dir.q{/}.${$file_details}{name};
|
||||
if ( -e $fn and ! -w $fn ) {
|
||||
print "File $fn mode must be changed.\n";
|
||||
unless ( chmod (oct(664), $fn) ) {
|
||||
croak "Cannot change file mode.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 1: If they exist, save original files
|
||||
#-------------------------------------------------
|
||||
foreach my $file_details ( @files_details ) {
|
||||
my $fn = $dest_dir.q{/}.${$file_details}{name};
|
||||
if ( -e $fn ) {
|
||||
my ($fh, $filename) = tempfile();
|
||||
${$file_details}{backup_filename} = $filename;
|
||||
unless ( copy $fn, $filename ) {
|
||||
croak "The Copy operation failed: $ERRNO";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 2: Retrieve remote files in temporary files
|
||||
#-------------------------------------------------
|
||||
foreach my $file_details ( @files_details ) {
|
||||
my ($fh, $filename) = tempfile();
|
||||
${$file_details}{new_filename} = $filename;
|
||||
my $rc = getstore(${$file_details}{url}, $filename);
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 3: Check downloaded files integrity
|
||||
#-------------------------------------------------
|
||||
foreach my $file_details ( @files_details ) {
|
||||
my $fn = ${$file_details}{new_filename};
|
||||
my $csv = Text::CSV->new({ binary => 1, auto_diag => 1, sep_char => q{,} }) or croak "Cannot use CSV: ".Text::CSV->error_diag ();
|
||||
open my $fh, "<:encoding(utf8)", $fn or croak "$fn: $ERRNO";
|
||||
while ( my $row = $csv->getline( $fh ) ) {
|
||||
}
|
||||
$csv->eof or croak $csv->error_diag();
|
||||
|
||||
close $fh or croak "$fn: $ERRNO";
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 4: Copy Files on their final destination
|
||||
#-------------------------------------------------
|
||||
foreach my $file_details ( @files_details ) {
|
||||
my $fn = $dest_dir.q{/}.${$file_details}{name};
|
||||
if ( -e ${$file_details}{new_filename} ) {
|
||||
unless ( copy ${$file_details}{new_filename}, $fn ) {
|
||||
croak "The Copy operation failed: $ERRNO";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------
|
||||
# STEP 5: Delete backup, temporary files
|
||||
#-------------------------------------------------
|
||||
clean_temporary_files();
|
||||
|
||||
sub clean_temporary_files {
|
||||
foreach my $file_details ( @files_details ) {
|
||||
if ($DEBUG) {
|
||||
print "${$file_details}{name} Details : \n";
|
||||
print "Backup file : ${$file_details}{backup_filename}\n";
|
||||
print "Downloaded file : ${$file_details}{new_filename}\n\n";
|
||||
} else {
|
||||
unlink ${$file_details}{backup_filename} or carp "Could not unlink ${$file_details}{backup_filename}: $ERRNO";
|
||||
unlink ${$file_details}{new_filename} or carp "Could not unlink ${$file_details}{new_filename}: $ERRNO";
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub process_options {
|
||||
my ( $opt_dest, $opt_help, $opt_debug );
|
||||
|
||||
GetOptions(
|
||||
q{dest-dir=s} => \$opt_dest, # Dest directory for downloaded files
|
||||
q{help} => \$opt_help, # Print Usage
|
||||
q{debug} => \$opt_debug, # Set Debug MODE
|
||||
);
|
||||
|
||||
if ( $opt_debug ) {
|
||||
$DEBUG = 1;
|
||||
}
|
||||
|
||||
if ( $opt_dest ) {
|
||||
$DEST_DIR = $opt_dest;
|
||||
}
|
||||
|
||||
if ( $opt_help ) {
|
||||
Usage();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Usage {
|
||||
my $_bold = "\e[1m";
|
||||
my $_normal = "\e[0m";
|
||||
my $_ul = "\e[4m";
|
||||
my $scriptName = basename($PROGRAM_NAME);
|
||||
my $scriptNameBlank = $scriptName;
|
||||
$scriptNameBlank =~ s/./ /smxg;
|
||||
|
||||
print << "EOM";
|
||||
|
||||
${_bold}NAME${_normal}
|
||||
${scriptName} - Download IANA Address Space Registries
|
||||
|
||||
${_bold}SYNOPSIS${_normal}
|
||||
${scriptName} [ --help ] [ --dest-dir=${_ul}alternate_destination_directory${_normal} ] [ --debug ]
|
||||
|
||||
${_bold}DESCRIPTION${_normal}
|
||||
${scriptName} is a tool to download official IANA Address Space registries.
|
||||
|
||||
Although these files are part of Zonemaster distribution, they are subject to changes and it is important that Zonemaster use last versions in order to give more accurate tests results.
|
||||
|
||||
That script should be called on a regular frequency basis to keep synchronization with IANA registries.
|
||||
|
||||
${_bold}OPTIONS${_normal}
|
||||
--help
|
||||
Print this message and exit.
|
||||
|
||||
--dest-dir
|
||||
Name of an alternate directory to save downloaded files.
|
||||
${_bold}DEFAULT${_normal} is $dest_dir.
|
||||
|
||||
--debug
|
||||
Set Debug mode ON. Temporary files will not be deleted.
|
||||
|
||||
EOM
|
||||
|
||||
exit 0;
|
||||
|
||||
}
|
||||
|
||||
10
zonemaster-engine/util/reformat_json.pl
Executable file
10
zonemaster-engine/util/reformat_json.pl
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.14.2;
|
||||
use warnings;
|
||||
|
||||
use JSON::PP;
|
||||
|
||||
my $json = JSON::PP->new->canonical->pretty->utf8;
|
||||
|
||||
say $json->encode($json->decode(join('',<>)));
|
||||
Reference in New Issue
Block a user