...
 
Commits (5)
5451. [func] Add 'rndc dnssec -status' command. [GL #1612]
5450. [placeholder]
5449. [bug] Fix a socket shutdown race in netmgr udp. [GL #1938]
......
......@@ -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).
......
......@@ -59,6 +59,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>
......@@ -66,6 +67,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>
......@@ -14463,6 +14465,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;
......
......@@ -105,6 +105,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,6 +29,10 @@ New Features
Feature Changes
~~~~~~~~~~~~~~~
- New ``rndc`` command ``rndc dnssec -status`` that shows the current
DNSSEC policy and keys in use, the key states and rollover status.
[GL #1612]
- Disable and disallow static linking of BIND 9 binaries and libraries
as BIND 9 modules require ``dlopen()`` support and static linking also
prevents using security features like read-only relocations (RELRO) or
......
......@@ -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);
}
}
......@@ -470,6 +470,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.
......
......@@ -605,6 +605,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';
}