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