mirror of
https://github.com/zerotier/edge.git
synced 2026-05-22 16:25:05 -07:00
870 lines
21 KiB
Perl
Executable File
870 lines
21 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
# Copyright 2009-2014 SPARTA, Inc. All rights reserved. See the COPYING
|
|
# file distributed with this software for details.
|
|
#
|
|
|
|
use strict;
|
|
|
|
use Getopt::Long qw(:config no_ignore_case_always);
|
|
|
|
use Net::DNS::SEC::Tools::BootStrap;
|
|
use Net::DNS::SEC::Tools::conf;
|
|
use Net::DNS::SEC::Tools::defaults;
|
|
use Net::DNS::SEC::Tools::dnssectools;
|
|
use Net::DNS::SEC::Tools::keyrec;
|
|
use Net::DNS::SEC::Tools::rollrec;
|
|
use Net::DNS::SEC::Tools::rollmgr;
|
|
use Net::DNS::SEC::Tools::tooloptions;
|
|
use Net::DNS::SEC::Tools::timetrans;
|
|
use Net::DNS::SEC::Tools::QWPrimitives;
|
|
use POSIX qw(getcwd);
|
|
use IO::Dir;
|
|
use Data::Dumper;
|
|
|
|
#
|
|
# Detect required Perl modules.
|
|
#
|
|
dnssec_tools_load_mods('Date::Parse' => "",
|
|
'Date::Format' => "",);
|
|
|
|
my %opts = (d => '5',
|
|
t => 'kskpub,kskcur,zskpub,zskcur');
|
|
|
|
DTGetOptions(config => [qw(allow_zero)],
|
|
\%opts,
|
|
['GUI:VERSION',"DNSSEC-Tools Version: 2.2.3"],
|
|
|
|
# ['o|obsolete', 'Show obsolete keys/etc as well as current'],
|
|
|
|
['z|zone=s', 'Show information only about zone1,zone2,...'],
|
|
['p|phase=i', 'Show only zones in rollerd phase N (0 = any phase)'],
|
|
|
|
['k|key-data', 'Show keying data (default = everything)'],
|
|
['r|roll-status', 'Show rolling status (default = everything)'],
|
|
|
|
['t|key-types=s', "Show these keys (default = $opts{t})"],
|
|
['K|key-gen-time', "Calculate age based on key gen time not roll time"],
|
|
|
|
['d|detail=i', 'Details level (1-9, 5 = default)',
|
|
values => [1..9], type => 'menu', default => 5],
|
|
|
|
['M|monitor', 'Give data for monitor systems'],
|
|
|
|
["debug",
|
|
"Debugging output (show extra processing information)."],
|
|
|
|
['GUI:otherargs_text',"[FILES OR DIRECTORIES...]"],
|
|
) || exit(1);
|
|
|
|
@ARGV = (getcwd()) if ($#ARGV == -1);
|
|
# XXX: deal with '.' passed in on the command line
|
|
|
|
my @files = @ARGV;
|
|
my @filestodo;
|
|
my %zoneinfo;
|
|
|
|
my $todaystime = time();
|
|
my $gmtime = str2time(scalar gmtime());
|
|
|
|
my @rolltypes = qw(roll); # keywords for how rollrec data is stored.
|
|
|
|
# Ensure the requested level of detail is within our acceptable range.
|
|
if (($opts{'d'} < 1) || ($opts{'d'} > 9)) {
|
|
print STDERR "invalid -d option: $opts{'d'}\n";
|
|
exit(1);
|
|
}
|
|
|
|
# -M implies -r and -d 1.
|
|
if ($opts{'M'}) {
|
|
$opts{'r'} = 1;
|
|
$opts{'d'} = 1;
|
|
}
|
|
|
|
# generate the list of files to read in.
|
|
expand_files(@files);
|
|
|
|
# load the contents of everything into memory.
|
|
load_files(@filestodo);
|
|
|
|
# print summarized results
|
|
print_zone_information();
|
|
|
|
|
|
#
|
|
# load the various types of files we understand
|
|
#
|
|
|
|
my %krfdata;
|
|
my %krfkeys;
|
|
my %krfzones;
|
|
my %krfsets;
|
|
|
|
sub remember_keyrecs {
|
|
my @krnames = keyrec_names();
|
|
foreach my $krn (@krnames) {
|
|
debug("looking up: $krn\n");
|
|
my $krf = keyrec_fullrec($krn);
|
|
|
|
# err.... If it doesn't know what it is, then we certainly won't.
|
|
next if (!defined($krf->{'keyrec_type'}));
|
|
|
|
# generically store it
|
|
push @{$krfdata{$krf->{'zonename'}}{$krf->{'keyrec_type'}}}, {%$krf};
|
|
|
|
# store by type
|
|
|
|
if ($krf->{'keyrec_type'} eq 'zone') {
|
|
# zones
|
|
$krfzones{$krf->{'keyrec_name'}} = $krf;
|
|
} elsif ($krf->{'keyrec_type'} eq 'set') {
|
|
# sets
|
|
$krfsets{$krf->{'zonename'}}{$krf->{'set_type'}} = {%$krf};
|
|
} else {
|
|
# keys
|
|
$krfkeys{$krf->{'zonename'}}{$krf->{'keyrec_name'}} = {%$krf};
|
|
}
|
|
}
|
|
}
|
|
|
|
my %rrdata;
|
|
my %rrlookup;
|
|
|
|
sub remember_rollrecs {
|
|
my @rrnames = rollrec_names();
|
|
foreach my $rrn (@rrnames) {
|
|
debug("looking up rr: $rrn\n");
|
|
my $rr = rollrec_fullrec($rrn);
|
|
if ($rr->{'rollrec_type'}) {
|
|
push @{$rrdata{$rr->{'rollrec_name'}}{$rr->{'rollrec_type'}}}, $rr;
|
|
$rrlookup{$rr->{'rollrec_name'}} = $rr;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub load_files {
|
|
my @todolist = @_;
|
|
foreach my $file (@todolist) {
|
|
if ($file =~ /\.krf$/) {
|
|
# load it as a krf
|
|
keyrec_read($file);
|
|
remember_keyrecs();
|
|
} elsif ($file =~ /\.(rollrec|rrf)$/) {
|
|
# load it as a rollrec
|
|
rollrec_read($file);
|
|
remember_rollrecs();
|
|
} else {
|
|
# XXX: maybe look at the first line to determine what it is?
|
|
}
|
|
# XXX: load .signed files and look for sig expiry times?
|
|
}
|
|
}
|
|
|
|
# expand the list of files/directories to just all the files
|
|
# i.e. remove the directories and replace with their file contents
|
|
sub expand_files {
|
|
my @files = @_;
|
|
my @errext = ();
|
|
my @errrd = ();
|
|
my $errors = 0;
|
|
foreach my $file (@files) {
|
|
if (! -e $file) {
|
|
push @errext, $file;
|
|
next;
|
|
}
|
|
if (-f $file) {
|
|
push @filestodo, $file;
|
|
} elsif (-d $file) {
|
|
my $dirh = IO::Dir->new($file);
|
|
my $direntry;
|
|
$file .= "/" if ($file !~ /\/$/);
|
|
while (defined($direntry = $dirh->read)) {
|
|
my $fullfile = $file . $direntry;
|
|
push @filestodo, $fullfile if (-f $fullfile);
|
|
# XXX: add recursive option.
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get the keyrec files from any specified rollrecs.
|
|
my @morefiles = ();
|
|
foreach my $file (@filestodo) {
|
|
if ($file =~ /\.(rollrec|rrf)$/) {
|
|
rollrec_read($file);
|
|
foreach my $rrn (rollrec_names()) {
|
|
my $krf = rollrec_recval($rrn, 'keyrec');
|
|
if(-e $krf && -f $krf) {
|
|
push @morefiles, $krf
|
|
}
|
|
}
|
|
rollrec_close();
|
|
}
|
|
}
|
|
push @filestodo, @morefiles;
|
|
|
|
# Find the files that we can't read.
|
|
foreach my $file (@filestodo) {
|
|
if (! -r $file) {
|
|
push @errrd, $file;
|
|
}
|
|
}
|
|
|
|
# Give an error and exit if unreadable or nonexistent file were specified.
|
|
$errors = @errext + @errrd;
|
|
if ($errors) {
|
|
if ($opts{'M'}) {
|
|
if ($errors == 1) {
|
|
print "1 file does not exist or is unreadable\n";
|
|
} else {
|
|
print $errors . " files do not exist or are unreadable\n";
|
|
}
|
|
exit(2);
|
|
}
|
|
|
|
if (@errext > 0) {
|
|
if (@errext == 1) {
|
|
print "1 named file does not exist\n";
|
|
} else {
|
|
print @errext . " named files do not exist\n";
|
|
}
|
|
if ($opts{'d'} > 5) {
|
|
foreach my $file (sort(@errext)) {
|
|
print "\t$file\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (@errrd > 0) {
|
|
if (@errext == 1) {
|
|
print "1 file is not readable\n";
|
|
} else {
|
|
print @errext . " files are not readable\n";
|
|
}
|
|
if ($opts{'d'} > 5) {
|
|
foreach my $file (sort(@errrd)) {
|
|
print "\t$file\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
exit(2);
|
|
}
|
|
|
|
}
|
|
|
|
sub get_ksk_phase3_length {
|
|
my ($rollrec) = @_;
|
|
|
|
my $length = $rollrec->{'maxttl'}*2;
|
|
|
|
if ($rollrec->{'istrustanchor'}) {
|
|
# we should do a proper RFC5011 waiting period
|
|
# use either their defined value or a default of 60 days
|
|
# The 60 days comes from the rollerd 60 day default
|
|
my $addtime = dt_parse_duration($rollrec->{'holddowntime'});
|
|
|
|
$addtime ||= (2*30*24*60*60);
|
|
|
|
$length += $addtime;
|
|
}
|
|
|
|
return $length;
|
|
}
|
|
|
|
sub print_life_graph {
|
|
my ($percent, $word) = @_;
|
|
|
|
$word ||= "life";
|
|
|
|
my $spaces = " " x (4-length($word));
|
|
|
|
print " $word:$spaces |";
|
|
print "=" x int(65*($percent/100));
|
|
print "O";
|
|
print "-" x (65-int(65*($percent/100)));
|
|
print ($percent < 100 ? "|" : "X");
|
|
print "\n";
|
|
}
|
|
|
|
sub print_key {
|
|
my ($keytype, $key) = @_;
|
|
my $keymaintype = substr($keytype, 0, 3);
|
|
|
|
my $keytag = $key->{'keyrec_name'};
|
|
$keytag =~ s/.*\+//;
|
|
|
|
return if($keytag eq '');
|
|
|
|
my $smalltype = substr($keytype, 0, 3);
|
|
my $smallstatus = substr($keytype, 3, 3);
|
|
|
|
my $life = $key->{$smalltype . 'life'};
|
|
|
|
my $keystarttime;
|
|
# pull the date from the rollrec file:
|
|
# - this is the end of the last roll time, rather than key age
|
|
if (exists($rrdata{$key->{'zonename'}}) &&
|
|
exists($rrdata{$key->{'zonename'}}{'roll'}) &&
|
|
exists($rrdata{$key->{'zonename'}}{'roll'}[0]) &&
|
|
exists($rrdata{$key->{'zonename'}}{'roll'}[0]{'zsk_rollsecs'})) {
|
|
$keystarttime = $rrdata{$key->{'zonename'}}{'roll'}[0]{'zsk_rollsecs'};
|
|
}
|
|
|
|
my $useGenLife = $opts{'K'};
|
|
if ($useGenLife || !defined($keystarttime)) {
|
|
# the age of the key is based on the actual generation date
|
|
$keystarttime = $key->{'keyrec_gensecs'};
|
|
$useGenLife = 1;
|
|
}
|
|
|
|
my $age = $todaystime - $keystarttime;
|
|
my $percent;
|
|
|
|
if ($age > $life) {
|
|
$percent = 100;
|
|
} else {
|
|
$percent = int(100*($age/$life));
|
|
}
|
|
|
|
printf(" key: %05.5d %3.3s %3.3s %4.4d %-12.12s %3.3d%% %30s|\n",
|
|
$keytag, uc($keytype), $smallstatus,
|
|
$key->{$smalltype . 'length'}, $key->{'algorithm'},
|
|
$percent, fuzzytimetrans($life));
|
|
|
|
if ($opts{'d'} > 8) {
|
|
printf(" file: %s\n", $key->{'keypath'});
|
|
}
|
|
|
|
if ($useGenLife) {
|
|
if ($opts{'d'} > 4) {
|
|
print_life_graph($percent);
|
|
}
|
|
|
|
if ($percent == 100 && $opts{'d'} > 1) {
|
|
print " WARN: *** key has passed its expected lifetime ***\n";
|
|
} elsif ($opts{'d'} > 6) {
|
|
print " (" . fuzzytimetrans($life-$age) . " remaining)\n";
|
|
}
|
|
}
|
|
|
|
print "\n" if ($useGenLife && $opts{'d'} > 2);
|
|
|
|
return [$keymaintype, $percent, ($percent == 100 ? 0 : $life - $age), $life];
|
|
}
|
|
|
|
sub print_roll {
|
|
my ($rolltype, $rollrec, $keylives) = @_;
|
|
|
|
my $type;
|
|
|
|
if ($rollrec->{'zskphase'} > 0) {
|
|
$type = 'zsk';
|
|
} elsif ($rollrec->{'kskphase'} > 0) {
|
|
$type = 'ksk';
|
|
} else {
|
|
print(" roll: not currently rolling any keys\n");
|
|
return;
|
|
}
|
|
|
|
my $phase = $rollrec->{$type . 'phase'};
|
|
my $pmsg = '';
|
|
|
|
$pmsg = '- ' . rollmgr_get_phase(uc($type), $phase)
|
|
if ($opts{'d'} > 5);
|
|
printf(" roll: %3.3s phase: %d %s\n", uc($type), $phase, $pmsg);
|
|
|
|
printf(" started: $rollrec->{phasestart}\n")
|
|
if ($opts{'d'} > 6);
|
|
|
|
my $started = str2time($rollrec->{'phasestart'});
|
|
|
|
#
|
|
# bar graph
|
|
#
|
|
my $rolltimelength = 0;
|
|
my $currentperiod = 0;
|
|
|
|
my $barlength = 66;
|
|
|
|
my @phasespots;
|
|
|
|
if ($type eq 'zsk') {
|
|
# phase 1
|
|
$rolltimelength += $rollrec->{'maxttl'}*2;
|
|
$phasespots[1] = 0;
|
|
|
|
if ($phase == 1) {
|
|
$currentperiod += ($gmtime - $started);
|
|
} else {
|
|
$currentperiod = $rolltimelength;
|
|
}
|
|
|
|
# phase 2
|
|
$phasespots[2] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
# phase 3
|
|
$phasespots[3] = $rolltimelength;
|
|
if ($phase == 3) {
|
|
$currentperiod = $rolltimelength + ($gmtime - $started);
|
|
} else {
|
|
$currentperiod = $rolltimelength + $rollrec->{'maxttl'}*2;
|
|
}
|
|
$rolltimelength += $rollrec->{'maxttl'}*2;
|
|
|
|
# phase 4
|
|
$phasespots[4] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
my $percentdone = $currentperiod / $rolltimelength;
|
|
|
|
if ($opts{'d'} > 4) {
|
|
#
|
|
# now construct the timeline based on the gathered information
|
|
#
|
|
|
|
my $outstring = "=" x int($barlength * $percentdone);
|
|
$outstring .= "-" x int($barlength - ($barlength * $percentdone));
|
|
|
|
my $lastpt = -1;
|
|
foreach my $phasepoint (1..4) {
|
|
my $pt =
|
|
int($barlength * $phasespots[$phasepoint]/$rolltimelength);
|
|
$pt++ if ($lastpt == $pt);
|
|
|
|
$pt -= 1 if ($pt == $barlength);
|
|
|
|
substr($outstring, $pt, 1, $phasepoint);
|
|
$lastpt = $pt;
|
|
}
|
|
|
|
# and finally print it out
|
|
printf(" time: |%s|\n", $outstring);
|
|
}
|
|
|
|
} elsif ($type eq 'ksk') {
|
|
# phase 1
|
|
$rolltimelength += $rollrec->{'maxttl'}*2;
|
|
$phasespots[1] = 0;
|
|
|
|
if ($phase == 1) {
|
|
$currentperiod += ($gmtime - $started);
|
|
} else {
|
|
$currentperiod = $rolltimelength;
|
|
}
|
|
|
|
# phase 2
|
|
$phasespots[2] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
# phase 3
|
|
$phasespots[3] = $rolltimelength;
|
|
$rolltimelength += get_ksk_phase3_length($rollrec);
|
|
|
|
if ($phase == 3) {
|
|
$currentperiod = $phasespots[3] + ($gmtime - $started);
|
|
} else {
|
|
$currentperiod = $rolltimelength;
|
|
}
|
|
|
|
# phase 4
|
|
$phasespots[4] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
# phase 5
|
|
$phasespots[5] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
# phase 6
|
|
$phasespots[6] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
# phase 7
|
|
# XXX: rollerd needs to be fixed to wait for 2*parent_TTL
|
|
$phasespots[7] = $rolltimelength;
|
|
# $rolltimelength += 0;
|
|
# $currentperiod += 0;
|
|
|
|
my $percentdone = $currentperiod / $rolltimelength;
|
|
|
|
#
|
|
# now construct the timeline based on the gathered information
|
|
#
|
|
|
|
if ($opts{'d'} > 4) {
|
|
my $outstring = "=" x int($barlength * $percentdone);
|
|
$outstring .= "-" x int($barlength - ($barlength * $percentdone));
|
|
|
|
my $lastpt = -1;
|
|
foreach my $phasepoint (1..7) {
|
|
my $pt =
|
|
int($barlength * $phasespots[$phasepoint]/$rolltimelength);
|
|
$pt++ if ($lastpt == $pt);
|
|
|
|
$pt = $barlength-2 if ($pt > $barlength-2);
|
|
|
|
substr($outstring, $pt, 1, $phasepoint);
|
|
$lastpt = $pt;
|
|
}
|
|
|
|
# ugly hack to force fit 4, 5 and 6 phases in to the left
|
|
$outstring =~ s/.7/67/ if ($outstring !~ /6/);
|
|
$outstring =~ s/.6/56/ if ($outstring !~ /5/);
|
|
$outstring =~ s/.5/45/ if ($outstring !~ /4/);
|
|
|
|
# and finally print it out
|
|
printf(" time: |%s|\n", $outstring);
|
|
}
|
|
}
|
|
|
|
#
|
|
# remaining time
|
|
#
|
|
if ($opts{'d'} > 4 &&
|
|
(($type eq 'zsk' &&
|
|
($phase == 1 || $phase == 3)) ||
|
|
($type eq 'ksk' &&
|
|
($phase == 1 || $phase == 3)))
|
|
) {
|
|
my $timeremaining = $rollrec->{'maxttl'}*2;
|
|
$timeremaining = get_ksk_phase3_length($rollrec)
|
|
if ($type eq 'ksk' && $phase == 3);
|
|
|
|
$timeremaining -= ($gmtime - $started);
|
|
|
|
my $phaseremaining = "";
|
|
if ($timeremaining > 0) {
|
|
$phaseremaining = fuzzytimetrans($timeremaining);
|
|
} else {
|
|
$phaseremaining = "none -- ready for next phase";
|
|
}
|
|
|
|
printf(" time: remaining phase $phase: %-30.30s %17.17s\n", $phaseremaining, "total: " . fuzzytimetrans($rolltimelength) . "|");
|
|
}
|
|
|
|
if ($opts{'d'} > 2) {
|
|
printf("\n");
|
|
}
|
|
|
|
return $type;
|
|
}
|
|
|
|
sub monitor_roll
|
|
{
|
|
my ($rolltype, $rollrec, $keylives) = @_;
|
|
|
|
my $type;
|
|
my $outstr;
|
|
|
|
if ($rollrec->{'zskphase'} > 0) {
|
|
$type = 'zsk';
|
|
} elsif ($rollrec->{'kskphase'} > 0) {
|
|
$type = 'ksk';
|
|
} else {
|
|
print("$rollrec->{'zonename'}: not currently rolling any keys:\n");
|
|
return;
|
|
}
|
|
|
|
my $phase = $rollrec->{$type . 'phase'};
|
|
|
|
$outstr = "$rollrec->{'zonename'}: " . uc($type) . " phase $phase: ";
|
|
|
|
#
|
|
# remaining time
|
|
#
|
|
if (($phase == 1) || ($phase == 3)) {
|
|
my $timeremaining = $rollrec->{'maxttl'} * 2;
|
|
my $started = str2time($rollrec->{'phasestart'});
|
|
|
|
$timeremaining = get_ksk_phase3_length($rollrec)
|
|
if ($type eq 'ksk' && $phase == 3);
|
|
|
|
$timeremaining -= ($gmtime - $started);
|
|
|
|
my $phaseremaining = "";
|
|
if ($timeremaining > 0) {
|
|
$outstr .= fuzzytimetrans($timeremaining) . " remaining: $timeremaining seconds";
|
|
} else {
|
|
$outstr .= "moving to next phase: 0 seconds";
|
|
}
|
|
} else {
|
|
$outstr .= "phase active: 0 seconds";
|
|
}
|
|
|
|
print "$outstr\n";
|
|
}
|
|
|
|
sub find_zone_phases {
|
|
my ($phaseNeeded) = @_;
|
|
my @zones;
|
|
|
|
foreach my $zone (%rrdata) {
|
|
foreach my $rolltype (@rolltypes) {
|
|
if ($phaseNeeded > 0) {
|
|
if ($rrdata{$zone}{$rolltype}[0]{'zskphase'} eq $phaseNeeded ||
|
|
$rrdata{$zone}{$rolltype}[0]{'kskphase'} eq $phaseNeeded) {
|
|
push @zones, $zone;
|
|
}
|
|
} elsif ($rrdata{$zone}{$rolltype}[0]{'zskphase'} > 0 ||
|
|
$rrdata{$zone}{$rolltype}[0]{'kskphase'} > 0) {
|
|
push @zones, $zone;
|
|
}
|
|
}
|
|
}
|
|
return @zones;
|
|
}
|
|
|
|
sub print_zone_information {
|
|
my $zonelineformat = "%-30s\n";
|
|
|
|
my @zones;
|
|
if ($opts{'z'}) {
|
|
@zones = split(/\s*,\s*/, $opts{'z'});
|
|
} elsif (exists($opts{'p'})) {
|
|
@zones = find_zone_phases($opts{'p'});
|
|
} else {
|
|
@zones = keys(%krfzones);
|
|
}
|
|
|
|
rollmgr_phasemsg('long') if ($opts{'d'} > 5);
|
|
|
|
foreach my $zone (sort(@zones)) {
|
|
my %keylives;
|
|
my %keyremaining;
|
|
my %keylifetimes;
|
|
next if ($zone eq '');
|
|
|
|
# Print monitor info.
|
|
if ($opts{'M'}) {
|
|
foreach my $rolltype (@rolltypes) {
|
|
foreach my $roll (@{$rrdata{$zone}{$rolltype}}) {
|
|
monitor_roll($rolltype, $rrlookup{$roll->{'rollrec_name'}});
|
|
}
|
|
}
|
|
|
|
print "\n" if (! $opts{'M'} > 2);
|
|
next;
|
|
}
|
|
|
|
print "Zone: $zone\n";
|
|
|
|
# print each active key
|
|
if ($opts{'k'} || !($opts{'k'} || $opts{'r'})) {
|
|
foreach my $keytype (split(/,\s*/, $opts{'t'})) {
|
|
foreach my $keyname (split(/ /, $krfsets{$zone}{$keytype}{'keys'})) {
|
|
my $keydata = print_key($keytype, $krfkeys{$zone}{$keyname});
|
|
$keylives{$keydata->[0]} =
|
|
max($keydata->[1], $keylives{$keydata->[0]});
|
|
$keyremaining{$keydata->[0]} =
|
|
max($keydata->[2], $keyremaining{$keydata->[0]});
|
|
$keylifetimes{$keydata->[0]} =
|
|
max($keydata->[3], $keylifetimes{$keydata->[0]});
|
|
}
|
|
}
|
|
}
|
|
|
|
print "\n" if ($opts{'d'} > 2);
|
|
|
|
# print each roller roll
|
|
my $being_rolled;
|
|
if ($opts{'r'} || !($opts{'k'} || $opts{'r'})) {
|
|
foreach my $rolltype (@rolltypes) {
|
|
foreach my $roll (@{$rrdata{$zone}{$rolltype}}) {
|
|
$being_rolled = print_roll($rolltype, $rrlookup{$roll->{'rollrec_name'}});
|
|
}
|
|
}
|
|
}
|
|
|
|
print "\n" if ($opts{'d'} > 2 && !$opts{'K'} && !defined($being_rolled));
|
|
|
|
if (!$opts{'K'}) {
|
|
# we print expiry times for the entire zsk/ksk collection instead of
|
|
# per key in this case.
|
|
foreach my $keytype (keys(%keylives)) {
|
|
if ($keytype eq $being_rolled) {
|
|
next;
|
|
}
|
|
print_life_graph($keylives{$keytype}, $keytype);
|
|
if ($keyremaining{$keytype} == 0) {
|
|
printf(" life: None left! Key should be rolled soon.\n");
|
|
} else {
|
|
printf(" life: " .
|
|
fuzzytimetrans($keyremaining{$keytype})
|
|
. " left (out of " .
|
|
fuzzytimetrans($keylifetimes{$keytype})
|
|
. ")\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($opts{'d'} > 8) {
|
|
print " keys: ";
|
|
foreach my $type (keys(%{$krfdata{$zone}})) {
|
|
next if ($type eq 'set');
|
|
print "$type=" . $#{$krfdata{$zone}{$type}} . " ";
|
|
}
|
|
print "\n";
|
|
}
|
|
|
|
print "\n";
|
|
}
|
|
}
|
|
|
|
sub max {
|
|
return $_[0] if (!defined($_[1]));
|
|
return $_[1] if (!defined($_[0]));
|
|
return ($_[0] > $_[1] ? $_[0] : $_[1]);
|
|
}
|
|
|
|
sub min {
|
|
return ($_[0] < $_[1] ? $_[0] : $_[1]);
|
|
}
|
|
|
|
#######################################################################
|
|
# debugging output
|
|
#
|
|
sub debug {
|
|
print STDERR @_ if ($opts{'debug'});
|
|
}
|
|
|
|
#######################################################################
|
|
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
lsdnssec - List DNSSEC components of zones from files or directories
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
lsdnssec [-d 1-9] [OPTIONS] [FILES OR DIRECTORIES...]
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
The B<lsdnssec> program summarizes information about DNSSEC-related files.
|
|
These files may be specified on the command line or found in directories
|
|
that were given on the command line. The B<-d> flag controls the amount
|
|
of detail in the B<lsdnssec> output.
|
|
|
|
B<lsdnssec> displays the following information about each zone for which it
|
|
collects information:
|
|
|
|
=over
|
|
|
|
=item keys
|
|
|
|
Key information is shown about the keys currently in use. A bar graph is
|
|
included that shows the age of the key with respect to the configured
|
|
expected key lifetime.
|
|
|
|
This information is collected from any B<.krf> files B<lsdnssec> finds.
|
|
|
|
=item rolling status
|
|
|
|
If any zone keys are being rolled via B<rollerd>, then the status of the
|
|
rolling state is shown. The time needed to reach the next state is also
|
|
displayed.
|
|
|
|
This information is collected from any B<.rollrec> or B<.rrf> files found by
|
|
B<lsdnssec>.
|
|
|
|
=back
|
|
|
|
=head1 OPTIONS
|
|
|
|
=over
|
|
|
|
=item B<-z ZONENAME1[,ZONENAME2]>
|
|
|
|
=item B<--zone=ZONENAME1[,ZONENAME2]>
|
|
|
|
Only prints information about the named zone(s).
|
|
|
|
=item B<-p NUMBER>
|
|
|
|
=item B<--phase=NUMBER>
|
|
|
|
Only prints information about zones currently being rolled by B<rollerd>
|
|
and where either a zsk or a ksk rollover is taking place and is in
|
|
phase NUMBER.
|
|
|
|
If the phase NUMBER is specified as 0, then any zone in any rolling
|
|
phase will be printed (but not zones that aren't being rolled at all).
|
|
|
|
This flag is especially useful to find all of your zones that are
|
|
currently in KSK rolling phase 6, which requires operator intervention
|
|
to propagate the new DS records into the parent zone.
|
|
|
|
=item B<-r>
|
|
|
|
=item B<--roll-status>
|
|
|
|
Show only rolling information from the rollrec files. By default both
|
|
roll-state and key information is shown.
|
|
|
|
=item B<-k>
|
|
|
|
=item B<--key-data>
|
|
|
|
Show only keying information from the krf files. By default both
|
|
roll-state and key information is shown.
|
|
|
|
=item B<-K>
|
|
|
|
=item B<--key-gen-time>
|
|
|
|
Normally B<rollerd> calculates the age of a key based on the last time a
|
|
key was rolled. However, it's also possible to calculate the age of a
|
|
key based on the difference between the time of execution and when the key
|
|
was created (which was typically before the rolling began).
|
|
The I<-K> flag switches to this second mode of key age calculation
|
|
(which will not match how B<rollerd> actually performs).
|
|
|
|
=item B<-M>
|
|
|
|
=item B<--monitor>
|
|
|
|
The I<-M> flag gives an abbreviated version of B<lsdnssec> output that is
|
|
intended for use by monitoring systems. It displays the zone name, the
|
|
rollover phase, and the time remaining in that phase. This option implicitly
|
|
sets the I<-r> flag on and sets the detail level to 1.
|
|
|
|
=item B<-d 1-9>
|
|
|
|
=item B<--detail 1-9>
|
|
|
|
Controls the amount of information shown in the output. A level of 9
|
|
shows everything; a level of 1 shows a minimal amount. The
|
|
default level is 5.
|
|
|
|
=item B<--debug>
|
|
|
|
Turns on extra debugging information.
|
|
|
|
=back
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
Copyright 2009-2014 SPARTA, Inc. All rights reserved.
|
|
See the COPYING file included with the DNSSEC-Tools package for details.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Wes Hardaker <hardaker AT AT AT users.sourceforge.net>
|
|
|
|
=head1 SEE ALSO
|
|
|
|
B<lskrf(1)>
|
|
|
|
B<zonesigner(8)>,
|
|
B<rollerd(8)>
|
|
|
|
=cut
|
|
|