]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Change output of rndc dnssec -status
authorMatthijs Mekking <matthijs@isc.org>
Wed, 15 Oct 2025 14:04:28 +0000 (16:04 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Fri, 28 Nov 2025 14:32:17 +0000 (15:32 +0100)
Wrap 'dns_keymgr_status()' in 'dns_zone_dnssecstatus()' so we can easily
retrieve the zone string name and refresh key time value.

In addition to the current time, output when the next key event is
expected.

Don't log keys that are completely hidden unless verbose is set.
Don't log key state values unless verbose is set, or they are in a
weird state.

For expected key states, log a more useful message of the stage of
the rollover. If we are in the middle of a key rollover, don't log
when the next key rollover is scheduled.

Condense the output for better readability.

bin/named/server.c
lib/dns/dst_api.c
lib/dns/include/dns/keymgr.h
lib/dns/include/dns/zone.h
lib/dns/include/dst/dst.h
lib/dns/keymgr.c
lib/dns/zone.c

index 7c370ddb247f1f2aaf76faed5b9551d0bc73d672..5150594117074f20dfd02b725ce4123977df0b2b 100644 (file)
@@ -14344,10 +14344,8 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
                 * Output the DNSSEC status of the key and signing policy.
                 */
                isc_result_t r;
-               LOCK(&kasp->lock);
-               r = dns_keymgr_status(kasp, &keys, now, &output[0],
-                                     sizeof(output));
-               UNLOCK(&kasp->lock);
+               r = dns_zone_dnssecstatus(zone, kasp, &keys, now, verbose,
+                                         &output[0], sizeof(output));
                CHECK(putstr(text, output));
                if (r != ISC_R_SUCCESS) {
                        CHECK(putstr(text,
index f5d8d94ba4bac10f4dd211433bf3c08c5c6a2949..2d6f739c03005771e399c6af68263e3896ab9140 100644 (file)
@@ -2306,6 +2306,26 @@ dst_key_tkeytoken(const dst_key_t *key) {
        return key->key_tkeytoken;
 }
 
+/*
+ * A key is considered hidden if it has all states set to HIDDEN or NA.
+ *
+ */
+bool
+dst_key_is_hidden(const dst_key_t *key) {
+       REQUIRE(VALID_KEY(key));
+
+       for (int i = 0; i < DST_MAX_KEYSTATES; i++) {
+               dst_key_state_t st;
+               if (dst_key_getstate(key, i, &st) != ISC_R_SUCCESS) {
+                       st = DST_KEY_STATE_HIDDEN;
+               }
+               if (st != DST_KEY_STATE_HIDDEN) {
+                       return false;
+               }
+       }
+       return true;
+}
+
 /*
  * A key is considered unused if it does not have any timing metadata set
  * other than "Created".
index 8e1508304acee2b9dd41446b527a98a675079aca..50b9c18419fcc29848d0822ec1a9d3ab3e0799fe 100644 (file)
@@ -167,19 +167,20 @@ dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
 
 isc_result_t
 dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
-                 isc_stdtime_t now, char *out, size_t out_len);
+                 isc_buffer_t *buf, isc_stdtime_t now, bool verbose,
+                 bool checkds);
 /*%<
  * Retrieve the status of given 'kasp' policy and keys in the
- * 'keyring' and store the printable output in the 'out' buffer.
+ * 'keyring' and store the printable output in the 'buf' buffer.
  *
  *     Requires:
  *\li          'kasp' is not NULL.
  *\li          'keyring' is not NULL.
- *\li          'out' is not NULL.
+ *\li          'buf' is not NULL.
  *
  *     Returns:
  *\li          ISC_R_SUCCESS on success.
- *\li          ISC_R_NOSPACE if the 'out' buffer is too small.
+ *\li          ISC_R_NOSPACE if the 'buf' buffer is too small.
  *\li          ISC_R_FAILURE if other error occurred.
  *\li          Printable status in 'out'.
  *
index d9821e7213bf3343233ccf51395e9f22321ae461..04aa03dd92ae5d2db8488600f0d9a6d864fbea6e 100644 (file)
@@ -691,6 +691,28 @@ dns_zone_unload(dns_zone_t *zone);
  *\li  'zone' to be a valid zone.
  */
 
+isc_result_t
+dns_zone_dnssecstatus(dns_zone_t *zone, dns_kasp_t *kasp,
+                     dns_dnsseckeylist_t *keys, isc_stdtime_t now,
+                     bool verbose, char *out, size_t out_len);
+/*%<
+ * Retrieve the DNSSEC status of given 'zone' and store the printable output
+ * in the 'out' buffer.
+ *
+ *      Requires:
+ *\li           'zone' is not NULL.
+ *\li           'kasp' is not NULL.
+ *\li           'keys' is not NULL.
+ *\li           'out' is not NULL.
+ *
+ *      Returns:
+ *\li           ISC_R_SUCCESS on success.
+ *\li           ISC_R_NOSPACE if the 'out' buffer is too small.
+ *\li           ISC_R_FAILURE if other error occurred.
+ *\li           Printable status in 'out'.
+ *
+ */
+
 dns_kasp_t *
 dns_zone_getkasp(dns_zone_t *zone);
 /*%<
index 061369d50ca10055cd7c2656138ca2dbd9950f17..622b564f1216c4d05eb81585fb3fd2332ef77928 100644 (file)
@@ -1103,6 +1103,15 @@ dst_key_is_unused(const dst_key_t *key);
  *     'key' to be valid.
  */
 
+bool
+dst_key_is_hidden(const dst_key_t *key);
+/*%<
+ * Check if this key is completely hidden.
+ *
+ * Requires:
+ *     'key' to be valid.
+ */
+
 bool
 dst_key_is_published(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *publish);
 /*%<
index 892fcaafda7065bf32c8be6eb5b5949fadd483ea..6ccb4ef87747b74bd6f57d410127fa47eb48bbdb 100644 (file)
@@ -2552,113 +2552,311 @@ failure:
 }
 
 static isc_result_t
-rollover_status(dns_dnsseckey_t *dkey, dns_kasp_t *kasp, isc_stdtime_t now,
-               isc_buffer_t *buf, bool zsk) {
-       char timestr[26]; /* Minimal buf as per ctime_r() spec. */
+keystate_status(dst_key_t *key, isc_buffer_t *buf, const char *pre, int ks) {
+       dst_key_state_t state = NA;
        isc_result_t result = ISC_R_SUCCESS;
-       isc_stdtime_t active_time = 0;
-       dst_key_state_t state = NA, goal = NA;
-       int rrsig, active, retire;
-       dst_key_t *key = dkey->key;
 
-       if (zsk) {
-               rrsig = DST_KEY_ZRRSIG;
-               active = DST_TIME_ACTIVATE;
-               retire = DST_TIME_INACTIVE;
-       } else {
-               rrsig = DST_KEY_KRRSIG;
-               active = DST_TIME_PUBLISH;
-               retire = DST_TIME_DELETE;
+       (void)dst_key_getstate(key, ks, &state);
+       switch (state) {
+       case HIDDEN:
+               RETERR(isc_buffer_printf(buf, "  - %shidden\n", pre));
+               break;
+       case RUMOURED:
+               RETERR(isc_buffer_printf(buf, "  - %srumoured\n", pre));
+               break;
+       case OMNIPRESENT:
+               RETERR(isc_buffer_printf(buf, "  - %somnipresent\n", pre));
+               break;
+       case UNRETENTIVE:
+               RETERR(isc_buffer_printf(buf, "  - %sunretentive\n", pre));
+               break;
+       case NA:
+       default:
+               /* print nothing */
+               break;
        }
 
-       RETERR(isc_buffer_printf(buf, "\n"));
+failure:
+       return result;
+}
+
+static isc_result_t
+rollover_status(dns_dnsseckey_t *dkey, dns_kasp_t *kasp,
+               dns_dnsseckeylist_t *keyring, isc_stdtime_t now,
+               isc_buffer_t *buf, bool *verbose, bool checkds) {
+       isc_result_t result = ISC_R_SUCCESS;
+       dst_key_t *key = dkey->key;
+       dst_key_state_t goal = HIDDEN;
+       dst_key_state_t dnskey = HIDDEN;
+       dst_key_state_t zrrsig = HIDDEN;
+       dst_key_state_t ds = HIDDEN;
+       bool ksk = false;
+       bool zsk = false;
+       bool log_next_rollover = false;
+       int active_state = DST_TIME_ACTIVATE;
+       int retire_state = DST_TIME_INACTIVE;
 
        (void)dst_key_getstate(key, DST_KEY_GOAL, &goal);
-       (void)dst_key_getstate(key, rrsig, &state);
-       (void)dst_key_gettime(key, active, &active_time);
-       if (active_time == 0) {
-               // only interested in keys that were once active.
-               return ISC_R_SUCCESS;
+       (void)dst_key_getstate(key, DST_KEY_DNSKEY, &dnskey);
+       (void)dst_key_getstate(key, DST_KEY_ZRRSIG, &zrrsig);
+       (void)dst_key_getstate(key, DST_KEY_DS, &ds);
+
+       // publish status
+       RETERR(keytime_status(key, now, buf, "  Published:    ", DST_KEY_DNSKEY,
+                             DST_TIME_PUBLISH));
+
+       // signing status
+       result = dst_key_getbool(key, DST_BOOL_KSK, &ksk);
+       if (result == ISC_R_SUCCESS && ksk) {
+               RETERR(keytime_status(key, now, buf, "  Key signing:  ",
+                                     DST_KEY_KRRSIG, DST_TIME_PUBLISH));
+       }
+       result = dst_key_getbool(key, DST_BOOL_ZSK, &zsk);
+       if (result == ISC_R_SUCCESS && zsk) {
+               RETERR(keytime_status(key, now, buf, "  Zone signing: ",
+                                     DST_KEY_ZRRSIG, DST_TIME_ACTIVATE));
        }
 
-       if (goal == HIDDEN && (state == UNRETENTIVE || state == HIDDEN)) {
-               isc_stdtime_t remove_time = 0;
-               // is the key removed yet?
-               state = NA;
-               (void)dst_key_getstate(key, DST_KEY_DNSKEY, &state);
-               if (state == RUMOURED || state == OMNIPRESENT) {
-                       result = dst_key_gettime(key, DST_TIME_DELETE,
-                                                &remove_time);
-                       if (result == ISC_R_SUCCESS) {
+       if (zsk) {
+               if (goal == OMNIPRESENT) {
+                       if (dnskey == HIDDEN && zrrsig == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is created but not "
+                                            "published yet.\n"));
+                       } else if (dnskey == RUMOURED && zrrsig == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is pre-published.\n"));
+                       } else if (dnskey == RUMOURED && zrrsig == RUMOURED) {
+                               RETERR(isc_buffer_printf(buf, "  Introducing "
+                                                             "new key.\n"));
+                       } else if (dnskey == OMNIPRESENT && zrrsig == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is published, but not yet "
+                                            "signing.\n"));
+                       } else if (dnskey == OMNIPRESENT && zrrsig == RUMOURED)
+                       {
+                               if (keymgr_dep(key, keyring, NULL)) {
+                                       RETERR(isc_buffer_printf(
+                                               buf,
+                                               "  Key is published, waiting "
+                                               "for the zone to be completely "
+                                               "signed with this key.\n"));
+                               } else {
+                                       RETERR(isc_buffer_printf(
+                                               buf,
+                                               "  Key is published, "
+                                               "introducing signatures.\n"));
+                               }
+                       } else if (dnskey == OMNIPRESENT &&
+                                  zrrsig == OMNIPRESENT)
+                       {
+                               if (!ksk) {
+                                       log_next_rollover = true;
+                               }
+                       } else {
                                RETERR(isc_buffer_printf(
-                                       buf, "  Key is retired, will be "
-                                            "removed on "));
-                               isc_stdtime_tostring(remove_time, timestr,
-                                                    sizeof(timestr));
-                               RETERR(isc_buffer_printf(buf, "%s", timestr));
+                                       buf, "  Key is in unexpected state, "
+                                            "performing auto-healing.\n"));
+                               *verbose = true;
+                       }
+               } else if (goal == HIDDEN) {
+                       if (dnskey == OMNIPRESENT && zrrsig == OMNIPRESENT) {
+                               if (!ksk) {
+                                       RETERR(isc_buffer_printf(
+                                               buf, "  Key will be retired "
+                                                    "after successor key "
+                                                    "becomes active.\n"));
+                               }
+                       } else if (dnskey == OMNIPRESENT &&
+                                  zrrsig == UNRETENTIVE)
+                       {
+                               RETERR(isc_buffer_printf(
+                                       buf,
+                                       "  Key is retired, waiting until all "
+                                       "signatures generated with this key "
+                                       "are replaced with successor.\n"));
+                       } else if (dnskey == OMNIPRESENT && zrrsig == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is retired, no longer "
+                                            "signing the zone.\n"));
+                       } else if (dnskey == UNRETENTIVE && zrrsig == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is removed from zone.\n"));
+                       } else if (dnskey == HIDDEN && zrrsig == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is completely hidden "
+                                            "(waiting to be purged).\n"));
+                       } else {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  WARNING: Key is in unexpected "
+                                            "state, "
+                                            "performing auto-healing.\n"));
+                               *verbose = true;
                        }
-               } else {
-                       RETERR(isc_buffer_printf(buf, "  Key has been removed "
-                                                     "from the zone"));
                }
-       } else {
-               isc_stdtime_t retire_time = 0;
-               result = dst_key_gettime(key, retire, &retire_time);
-               if (result == ISC_R_SUCCESS) {
-                       if (now < retire_time) {
-                               if (goal == OMNIPRESENT) {
+       } else if (ksk) {
+               if (goal == OMNIPRESENT) {
+                       if (dnskey == HIDDEN && ds == HIDDEN) {
+                               if (!zsk) {
+                                       RETERR(isc_buffer_printf(
+                                               buf, "  Key is created but not "
+                                                    "published yet.\n"));
+                               }
+                       } else if (dnskey == RUMOURED && ds == HIDDEN) {
+                               if (!zsk) {
+                                       RETERR(isc_buffer_printf(
+                                               buf,
+                                               "  Key is pre-published.\n"));
+                               }
+                       } else if (dnskey == OMNIPRESENT && ds == HIDDEN) {
+                               if (keymgr_dep(key, keyring, NULL)) {
                                        RETERR(isc_buffer_printf(
-                                               buf, "  Next rollover "
-                                                    "scheduled on "));
-                                       retire_time = keymgr_prepublication_time(
-                                               dkey, kasp,
-                                               retire_time - active_time, now);
+                                               buf,
+                                               "  Waiting for the DS to be "
+                                               "submitted to the parent.\n"));
                                } else {
                                        RETERR(isc_buffer_printf(
-                                               buf, "  Key will retire on "));
+                                               buf,
+                                               "  Wait for zone to be fully "
+                                               "signed before submitting the "
+                                               "DS to the parent.\n"));
+                               }
+                       } else if (dnskey == OMNIPRESENT && ds == RUMOURED) {
+                               isc_stdtime_t dstime = now;
+                               isc_result_t ret = dst_key_gettime(
+                                       key, DST_TIME_DSPUBLISH, &dstime);
+                               if (ret != ISC_R_SUCCESS || dstime > now) {
+                                       RETERR(isc_buffer_printf(
+                                               buf,
+                                               "  Waiting for the DS to be "
+                                               "published to the parent.\n"));
+                                       if (checkds) {
+                                               RETERR(isc_buffer_printf(
+                                                       buf,
+                                                       "  checkds is enabled, "
+                                                       "BIND will check the "
+                                                       "DS RRset "
+                                                       "periodically.\n"));
+                                       } else {
+                                               RETERR(isc_buffer_printf(
+                                                       buf,
+                                                       "  ! Once the DS is in "
+                                                       "the parent, run 'rndc "
+                                                       "dnssec -checkds -key "
+                                                       "%d published' to mark "
+                                                       "it as published.\n",
+                                                       dst_key_id(key)));
+                                       }
+                               } else {
+                                       RETERR(isc_buffer_printf(
+                                               buf, "  Waiting TTL period for "
+                                                    "validators to pick up "
+                                                    "the new DS RRset.\n"));
+                               }
+                       } else if (dnskey == OMNIPRESENT && ds == OMNIPRESENT) {
+                               log_next_rollover = true;
+                               active_state = DST_TIME_PUBLISH;
+                               retire_state = DST_TIME_DELETE;
+                       } else {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  WARNING: Key is in unexpected "
+                                            "state, "
+                                            "performing auto-healing.\n"));
+                               *verbose = true;
+                       }
+               } else if (goal == HIDDEN) {
+                       if (dnskey == OMNIPRESENT && ds == OMNIPRESENT) {
+                               RETERR(isc_buffer_printf(
+                                       buf,
+                                       "  Key will be retired after the DS is "
+                                       "withdrawn from the parent.\n"));
+                       } else if (dnskey == OMNIPRESENT && ds == UNRETENTIVE) {
+                               isc_stdtime_t dstime = now;
+                               isc_result_t ret = dst_key_gettime(
+                                       key, DST_TIME_DSDELETE, &dstime);
+                               if (ret != ISC_R_SUCCESS || dstime > now) {
+                                       RETERR(isc_buffer_printf(
+                                               buf,
+                                               "  Waiting for the DS to be "
+                                               "removed from the parent.\n"));
+                                       if (checkds) {
+                                               RETERR(isc_buffer_printf(
+                                                       buf,
+                                                       "  checkds is enabled, "
+                                                       "BIND will check the "
+                                                       "DS RRset "
+                                                       "periodically.\n"));
+                                       } else {
+                                               RETERR(isc_buffer_printf(
+                                                       buf,
+                                                       "  ! Once the DS is "
+                                                       "removed from the "
+                                                       "parent, run 'rndc "
+                                                       "dnssec -checkds -key "
+                                                       "%d withdrawn' to mark "
+                                                       "it as withdrawn.\n",
+                                                       dst_key_id(key)));
+                                       }
+                               } else {
+                                       RETERR(isc_buffer_printf(
+                                               buf, "  Waiting TTL period for "
+                                                    "validators to pick up "
+                                                    "the new DS RRset.\n"));
+                               }
+                       } else if (dnskey == OMNIPRESENT && ds == HIDDEN) {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  Key is removed from chain of "
+                                            "trust.\n"));
+                       } else if (dnskey == UNRETENTIVE && ds == HIDDEN) {
+                               if (!zsk) {
+                                       RETERR(isc_buffer_printf(
+                                               buf, "  Key is removed from "
+                                                    "zone.\n"));
+                               }
+                       } else if (dnskey == HIDDEN && ds == HIDDEN) {
+                               if (!zsk) {
+                                       RETERR(isc_buffer_printf(
+                                               buf,
+                                               "  Key is completely hidden "
+                                               "(waiting to be purged).\n"));
                                }
+                       } else {
+                               RETERR(isc_buffer_printf(
+                                       buf, "  WARNING: Key is in unexpected "
+                                            "state, "
+                                            "performing auto-healing.\n"));
+                               *verbose = true;
+                       }
+               }
+       }
+
+       // rollover status
+       if (log_next_rollover) {
+               isc_stdtime_t active_time = 0;
+               isc_stdtime_t retire_time = 0;
+               (void)dst_key_gettime(key, active_state, &active_time);
+               result = dst_key_gettime(key, retire_state, &retire_time);
+               if (result == ISC_R_SUCCESS) {
+                       char timestr[26]; /* Minimal buf as per ctime_r() spec.
+                                          */
+                       if (now < retire_time) {
+                               RETERR(isc_buffer_printf(buf, "  Next rollover "
+                                                             "scheduled on "));
+                               retire_time = keymgr_prepublication_time(
+                                       dkey, kasp, retire_time - active_time,
+                                       now);
                        } else {
                                RETERR(isc_buffer_printf(buf, "  Rollover is "
                                                              "due since "));
                        }
                        isc_stdtime_tostring(retire_time, timestr,
                                             sizeof(timestr));
-                       RETERR(isc_buffer_printf(buf, "%s", timestr));
+                       RETERR(isc_buffer_printf(buf, "%s\n", timestr));
                } else {
                        RETERR(isc_buffer_printf(buf,
-                                                "  No rollover scheduled"));
+                                                "  No rollover scheduled.\n"));
                }
        }
-       RETERR(isc_buffer_printf(buf, "\n"));
-
-failure:
-       return result;
-}
-
-static isc_result_t
-keystate_status(dst_key_t *key, isc_buffer_t *buf, const char *pre, int ks) {
-       dst_key_state_t state = NA;
-       isc_result_t result = ISC_R_SUCCESS;
-
-       (void)dst_key_getstate(key, ks, &state);
-       switch (state) {
-       case HIDDEN:
-               RETERR(isc_buffer_printf(buf, "  - %shidden\n", pre));
-               break;
-       case RUMOURED:
-               RETERR(isc_buffer_printf(buf, "  - %srumoured\n", pre));
-               break;
-       case OMNIPRESENT:
-               RETERR(isc_buffer_printf(buf, "  - %somnipresent\n", pre));
-               break;
-       case UNRETENTIVE:
-               RETERR(isc_buffer_printf(buf, "  - %sunretentive\n", pre));
-               break;
-       case NA:
-       default:
-               /* print nothing */
-               break;
-       }
 
 failure:
        return result;
@@ -2666,76 +2864,58 @@ failure:
 
 isc_result_t
 dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
-                 isc_stdtime_t now, char *out, size_t out_len) {
-       isc_buffer_t buf;
+                 isc_buffer_t *buf, isc_stdtime_t now, bool verbose,
+                 bool checkds) {
        isc_result_t result = ISC_R_SUCCESS;
-       char timestr[26]; /* Minimal buf as per ctime_r() spec. */
 
        REQUIRE(DNS_KASP_VALID(kasp));
        REQUIRE(keyring != NULL);
-       REQUIRE(out != NULL);
-
-       isc_buffer_init(&buf, out, out_len);
-
-       // policy name
-       RETERR(isc_buffer_printf(&buf, "dnssec-policy: %s\n",
-                                dns_kasp_getname(kasp)));
-       RETERR(isc_buffer_printf(&buf, "current time:  "));
-       isc_stdtime_tostring(now, timestr, sizeof(timestr));
-       RETERR(isc_buffer_printf(&buf, "%s\n", timestr));
+       REQUIRE(buf != NULL);
 
        ISC_LIST_FOREACH(*keyring, dkey, link) {
                char algstr[DNS_NAME_FORMATSIZE];
-               bool ksk = false, zsk = false;
 
                if (dst_key_is_unused(dkey->key)) {
                        continue;
                }
 
+               if (!verbose && dst_key_is_hidden(dkey->key)) {
+                       continue;
+               }
+
                // key data
                dns_secalg_format((dns_secalg_t)dst_key_alg(dkey->key), algstr,
                                  sizeof(algstr));
-               RETERR(isc_buffer_printf(&buf, "\nkey: %d (%s), %s\n",
-                                        dst_key_id(dkey->key), algstr,
-                                        keymgr_keyrole(dkey->key)));
-
-               // publish status
-               RETERR(keytime_status(dkey->key, now, &buf,
-                                     "  published:      ", DST_KEY_DNSKEY,
-                                     DST_TIME_PUBLISH));
-
-               // signing status
-               result = dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
-               if (result == ISC_R_SUCCESS && ksk) {
-                       RETERR(keytime_status(
-                               dkey->key, now, &buf, "  key signing:    ",
-                               DST_KEY_KRRSIG, DST_TIME_PUBLISH));
-               }
-               result = dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
-               if (result == ISC_R_SUCCESS && zsk) {
-                       RETERR(keytime_status(
-                               dkey->key, now, &buf, "  zone signing:   ",
-                               DST_KEY_ZRRSIG, DST_TIME_ACTIVATE));
-               }
+               RETERR(isc_buffer_printf(buf, "\n%s %d (%s):\n",
+                                        keymgr_keyrole(dkey->key),
+                                        dst_key_id(dkey->key), algstr));
 
                // rollover status
-               RETERR(rollover_status(dkey, kasp, now, &buf, zsk));
-
-               // key states
-               RETERR(keystate_status(dkey->key, &buf,
-                                      "goal:           ", DST_KEY_GOAL));
-               RETERR(keystate_status(dkey->key, &buf,
-                                      "dnskey:         ", DST_KEY_DNSKEY));
-               RETERR(keystate_status(dkey->key, &buf,
-                                      "ds:             ", DST_KEY_DS));
-               RETERR(keystate_status(dkey->key, &buf,
-                                      "zone rrsig:     ", DST_KEY_ZRRSIG));
-               RETERR(keystate_status(dkey->key, &buf,
-                                      "key rrsig:      ", DST_KEY_KRRSIG));
+               RETERR(rollover_status(dkey, kasp, keyring, now, buf, &verbose,
+                                      checkds));
+
+               if (verbose) {
+                       // key states
+                       RETERR(isc_buffer_printf(buf, "  Key states:\n"));
+
+                       RETERR(keystate_status(
+                               dkey->key, buf,
+                               "goal:           ", DST_KEY_GOAL));
+                       RETERR(keystate_status(
+                               dkey->key, buf,
+                               "dnskey:         ", DST_KEY_DNSKEY));
+                       RETERR(keystate_status(dkey->key, buf,
+                                              "ds:             ", DST_KEY_DS));
+                       RETERR(keystate_status(
+                               dkey->key, buf,
+                               "zone rrsig:     ", DST_KEY_ZRRSIG));
+                       RETERR(keystate_status(
+                               dkey->key, buf,
+                               "key rrsig:      ", DST_KEY_KRRSIG));
+               }
        }
 
 failure:
-
        return result;
 }
 
index 4ddeb709688c03f63e37695678f84c9a4c11e901..cfe76c97068ecb07dc946324f4007d97500c2314 100644 (file)
@@ -22283,6 +22283,42 @@ dns_zone_rekey(dns_zone_t *zone, bool fullsign, bool forcekeymgr) {
        }
 }
 
+isc_result_t
+dns_zone_dnssecstatus(dns_zone_t *zone, dns_kasp_t *kasp,
+                     dns_dnsseckeylist_t *keys, isc_stdtime_t now,
+                     bool verbose, char *out, size_t out_len) {
+       isc_buffer_t buf;
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_time_t refreshkeytime;
+       isc_stdtime_t refresh;
+       char timestr[26];
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+       REQUIRE(out != NULL);
+
+       isc_buffer_init(&buf, out, out_len);
+
+       RETERR(isc_buffer_printf(
+               &buf, "DNSSEC status for zone '%s' using policy '%s':\n",
+               zone->strname, dns_kasp_getname(kasp)));
+
+       isc_stdtime_tostring(now, timestr, sizeof(timestr));
+       RETERR(isc_buffer_printf(&buf, "Current time:   %s\n", timestr));
+
+       dns_zone_getrefreshkeytime(zone, &refreshkeytime);
+       refresh = isc_time_seconds(&refreshkeytime);
+       isc_stdtime_tostring(refresh, timestr, sizeof(timestr));
+       RETERR(isc_buffer_printf(&buf, "Next key event: %s\n", timestr));
+
+       bool checkds = zone->checkdstype != dns_checkdstype_no;
+       LOCK(&kasp->lock);
+       result = dns_keymgr_status(kasp, keys, &buf, now, verbose, checkds);
+       UNLOCK(&kasp->lock);
+
+failure:
+       return result;
+}
+
 isc_result_t
 dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
                 unsigned int *errors) {