1#!/usr/bin/perl 2 3use warnings; 4use strict; 5 6use POSIX qw(strftime); 7my $now = strftime "%Y%m%d%H%M%S", gmtime; 8 9sub ext8601 ($) { 10 my $d = shift; 11 $d =~ s{(....)(..)(..)(..)(..)(..)} 12 {$1-$2-$3.$4:$5:$6+0000}; 13 return $d; 14} 15 16sub 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+); key id = (\d+)}; 31 $k->{alg} = $1; 32 $k->{id} = $2; 33 $k->{data} = $data; 34 return $k; 35} 36 37sub fmtkey ($) { 38 my $k = shift; 39 return sprintf "%16s tag %s", $k->{name}, $k->{id}; 40} 41 42sub 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} lt $now) { 47 printf " trusted\n"; 48 } else { 49 printf " waiting for %s\n", ext8601 $a->{addhd}; 50 } 51} 52 53sub 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 65my $anchor; 66my $owner = "."; 67while (<>) { 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 84for 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 120exit; 121 122__END__ 123 124=head1 NAME 125 126check5011 - summarize DNSSEC trust anchor status 127 128=head1 SYNOPSIS 129 130check5011 <I<managed-keys.bind>> 131 132=head1 DESCRIPTION 133 134The BIND managed-keys file contains DNSSEC trust anchors 135that can be automatically updated according to RFC 5011. The 136B<check5011> program reads this file and prints a summary of the 137status of the trust anchors. It fetches the corresponding 138DNSKEY records using B<dig> and compares them to the trust anchors. 139 140Each key is printed on a line with its name, its tag, and its 141algorithm, followed by a summary of its status. 142 143=over 144 145=item C<trusted> 146 147The key is currently trusted. 148 149=item C<waiting for ...> 150 151The key is new, and B<named> is waiting for the "add hold-down" period 152to pass before the key will be trusted. 153 154=item C<untrusted and to be removed at ...> 155 156The key was revoked and will be removed at the stated time. 157 158=item C<no trust anchor> 159 160The key is present in the DNS but not in the managed-keys file. 161 162=item C<revoked> 163 164The key has its revoked flag set. This is printed before the key's 165trust anchor status which should normally be C<untrusted...> if 166B<named> has observed the revocation. 167 168=item C<missing> 169 170There is no DNSKEY record for this trust anchor. This is printed 171before the key's trust anchor status. 172 173=back 174 175By default the managed keys are stored in a file called 176F<managed-keys.bind> in B<named>'s working directory. This location 177can be changed with B<named>'s B<managed-keys-directory> option. If 178you are using views the file may be named with the SHA256 hash of a 179view 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 197dig(1), named(8) 198 199=cut 200