1#!@PERL@ 2# 3# Copyright (C) Internet Systems Consortium, Inc. ("ISC") 4# 5# This Source Code Form is subject to the terms of the Mozilla Public 6# License, v. 2.0. If a copy of the MPL was not distributed with this 7# file, You can obtain one at http://mozilla.org/MPL/2.0/. 8# 9# See the COPYRIGHT file distributed with this work for additional 10# information regarding copyright ownership. 11 12use warnings; 13use FileHandle; 14use IPC::Open2; 15use POSIX qw/strftime/; 16 17# 18# We only compare keyid / DNSSEC algorithm pairs. If this succeeds then 19# the crypto will likely succeed. If it fails then the crypto will definitely 20# fail. 21# 22$prefix = "@prefix@"; 23$dig = "$prefix/bin/dig +cd +dnssec +noall +answer"; 24$dsfromkey = "$prefix/sbin/dnssec-dsfromkey -1 -A -f /dev/stdin"; 25 26# Get "now" in a RRSIG datestamp format. 27$now = strftime "%Y%m%d%H%M%S", gmtime; 28 29foreach $zone (@ARGV) { 30 my %algorithms = (); 31 my %dnskeygood = (); 32 my %dnskeyalg = (); 33 my %dnskey = (); 34 my %dsgood = (); 35 my %ds = (); 36 37 # Read the DS records and extract the key id, algorithm pairs 38 open(DS, "$dig -t DS -q $zone|") || die("dig DS failed"); 39 while(<DS>) { 40 @words = split; 41 if ($words[3] eq "RRSIG" && $words[4] eq "DS") { 42 next if ($words[8] >= $now && $words[9] <= $now); 43 print "BAD SIG DATES: $_"; 44 } 45 next if ($words[3] ne "DS"); 46 $ds{"$words[4] $words[5]"} = 1; 47 $algorithms{"$words[5]"} = 1; 48 } 49 close(DS); 50 51 # Read the RRSIG(DNSKEY) records and extract the key id, 52 # algorithm pairs. Set good if we have a match against the DS 53 # records. DNSKEY records should be before the RRSIG records. 54 open(DNSKEY, "$dig -t DNSKEY -q $zone|") || die("dig DNSKEY failed"); 55 while (<DNSKEY>) { 56 @words = split; 57 if ($words[3] eq "DNSKEY") { 58 $dnskeyalg{"$words[6]"} = 1; 59 next if (! -e "/dev/stdin"); 60 # get the key id ($dswords[3]). 61 $pid = open2(*Reader, *Writer, "$dsfromkey $zone"); 62 die("dsfromkey failed") if ($pid == -1); 63 print Writer "$_"; 64 close(Writer); 65 $line = <Reader>; 66 close(Reader); 67 @dswords = split /\s/, $line; 68 $dnskey{"$dswords[3] $dswords[4]"} = 1; 69 next; 70 } 71 next if ($words[3] ne "RRSIG" || $words[4] ne "DNSKEY"); 72 if ($words[8] >= $now && $words[9] <= $now) { 73 # If we don't have /dev/stdin then just check for the 74 # RRSIG otherwise check for both the DNSKEY and 75 # RRSIG. 76 $dsgood{"$words[5]"} = 1 77 if (! -e "/dev/stdin" && 78 exists($ds{"$words[10] $words[5]"})); 79 $dsgood{"$words[5]"} = 1 80 if (exists($ds{"$words[10] $words[5]"}) && 81 exists($dnskey{"$words[10] $words[5]"})); 82 $dnskeygood{"$words[5]"} = 1 83 if (! -e "/dev/stdin"); 84 $dnskeygood{"$words[5]"} = 1 85 if (exists($dnskey{"$words[10] $words[5]"})); 86 } else { 87 $dnskeygood{"$words[5]"} = 1; 88 print "BAD SIG DATES: $_"; 89 } 90 } 91 close(DNSKEY); 92 93 # Do we have signatures for all DNSKEY algorithms? 94 foreach $alg ( keys %dnskeyalg ) { 95 print "Missing $zone DNSKEY RRSIG for algorithm $alg\n" 96 if (!exists($dnskeygood{$alg})); 97 } 98 99 # Do we have a matching self signed DNSKEY for all DNSSEC algorithms 100 # in the DS records. 101 $count = 0; 102 foreach $alg ( keys %algorithms ) { 103 if (exists($dsgood{$alg})) { 104 print "$zone algorithm $alg good " . 105 "(found DS / self signed DNSKEY pair)\n"; 106 } else { 107 print "$zone algorithm $alg bad " . 108 "(no DS / self signed DNSKEY pair found)\n"; 109 } 110 $count++; 111 } 112 print "$zone has no secure delegation records\n" 113 if (! $count); 114} 115