Home | History | Annotate | Line # | Download | only in scripts
check5011.pl revision 1.1.1.1.4.2
      1 #!/usr/bin/perl
      2 
      3 use warnings;
      4 use strict;
      5 
      6 use POSIX qw(strftime);
      7 my $now = strftime "%Y%m%d%H%M%S", gmtime;
      8 
      9 sub ext8601 ($) {
     10 	my $d = shift;
     11 	$d =~ s{(....)(..)(..)(..)(..)(..)}
     12 	       {$1-$2-$3.$4:$5:$6+0000};
     13 	return $d;
     14 }
     15 
     16 sub getkey ($$) {
     17 	my $h = shift;
     18 	my $k = shift;
     19 	m{\s+(\d+)\s+(\d+)\s+(\d+)\s+[(]\s*$};
     20 	$k->{flags}     = $1;
     21 	$k->{protocol}  = $2;
     22 	$k->{algorithm} = $3;
     23 	my $data = "(";
     24 	while (<$h>) {
     25 		s{^\s+}{};
     26 		s{\s+$}{};
     27 		last if m{^[)]};
     28 		$data .= $_;
     29 	}
     30 	m{ alg = (\S+)\s*; key id = (\d+)};
     31 	$k->{alg}  = $1;
     32 	$k->{id}   = $2;
     33 	$k->{data} = $data;
     34 	return $k;
     35 }
     36 
     37 sub fmtkey ($) {
     38 	my $k = shift;
     39 	return sprintf "%16s tag %s", $k->{name}, $k->{id};
     40 }
     41 
     42 sub printstatus ($) {
     43 	my $a = shift;
     44 	if ($a->{removehd} ne "19700101000000") {
     45 		printf " untrusted and to be removed at %s\n", ext8601 $a->{removehd};
     46 	} elsif ($a->{addhd} le $now) {
     47 		printf " trusted\n";
     48 	} else {
     49 		printf " waiting for %s\n", ext8601 $a->{addhd};
     50 	}
     51 }
     52 
     53 sub digkeys ($) {
     54 	my $name = shift;
     55 	my $keys;
     56 	open my $d, "-|", qw{dig +multiline DNSKEY}, $name;
     57 	while (<$d>) {
     58 		next unless m{^([a-z0-9.-]*)\s+\d+\s+IN\s+DNSKEY\s+};
     59 		next unless $name eq $1;
     60 		push @$keys, getkey $d, { name => $name };
     61 	}
     62 	return $keys;
     63 }
     64 
     65 my $anchor;
     66 my $owner = ".";
     67 while (<>) {
     68 	next unless m{^([a-z0-9.-]*)\s+KEYDATA\s+(\d+)\s+(\d+)\s+(\d+)\s+};
     69 	my $k = getkey *ARGV, {
     70 		name     => $1,
     71 		refresh  => $2,
     72 		addhd    => $3,
     73 		removehd => $4,
     74 	};
     75 	if ($k->{name} eq "") {
     76 		$k->{name} = $owner;
     77 	} else {
     78 		$owner = $k->{name};
     79 	}
     80 	$k->{name} =~ s{[.]*$}{.};
     81 	push @{$anchor->{$k->{name}}}, $k;
     82 }
     83 
     84 for my $name (keys %$anchor) {
     85 	my $keys = digkeys $name;
     86 	my $anchors = $anchor->{$name};
     87 	for my $k (@$keys) {
     88 		if ($k->{flags} & 1) {
     89 			printf "%s %s", fmtkey $k, $k->{alg};
     90 		} else {
     91 			# ZSK - skipping
     92 			next;
     93 		}
     94 		if ($k->{flags} & 512) {
     95 			print " revoked;";
     96 		}
     97 		my $a;
     98 		for my $t (@$anchors) {
     99 			if ($t->{data} eq $k->{data} and
    100 			    $t->{protocol} eq $k->{protocol} and
    101 			    $t->{algorithm} eq $k->{algorithm}) {
    102 				$t->{matched} = 1;
    103 				$a = $t;
    104 				last;
    105 			}
    106 		}
    107 		if (not defined $a) {
    108 			print " no trust anchor\n";
    109 			next;
    110 		}
    111 		printstatus $a;
    112 	}
    113 	for my $a (@$anchors) {
    114 		next if $a->{matched};
    115 		printf "%s %s missing;", fmtkey $a, $a->{alg};
    116 		printstatus $a;
    117 	}
    118 }
    119 
    120 exit;
    121 
    122 __END__
    123 
    124 =head1 NAME
    125 
    126 check5011 - summarize DNSSEC trust anchor status
    127 
    128 =head1 SYNOPSIS
    129 
    130 check5011 <I<managed-keys.bind>>
    131 
    132 =head1 DESCRIPTION
    133 
    134 The BIND managed-keys file contains DNSSEC trust anchors
    135 that can be automatically updated according to RFC 5011. The
    136 B<check5011> program reads this file and prints a summary of the
    137 status of the trust anchors. It fetches the corresponding
    138 DNSKEY records using B<dig> and compares them to the trust anchors.
    139 
    140 Each key is printed on a line with its name, its tag, and its
    141 algorithm, followed by a summary of its status.
    142 
    143 =over
    144 
    145 =item C<trusted>
    146 
    147 The key is currently trusted.
    148 
    149 =item C<waiting for ...>
    150 
    151 The key is new, and B<named> is waiting for the "add hold-down" period
    152 to pass before the key will be trusted.
    153 
    154 =item C<untrusted and to be removed at ...>
    155 
    156 The key was revoked and will be removed at the stated time.
    157 
    158 =item C<no trust anchor>
    159 
    160 The key is present in the DNS but not in the managed-keys file.
    161 
    162 =item C<revoked>
    163 
    164 The key has its revoked flag set. This is printed before the key's
    165 trust anchor status which should normally be C<untrusted...> if
    166 B<named> has observed the revocation.
    167 
    168 =item C<missing>
    169 
    170 There is no DNSKEY record for this trust anchor. This is printed
    171 before the key's trust anchor status.
    172 
    173 =back
    174 
    175 By default the managed keys are stored in a file called
    176 F<managed-keys.bind> in B<named>'s working directory. This location
    177 can be changed with B<named>'s B<managed-keys-directory> option. If
    178 you are using views the file may be named with the SHA256 hash of a
    179 view name with a F<.mkeys> extension added.
    180 
    181 =head1 AUTHOR
    182 
    183 =over
    184 
    185 =item Written by Tony Finch <fanf2@cam.ac.uk> <dot@dotat.at>
    186 
    187 =item at the University of Cambridge Computing Service.
    188 
    189 =item You may do anything with this. It has no warranty.
    190 
    191 =item L<http://creativecommons.org/publicdomain/zero/1.0/>
    192 
    193 =back
    194 
    195 =head1 SEE ALSO
    196 
    197 dig(1), named(8)
    198 
    199 =cut
    200