...
 
Commits (6)
  • Matthijs Mekking's avatar
    Move dst key printtime in separate function · 7915327a
    Matthijs Mekking authored
    I'd like to use the same functionality (pretty print the datetime
    of keytime metadata) in the 'rndc dnssec -status' command.  So it is
    better that this logic is done in a separate function.
    
    Since the stdtime.c code have differernt files for unix and win32,
    I think the "#ifdef WIN32" define can be dropped.
    
    (cherry picked from commit 9e03f8e8)
    7915327a
  • Matthijs Mekking's avatar
    Implement dummy 'rndc dnssec -status' command · 34a9c3f6
    Matthijs Mekking authored
    Add the code and documentation required to provide DNSSEC signing
    status through rndc.  This does not yet show any useful information,
    just provide the command that will output some dummy string.
    
    (cherry picked from commit e1ba1bea)
    34a9c3f6
  • Matthijs Mekking's avatar
    Output rndc dnssec -status · f1b3686c
    Matthijs Mekking authored
    Implement the 'rndc dnssec -status' command that will output
    some information about the key states, such as which policy is
    used for the zone, what keys are in use, and when rollover is
    scheduled.
    
    Add loose testing in the kasp system test, the actual times are
    already tested via key file inspection.
    
    (cherry picked from commit 19ce9ec1)
    f1b3686c
  • Matthijs Mekking's avatar
    Update notes, changes for #1612 · 2d9b282d
    Matthijs Mekking authored
    (cherry picked from commit e273b95a)
    2d9b282d
  • Matthijs Mekking's avatar
    Fix linking problem for #1612 · 9f5a4380
    Matthijs Mekking authored
    When a library is examined, an object file within it can be left out
    of the link if it does not provide symbols that the symbol table
    needs.  Introducing `isc_stdtime_tostring` caused a build failure for
    `update_test` because it now requires `libisc.a(stdtime.o)` and that
    also exports the `isc_stdtime_get` symbol, meaning we have a
    multiple definition error.
    
    Add a local version of `isc_stdtime_tostring`, so that the linker
    will not search for it in available object files.
    9f5a4380
  • Matthijs Mekking's avatar
    Merge branch '1612-rndc-dnssec-status-v9_16' into 'v9_16' · 99b9c82c
    Matthijs Mekking authored
    Resolve "Get current state of DNSSEC keys (kasp) via rndc"
    
    See merge request !3771
    99b9c82c
5452. [bug] The "blackhole" ACL was accidentally disabled with
respect to client queries. [GL #1936]
5451. [func] Add 'rndc dnssec -status' command. [GL #1612]
5449. [bug] Fix a socket shutdown race in netmgr udp. [GL #1938]
5448. [bug] Fix a race condition in isc__nm_tcpdns_send().
......
......@@ -209,6 +209,8 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
result = named_server_changezone(named_g_server, cmdline, text);
} else if (command_compare(command, NAMED_COMMAND_DELZONE)) {
result = named_server_delzone(named_g_server, lex, text);
} else if (command_compare(command, NAMED_COMMAND_DNSSEC)) {
result = named_server_dnssec(named_g_server, lex, text);
} else if (command_compare(command, NAMED_COMMAND_DNSTAP) ||
command_compare(command, NAMED_COMMAND_DNSTAPREOPEN))
{
......
......@@ -61,6 +61,7 @@
#define NAMED_COMMAND_SHOWZONE "showzone"
#define NAMED_COMMAND_SYNC "sync"
#define NAMED_COMMAND_SIGNING "signing"
#define NAMED_COMMAND_DNSSEC "dnssec"
#define NAMED_COMMAND_ZONESTATUS "zonestatus"
#define NAMED_COMMAND_NTA "nta"
#define NAMED_COMMAND_TESTGEN "testgen"
......
......@@ -333,6 +333,13 @@ isc_result_t
named_server_signing(named_server_t *server, isc_lex_t *lex,
isc_buffer_t **text);
/*%
* Lists the DNSSEC status for a given zone.
*/
isc_result_t
named_server_dnssec(named_server_t *server, isc_lex_t *lex,
isc_buffer_t **text);
/*%
* Lists status information for a given zone (e.g., name, type, files,
* load time, expiry, etc).
......
......@@ -58,6 +58,7 @@
#include <dns/dlz.h>
#include <dns/dns64.h>
#include <dns/dnsrps.h>
#include <dns/dnssec.h>
#include <dns/dyndb.h>
#include <dns/events.h>
#include <dns/fixedname.h>
......@@ -65,6 +66,7 @@
#include <dns/geoip.h>
#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/keymgr.h>
#include <dns/keytable.h>
#include <dns/keyvalues.h>
#include <dns/lib.h>
......@@ -14465,6 +14467,83 @@ cleanup:
return (result);
}
isc_result_t
named_server_dnssec(named_server_t *server, isc_lex_t *lex,
isc_buffer_t **text) {
isc_result_t result = ISC_R_SUCCESS;
dns_zone_t *zone = NULL;
dns_kasp_t *kasp = NULL;
dns_dnsseckeylist_t keys;
dns_dnsseckey_t *key;
const char *ptr;
/* variables for -status */
char output[BUFSIZ];
isc_stdtime_t now;
isc_time_t timenow;
const char *dir;
/* Skip the command name. */
ptr = next_token(lex, text);
if (ptr == NULL) {
return (ISC_R_UNEXPECTEDEND);
}
/* Find out what we are to do. */
ptr = next_token(lex, text);
if (ptr == NULL) {
return (ISC_R_UNEXPECTEDEND);
}
if (strcasecmp(ptr, "-status") != 0) {
return (DNS_R_SYNTAX);
}
ISC_LIST_INIT(keys);
CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
if (zone == NULL) {
CHECK(ISC_R_UNEXPECTEDEND);
}
kasp = dns_zone_getkasp(zone);
if (kasp == NULL) {
CHECK(putstr(text, "zone does not have dnssec-policy"));
CHECK(putnull(text));
goto cleanup;
}
/* -status */
TIME_NOW(&timenow);
now = isc_time_seconds(&timenow);
dir = dns_zone_getkeydirectory(zone);
LOCK(&kasp->lock);
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), dir, now,
dns_zone_getmctx(zone), &keys);
UNLOCK(&kasp->lock);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
goto cleanup;
}
LOCK(&kasp->lock);
dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
UNLOCK(&kasp->lock);
CHECK(putstr(text, output));
CHECK(putnull(text));
cleanup:
while (!ISC_LIST_EMPTY(keys)) {
key = ISC_LIST_HEAD(keys);
ISC_LIST_UNLINK(keys, key, link);
dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
}
if (zone != NULL) {
dns_zone_detach(&zone);
}
return (result);
}
static isc_result_t
putmem(isc_buffer_t **b, const char *str, size_t len) {
isc_result_t result;
......
......@@ -104,6 +104,9 @@ command is one of the following:\n\
Add zone to given view. Requires allow-new-zones option.\n\
delzone [-clean] zone [class [view]]\n\
Removes zone from given view.\n\
dnssec -status zone [class [view]]\n\
Show the DNSSEC signing state for the specified zone.\n\
Requires the zone to have a dnssec-policy.\n\
dnstap -reopen\n\
Close, truncate and re-open the DNSTAP output file.\n\
dnstap -roll count\n\
......
......@@ -162,6 +162,10 @@ Currently supported commands are:
See also ``rndc addzone`` and ``rndc modzone``.
``dnssec`` [**-status** *zone* [*class* [*view*]]
Show the DNSSEC signing state for the specified zone. Requires the
zone to have a "dnssec-policy".
``dnstap`` ( **-reopen** | **-roll** [*number*] )
Close and re-open DNSTAP output files. ``rndc dnstap -reopen`` allows
the output file to be renamed externally, so that :manpage:`named(8)` can
......
......@@ -24,4 +24,5 @@ rm -f ns*/managed-keys.bind
rm -f ns*/*.mkeys
rm -f ns*/zones ns*/*.db.infile
rm -f *.created published.test* retired.test*
rm -f rndc.dnssec.status.out.*
rm -f python.out.*
......@@ -11,6 +11,15 @@
// NS4
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
key "sha1" {
algorithm "hmac-sha1";
secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
......
......@@ -11,6 +11,15 @@
// NS5
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
key "sha1" {
algorithm "hmac-sha1";
secret "FrSt77yPTFx6hTs4i2tKLB9LmE0=";
......
This diff is collapsed.
......@@ -162,6 +162,10 @@ back. To remove it permanently, it must also be removed from
.sp
See also \fBrndc addzone\fP and \fBrndc modzone\fP\&.
.TP
\fBdnssec\fP [\fB\-status\fP \fIzone\fP [\fIclass\fP [\fIview\fP]]
Show the DNSSEC signing state for the specified zone. Requires the
zone to have a "dnssec\-policy".
.TP
\fBdnstap\fP ( \fB\-reopen\fP | \fB\-roll\fP [\fInumber\fP] )
Close and re\-open DNSTAP output files. \fBrndc dnstap \-reopen\fP allows
the output file to be renamed externally, so that \fBnamed(8)\fP can
......
......@@ -29,7 +29,9 @@ New Features
Feature Changes
~~~~~~~~~~~~~~~
- None.
- New ``rndc`` command ``rndc dnssec -status`` that shows the current
DNSSEC policy and keys in use, the key states and rollover status.
[GL #1612]
Bug Fixes
~~~~~~~~~
......
......@@ -1906,7 +1906,6 @@ printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
isc_result_t result;
char output[26]; /* Minimum buffer as per ctime_r() specification. */
isc_stdtime_t when;
time_t t;
char utc[sizeof("YYYYMMDDHHSSMM")];
isc_buffer_t b;
isc_region_t r;
......@@ -1916,18 +1915,7 @@ printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
return;
}
/* time_t and isc_stdtime_t might be different sizes */
t = when;
#ifdef WIN32
if (ctime_s(output, sizeof(output), &t) != 0) {
goto error;
}
#else /* ifdef WIN32 */
if (ctime_r(&t, output) == NULL) {
goto error;
}
#endif /* ifdef WIN32 */
isc_stdtime_tostring(when, output, sizeof(output));
isc_buffer_init(&b, utc, sizeof(utc));
result = dns_time32_totext(when, &b);
if (result != ISC_R_SUCCESS) {
......
......@@ -51,6 +51,23 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
*\li On error, keypool is unchanged
*/
void
dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
isc_stdtime_t now, char *out, size_t out_len);
/*%<
* Retrieve the status of given 'kasp' policy and keys in the
* 'keyring' and store the printable output in the 'out' buffer.
*
* Requires:
*\li 'kasp' is not NULL.
*\li 'keyring' is not NULL.
*\li 'out' is not NULL.
*
* Returns:
*\li Printable status in 'out'.
*
*/
ISC_LANG_ENDDECLS
#endif /* DNS_KEYMGR_H */
......@@ -1841,3 +1841,204 @@ failure:
return (result);
}
static void
keytime_status(dst_key_t *key, isc_stdtime_t now, isc_buffer_t *buf,
const char *pre, int ks, int kt) {
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
isc_result_t ret;
isc_stdtime_t when = 0;
dst_key_state_t state;
isc_buffer_printf(buf, "%s", pre);
(void)dst_key_getstate(key, ks, &state);
ret = dst_key_gettime(key, kt, &when);
if (state == RUMOURED || state == OMNIPRESENT) {
isc_buffer_printf(buf, "yes - since ");
} else if (now < when) {
isc_buffer_printf(buf, "no - scheduled ");
} else {
isc_buffer_printf(buf, "no\n");
return;
}
if (ret == ISC_R_SUCCESS) {
isc_stdtime_tostring(when, timestr, sizeof(timestr));
isc_buffer_printf(buf, "%s\n", timestr);
}
}
static void
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. */
isc_result_t ret = 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;
}
isc_buffer_printf(buf, "\n");
(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;
}
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) {
ret = dst_key_gettime(key, DST_TIME_DELETE,
&remove_time);
if (ret == ISC_R_SUCCESS) {
isc_buffer_printf(buf, " Key is retired, will "
"be removed on ");
isc_stdtime_tostring(remove_time, timestr,
sizeof(timestr));
isc_buffer_printf(buf, "%s", timestr);
}
} else {
isc_buffer_printf(
buf, " Key has been removed from the zone");
}
} else {
isc_stdtime_t retire_time = 0;
uint32_t lifetime = 0;
(void)dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
ret = dst_key_gettime(key, retire, &retire_time);
if (ret == ISC_R_SUCCESS) {
if (now < retire_time) {
if (goal == OMNIPRESENT) {
isc_buffer_printf(buf,
" Next rollover "
"scheduled on ");
retire_time = keymgr_prepublication_time(
dkey, kasp, lifetime, now);
} else {
isc_buffer_printf(
buf, " Key will retire on ");
}
} else {
isc_buffer_printf(buf,
" Rollover is due since ");
}
isc_stdtime_tostring(retire_time, timestr,
sizeof(timestr));
isc_buffer_printf(buf, "%s", timestr);
} else {
isc_buffer_printf(buf, " No rollover scheduled");
}
}
isc_buffer_printf(buf, "\n");
}
static void
keystate_status(dst_key_t *key, isc_buffer_t *buf, const char *pre, int ks) {
dst_key_state_t state = NA;
(void)dst_key_getstate(key, ks, &state);
switch (state) {
case HIDDEN:
isc_buffer_printf(buf, " - %shidden\n", pre);
break;
case RUMOURED:
isc_buffer_printf(buf, " - %srumoured\n", pre);
break;
case OMNIPRESENT:
isc_buffer_printf(buf, " - %somnipresent\n", pre);
break;
case UNRETENTIVE:
isc_buffer_printf(buf, " - %sunretentive\n", pre);
break;
case NA:
default:
/* print nothing */
break;
}
}
void
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;
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
isc_buffer_printf(&buf, "dnssec-policy: %s\n", dns_kasp_getname(kasp));
isc_buffer_printf(&buf, "current time: ");
isc_stdtime_tostring(now, timestr, sizeof(timestr));
isc_buffer_printf(&buf, "%s\n", timestr);
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
dkey = ISC_LIST_NEXT(dkey, link))
{
char algstr[DNS_NAME_FORMATSIZE];
bool ksk = false, zsk = false;
if (dst_key_is_unused(dkey->key)) {
continue;
}
// key data
dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
dns_secalg_format((dns_secalg_t)dst_key_alg(dkey->key), algstr,
sizeof(algstr));
isc_buffer_printf(&buf, "\nkey: %d (%s), %s\n",
dst_key_id(dkey->key), algstr,
keymgr_keyrole(dkey->key));
// publish status
keytime_status(dkey->key, now, &buf,
" published: ", DST_KEY_DNSKEY,
DST_TIME_PUBLISH);
// signing status
if (ksk) {
keytime_status(dkey->key, now, &buf,
" key signing: ", DST_KEY_KRRSIG,
DST_TIME_PUBLISH);
}
if (zsk) {
keytime_status(dkey->key, now, &buf,
" zone signing: ", DST_KEY_ZRRSIG,
DST_TIME_ACTIVATE);
}
// rollover status
rollover_status(dkey, kasp, now, &buf, zsk);
// key states
keystate_status(dkey->key, &buf,
"goal: ", DST_KEY_GOAL);
keystate_status(dkey->key, &buf,
"dnskey: ", DST_KEY_DNSKEY);
keystate_status(dkey->key, &buf,
"ds: ", DST_KEY_DS);
keystate_status(dkey->key, &buf,
"zone rrsig: ", DST_KEY_ZRRSIG);
keystate_status(dkey->key, &buf,
"key rrsig: ", DST_KEY_KRRSIG);
}
}
......@@ -75,11 +75,34 @@ set_mystdtime(int year, int month, int day) {
mystdtime = timegm(&tm);
}
/*
* Override isc_stdtime_get() from lib/isc/[unix/win32]/stdtime.c
* with our own for testing purposes.
*/
void
isc_stdtime_get(isc_stdtime_t *now) {
*now = mystdtime;
}
/*
* Because update_test.o requires dns_update_*() symbols, the linker is able
* to resolve them using libdns.a(update.o). That object has other symbol
* dependencies (dst_key_*()), so it pulls libdns.a(dst_api.o).
* That object file requires the isc_stdtime_tostring() symbol.
*
* Define a local version here so that we don't have to depend on
* libisc.a(stdtime.o). If isc_stdtime_tostring() would be left undefined,
* the linker has to get the required object file, and that will result in a
* multiple definition error because the isc_stdtime_get() symbol exported
* there is already in the exported list.
*/
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen) {
UNUSED(t);
UNUSED(out);
UNUSED(outlen);
}
/* simple increment by 1 */
static void
increment_test(void **state) {
......
......@@ -472,6 +472,7 @@ dns_keydata_fromdnskey
dns_keydata_todnskey
dns_keyflags_fromtext
dns_keymgr_run
dns_keymgr_status
dns_keynode_dsset
dns_keynode_initial
dns_keynode_managed
......
......@@ -15,6 +15,7 @@
/*! \file */
#include <inttypes.h>
#include <stdlib.h>
#include <isc/lang.h>
......@@ -37,6 +38,20 @@ isc_stdtime_get(isc_stdtime_t *t);
*\li 't' is a valid pointer.
*/
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen);
/*
* Convert 't' into a null-terminated string of the form
* "Wed Jun 30 21:49:08 1993". Store the string in the 'out'
* buffer.
*
* Requires:
*
* 't' is a valid time.
* 'out' is a valid pointer.
* 'outlen' is at least 26.
*/
#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
/*
* Convert the standard time to its 32-bit version.
......
......@@ -49,3 +49,18 @@ isc_stdtime_get(isc_stdtime_t *t) {
*t = (isc_stdtime_t)ts.tv_sec;
}
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen) {
time_t when;
REQUIRE(out != NULL);
REQUIRE(outlen >= 26);
UNUSED(outlen);
/* time_t and isc_stdtime_t might be different sizes */
when = t;
INSIST((ctime_r(&when, out) != NULL));
*(out + strlen(out) - 1) = '\0';
}
......@@ -13,6 +13,7 @@
#define ISC_STDTIME_H 1
#include <inttypes.h>
#include <stdlib.h>
#include <isc/lang.h>
......@@ -35,6 +36,20 @@ isc_stdtime_get(isc_stdtime_t *t);
* 't' is a valid pointer.
*/
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen);
/*
* Convert 't' into a null-terminated string of the form
* "Wed Jun 30 21:49:08 1993". Store the string in the 'out'
* buffer.
*
* Requires:
*
* 't' is a valid time.
* 'out' is a valid pointer.
* 'outlen' is at least 26.
*/
#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
/*
* Convert the standard time to its 32-bit version.
......
......@@ -606,6 +606,7 @@ isc_stdio_sync
isc_stdio_tell
isc_stdio_write
isc_stdtime_get
isc_stdtime_tostring
isc_string_strerror_r
isc_symtab_count
isc_symtab_create
......
......@@ -25,3 +25,17 @@ isc_stdtime_get(isc_stdtime_t *t) {
(void)_time32(t);
}
void
isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen) {
time_t when;
REQUIRE(out != NULL);
/* Minimum buffer as per ctime_r() specification. */
REQUIRE(outlen >= 26);
/* time_t and isc_stdtime_t might be different sizes */
when = t;
INSIST((ctime_s(out, outlen, &when) == 0));
*(out + strlen(out) - 1) = '\0';
}