From cfb1587eb9a6dc6d1d36ea0344e1b20068b81e88 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 30 Jun 2009 02:53:46 +0000 Subject: [PATCH] 2619. [func] Add support for RFC 5011, automatic trust anchor maintenance. The new "managed-keys" statement can be used in place of "trusted-keys" for zones which support this protocol. (Note: this syntax is expected to change prior to 9.7.0 final.) [RT #19248] --- CHANGES | 6 + README.rfc5011 | 67 + bin/dnssec/Makefile.in | 15 +- bin/dnssec/dnssec-keyfromlabel.c | 13 +- bin/dnssec/dnssec-keygen.c | 13 +- bin/dnssec/dnssec-revoke.8 | 62 + bin/dnssec/dnssec-revoke.c | 217 ++++ bin/dnssec/dnssec-revoke.docbook | 138 +++ bin/dnssec/dnssec-revoke.html | 73 ++ bin/dnssec/win32/revoke.dsp | 103 ++ bin/dnssec/win32/revoke.dsw | 29 + bin/dnssec/win32/revoke.mak | 324 +++++ bin/named/config.c | 14 +- bin/named/include/named/server.h | 4 +- bin/named/server.c | 235 +++- bin/named/xfrout.c | 203 +-- lib/dns/Makefile.in | 15 +- lib/dns/db.c | 5 +- lib/dns/dst_api.c | 12 +- lib/dns/dst_internal.h | 4 +- lib/dns/include/dns/db.h | 7 +- lib/dns/include/dns/events.h | 3 +- lib/dns/include/dns/keydata.h | 55 + lib/dns/include/dns/keytable.h | 180 ++- lib/dns/include/dns/keyvalues.h | 5 +- lib/dns/include/dns/master.h | 3 +- lib/dns/include/dns/name.h | 42 +- lib/dns/include/dns/rriterator.h | 103 ++ lib/dns/include/dns/soa.h | 8 +- lib/dns/include/dns/types.h | 3 +- lib/dns/include/dns/view.h | 6 +- lib/dns/include/dns/zone.h | 5 +- lib/dns/include/dst/dst.h | 11 +- lib/dns/keydata.c | 89 ++ lib/dns/keytable.c | 315 ++++- lib/dns/master.c | 4 +- lib/dns/rdata/generic/keydata_65533.c | 372 ++++++ lib/dns/rdata/generic/keydata_65533.h | 35 + lib/dns/rriterator.c | 202 +++ lib/dns/soa.c | 35 +- lib/dns/validator.c | 22 +- lib/dns/view.c | 33 +- lib/dns/win32/libdns.def | 18 + lib/dns/win32/libdns.dsp | 16 + lib/dns/win32/libdns.mak | 48 + lib/dns/zone.c | 1654 ++++++++++++++++++++++--- lib/isc/random.c | 4 +- lib/isccfg/namedconf.c | 31 +- win32utils/BINDBuild.dsw | 21 + 49 files changed, 4305 insertions(+), 577 deletions(-) create mode 100644 README.rfc5011 create mode 100644 bin/dnssec/dnssec-revoke.8 create mode 100644 bin/dnssec/dnssec-revoke.c create mode 100644 bin/dnssec/dnssec-revoke.docbook create mode 100644 bin/dnssec/dnssec-revoke.html create mode 100644 bin/dnssec/win32/revoke.dsp create mode 100644 bin/dnssec/win32/revoke.dsw create mode 100644 bin/dnssec/win32/revoke.mak create mode 100644 lib/dns/include/dns/keydata.h create mode 100644 lib/dns/include/dns/rriterator.h create mode 100644 lib/dns/keydata.c create mode 100644 lib/dns/rdata/generic/keydata_65533.c create mode 100644 lib/dns/rdata/generic/keydata_65533.h create mode 100644 lib/dns/rriterator.c diff --git a/CHANGES b/CHANGES index b3c7cf6e99..d1b2391994 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +2619. [func] Add support for RFC 5011, automatic trust anchor + maintenance. The new "managed-keys" statement can + be used in place of "trusted-keys" for zones which + support this protocol. (Note: this syntax is + expected to change prior to 9.7.0 final.) [RT #19248] + 2618. [bug] The sdb and sdlz db_interator_seek() methods could loop infinitely. [RT #19847] diff --git a/README.rfc5011 b/README.rfc5011 new file mode 100644 index 0000000000..e8f07d0fed --- /dev/null +++ b/README.rfc5011 @@ -0,0 +1,67 @@ +BIND 9.7.0 introduces support for RFC 5011, dynamic trust anchor +management. Using this feature allows named to keep track of changes to +critical DNSSEC keys without any need for the operator to make changes to +configuration files. + +As of 9.7.0a1, the syntax for using RFC5011 is expected to change, so +proper documentation has yet to be written. This file is intended to +provide enough information to get started. + +AUTHORITATIVE SERVER +-------------------- + +To set up an authoritative zone for RFC5011 trust anchor maintenance, +generate two (or more) key signing keys (KSKs) for the zone. Sign the zone +with one of them; this is the "active" KSK. All KSK's which do not sign +the zone are "stand-by" keys. + +Any validating resolver which is configured to use the active KSK as an +RFC5011-managed trust anchor will take note of the stand-by KSKs in the +zone's DNSKEY RRset, and store them for future reference. The resolver +will recheck the zone periodically, and after 30 days, if the new key is +still there, then the key will be accepted by the resolver as a valid +trust anchor for the zone. + +At any time after this 30-day acceptance timer has expired, the active +KSK can be revoked and the zone can be "rolled over" to one of the +standby KSKs. + +To revoke a key, the new command "dnssec-revoke" has been added. This adds +the REVOKED bit to the key flags and re-generates the K*.key and K*.private +files. + +After revoking the active key, the zone must be signed with both the +revoked KSK and the new active KSK. Once a key has been revoked and +used to sign the DNSKEY RRset in which it appears, that key will never +again be accepted as a valid trust anchor by the resolver. However, +validation can proceed using the new active key (which had been accepted +by the resolver when it was a stand-by key). + +See RFC 5011 for more details on key rollover scenarios. + +VALIDATING RESOLVER +------------------- + +NOTE: This is expected to change before 9.7.0 is final! + +To configure a validating resolver to use RFC5011 to maintain a trust +anchor, configure the trust anchor using a "managed-keys" statement +instead of a "trusted-keys" statement. + +The syntax for "managed-keys" is identical to that for "trusted-keys". +However, whereas a trusted key is trusted permanently until it is removed +from named.conf, a managed key is only trusted for as long as it takes to +initialize RFC5011 key maintenance. + +When named loads for the first time with a managed key configured, it +will fetch the DNSKEY RRset directly from the zone apex and check its +signature against the key specified in the "managed-keys" statement. +If it is validly signed, then the DNSKEY RRset is used as the basis for a +new managed keys database. + +From that point on, when named loads, it will see the "managed-keys" +statement, check to make sure RFC5011 key maintenance has already been +initialized for the specified zone, and if so, it will simply move on. +No action will be taken unless a key is *removed* from the "managed-keys" +statement--in which case that zone is removed from the managed keys +database as well, and RFC5011 key maintenance will no longer be used. diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in index d59a38fb11..81c4725f98 100644 --- a/bin/dnssec/Makefile.in +++ b/bin/dnssec/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.35 2008/11/07 02:28:49 marka Exp $ +# $Id: Makefile.in,v 1.36 2009/06/30 02:52:32 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -40,18 +40,19 @@ LIBS = ${DNSLIBS} ${ISCLIBS} @LIBS@ # Alphabetically TARGETS = dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \ - dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ + dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \ + dnssec-revoke@EXEEXT@ OBJS = dnssectool.@O@ SRCS = dnssec-dsfromkey.c dnssec-keyfromlabel.c dnssec-keygen.c \ - dnssec-signzone.c dnssectool.c + dnssec-revoke.c dnssec-signzone.c dnssectool.c MANPAGES = dnssec-dsfromkey.8 dnssec-keyfromlabel.8 dnssec-keygen.8 \ - dnssec-signzone.8 + dnssec-revoke.8 dnssec-signzone.8 HTMLPAGES = dnssec-dsfromkey.html dnssec-keyfromlabel.html \ - dnssec-keygen.html dnssec-signzone.html + dnssec-keygen.html dnssec-revoke.html dnssec-signzone.html MANOBJS = ${MANPAGES} ${HTMLPAGES} @@ -77,6 +78,10 @@ dnssec-signzone@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS} ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ dnssec-signzone.@O@ ${OBJS} ${LIBS} +dnssec-revoke@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-revoke.@O@ ${OBJS} ${LIBS} + doc man:: ${MANOBJS} docclean manclean maintainer-clean:: diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c index 1ad66d70be..98edcbc880 100644 --- a/bin/dnssec/dnssec-keyfromlabel.c +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keyfromlabel.c,v 1.6 2009/05/07 23:47:44 tbox Exp $ */ +/* $Id: dnssec-keyfromlabel.c,v 1.7 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -64,7 +64,7 @@ usage(void) { fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n"); fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); fprintf(stderr, " -c (default: IN)\n"); - fprintf(stderr, " -f keyflag: KSK\n"); + fprintf(stderr, " -f keyflag (KSK or REVOKE)\n"); fprintf(stderr, " -t : " "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " "(default: AUTHCONF)\n"); @@ -87,7 +87,7 @@ main(int argc, char **argv) { dst_key_t *key = NULL, *oldkey; dns_fixedname_t fname; dns_name_t *name; - isc_uint16_t flags = 0, ksk = 0; + isc_uint16_t flags = 0, ksk = 0, revoke = 0; dns_secalg_t alg; isc_boolean_t null_key = ISC_FALSE; isc_mem_t *mctx = NULL; @@ -125,6 +125,9 @@ main(int argc, char **argv) { case 'f': if (strcasecmp(isc_commandline_argument, "KSK") == 0) ksk = DNS_KEYFLAG_KSK; + else if (strcasecmp(isc_commandline_argument, + "REVOKE") == 0) + revoke = DNS_KEYFLAG_REVOKE; else fatal("unknown flag '%s'", isc_commandline_argument); @@ -238,8 +241,10 @@ main(int argc, char **argv) { if ((options & DST_TYPE_KEY) != 0) /* KEY */ flags |= signatory; - else if ((flags & DNS_KEYOWNER_ZONE) != 0) /* DNSKEY */ + else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ flags |= ksk; + flags |= revoke; + } if (protocol == -1) protocol = DNS_KEYPROTO_DNSSEC; diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index 3f521b2d6d..72108e998b 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-keygen.c,v 1.85 2009/06/17 23:53:04 tbox Exp $ */ +/* $Id: dnssec-keygen.c,v 1.86 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -102,7 +102,7 @@ usage(void) { fprintf(stderr, " -c (default: IN)\n"); fprintf(stderr, " -d (0 => max, default)\n"); fprintf(stderr, " -e use large exponent (RSAMD5/RSASHA1 only)\n"); - fprintf(stderr, " -f keyflag: KSK\n"); + fprintf(stderr, " -f keyflag (KSK or REVOKE)\n"); fprintf(stderr, " -g use specified generator " "(DH only)\n"); fprintf(stderr, " -t : " @@ -130,7 +130,7 @@ main(int argc, char **argv) { dst_key_t *key = NULL, *oldkey; dns_fixedname_t fname; dns_name_t *name; - isc_uint16_t flags = 0, ksk = 0; + isc_uint16_t flags = 0, ksk = 0, revoke = 0; dns_secalg_t alg; isc_boolean_t conflict = ISC_FALSE, null_key = ISC_FALSE; isc_mem_t *mctx = NULL; @@ -182,6 +182,9 @@ main(int argc, char **argv) { case 'f': if (strcasecmp(isc_commandline_argument, "KSK") == 0) ksk = DNS_KEYFLAG_KSK; + else if (strcasecmp(isc_commandline_argument, + "REVOKE") == 0) + revoke = DNS_KEYFLAG_REVOKE; else fatal("unknown flag '%s'", isc_commandline_argument); @@ -423,8 +426,10 @@ main(int argc, char **argv) { if ((options & DST_TYPE_KEY) != 0) /* KEY / HMAC */ flags |= signatory; - else if ((flags & DNS_KEYOWNER_ZONE) != 0) /* DNSKEY */ + else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ flags |= ksk; + flags |= revoke; + } if (protocol == -1) protocol = DNS_KEYPROTO_DNSSEC; diff --git a/bin/dnssec/dnssec-revoke.8 b/bin/dnssec/dnssec-revoke.8 new file mode 100644 index 0000000000..728309f6bc --- /dev/null +++ b/bin/dnssec/dnssec-revoke.8 @@ -0,0 +1,62 @@ +.\" Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +.\" PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $Id: dnssec-revoke.8,v 1.2 2009/06/30 02:52:32 each Exp $ +.\" +.hy 0 +.ad l +.\"Generated by db2man.xsl. Don't modify this, modify the source. +.de Sh \" Subsection +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Ip \" List item +.br +.ie \\n(.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +.TH "DNSSEC-REVOKE" 8 "June 1, 2009" "" "" +.SH NAME +dnssec-revoke \- Set the REVOKED bit on a DNSSEC key +.SH "SYNOPSIS" +.HP 14 +\fBdnssec\-revoke\fR [\fB\-v\ \fIlevel\fR\fR] [\fB\-d\ \fIdirectory\fR\fR] [\fB\-F\fR] {keyfile} +.SH "DESCRIPTION" +.PP +\fBdnssec\-revoke\fR reads a DNSSEC key file, sets the REVOKED bit on the key as defined in RFC 5011, and creates a new pair of key files containing the now\- revoked key\&. +.SH "OPTIONS" +.TP +\-d \fIdirectory\fR +Sets the directory in which the key files are to reside\&. +.TP +\-v \fIlevel\fR +Sets the debugging level\&. +.TP +\-F +Force overwrite: Causes \fBdnssec\-revoke\fR to write the new key pair even if a file already exists matching the algorithm and key ID of the revoked key\&. +.SH "SEE ALSO" +.PP +\fBdnssec\-keygen\fR(8), BIND 9 Administrator Reference Manual, RFC 5011\&. +.SH "AUTHOR" +.PP +Internet Systems Consortium diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c new file mode 100644 index 0000000000..57473b3e7b --- /dev/null +++ b/bin/dnssec/dnssec-revoke.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: dnssec-revoke.c,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "dnssectool.h" + +const char *program = "dnssec-revoke"; +int verbose; + +static isc_mem_t *mctx = NULL; + +static void +usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, " -f: force ovewrite\n"); + fprintf(stderr, " -d directory: use directory for key files\n"); + fprintf(stderr, " -h: help\n"); + fprintf(stderr, " -r: remove old keyfiles after " + "creating revoked version\n"); + fprintf(stderr, " -v level: set level of verbosity\n"); + fprintf(stderr, "Output:\n"); + fprintf(stderr, " K++.key, " + "K++.private\n"); + + exit (-1); +} + +int +main(int argc, char **argv) { + isc_result_t result; + char *filename = NULL, *dir= NULL; + char newname[1024], oldname[1024]; + char keystr[KEY_FORMATSIZE]; + char *endp; + int ch; + isc_entropy_t *ectx = NULL; + dst_key_t *key = NULL; + isc_uint32_t flags; + isc_buffer_t buf; + isc_boolean_t force = ISC_FALSE; + isc_boolean_t remove = ISC_FALSE; + + if (argc == 1) + usage(); + + result = isc_mem_create(0, 0, &mctx); + if (result != ISC_R_SUCCESS) + fatal("Out of memory"); + + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; + + while ((ch = isc_commandline_parse(argc, argv, "d:fhrv:")) != -1) { + switch (ch) { + case 'd': + dir = isc_commandline_argument; + break; + case 'f': + force = ISC_TRUE; + break; + case 'r': + remove = ISC_TRUE; + break; + case 'v': + verbose = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') + fatal("-v must be followed by a number"); + break; + case '?': + if (isc_commandline_option != '?') + fprintf(stderr, "%s: invalid argument -%c\n", + program, isc_commandline_option); + /* Falls into */ + case 'h': + usage(); + + default: + fprintf(stderr, "%s: unhandled option -%c\n", + program, isc_commandline_option); + exit(1); + } + } + + if (argc < isc_commandline_index + 1 || + argv[isc_commandline_index] == NULL) + fatal("The key file name was not specified"); + if (argc > isc_commandline_index + 1) + fatal("Extraneous arguments"); + + if (dir == NULL) + dir = dirname(argv[isc_commandline_index]); + filename = argv[isc_commandline_index]; + + if (ectx == NULL) + setup_entropy(mctx, NULL, &ectx); + result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) + fatal("Could not initialize hash"); + result = dst_lib_init(mctx, ectx, + ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY); + if (result != ISC_R_SUCCESS) + fatal("Could not initialize dst"); + isc_entropy_stopcallbacksources(ectx); + + result = dst_key_fromnamedfile(filename, + DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, + mctx, &key); + if (result != ISC_R_SUCCESS) + fatal("Invalid keyfile name %s: %s", + filename, isc_result_totext(result)); + + if (verbose > 2) { + char keystr[KEY_FORMATSIZE]; + + key_format(key, keystr, sizeof(keystr)); + fprintf(stderr, "%s: %s\n", program, keystr); + } + + flags = dst_key_flags(key); + if ((flags & DNS_KEYFLAG_REVOKE) == 0) { + dst_key_setflags(key, flags | DNS_KEYFLAG_REVOKE); + + isc_buffer_init(&buf, newname, sizeof(newname)); + dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); + + if (access(newname, F_OK) == 0 && !force) { + fatal("Key file %s already exists; " + "use -f to force overwrite", newname); + } + + result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, + dir); + if (result != ISC_R_SUCCESS) { + key_format(key, keystr, sizeof(keystr)); + fatal("Failed to write key %s: %s", keystr, + isc_result_totext(result)); + } + + printf("%s\n", newname); + + isc_buffer_clear(&buf); + dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); + printf("%s\n", newname); + + /* + * Remove old key file, if told to (and if + * it isn't the same as the new file) + */ + if (remove && dst_key_alg(key) != DST_ALG_RSAMD5) { + isc_buffer_init(&buf, oldname, sizeof(oldname)); + dst_key_setflags(key, flags & ~DNS_KEYFLAG_REVOKE); + dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); + if (strcmp(oldname, newname) == 0) + goto cleanup; + if (access(oldname, F_OK) == 0) + unlink(oldname); + isc_buffer_clear(&buf); + dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); + if (access(oldname, F_OK) == 0) + unlink(oldname); + } + } else { + key_format(key, keystr, sizeof(keystr)); + fatal("Key %s is already revoked", keystr); + } + +cleanup: + dst_key_free(&key); + dst_lib_destroy(); + isc_hash_destroy(); + cleanup_entropy(&ectx); + if (verbose > 10) + isc_mem_stats(mctx, stdout); + isc_mem_destroy(&mctx); + + return (0); +} diff --git a/bin/dnssec/dnssec-revoke.docbook b/bin/dnssec/dnssec-revoke.docbook new file mode 100644 index 0000000000..c78ce6b1d3 --- /dev/null +++ b/bin/dnssec/dnssec-revoke.docbook @@ -0,0 +1,138 @@ +]> + + + + + + June 1, 2009 + + + + dnssec-revoke + 8 + BIND9 + + + + dnssec-revoke + Set the REVOKED bit on a DNSSEC key + + + + + 2009 + Internet Systems Consortium, Inc. ("ISC") + + + + + + dnssec-revoke + + + + + keyfile + + + + + DESCRIPTION + dnssec-revoke + reads a DNSSEC key file, sets the REVOKED bit on the key as defined + in RFC 5011, and creates a new pair of key files containing the now- + revoked key. + + + + + OPTIONS + + + + -h + + + Emit usage message and exit. + + + + + + -d directory + + + Sets the directory in which the key files are to reside. + + + + + + -r + + + After writing the new keyset files remove the original keyset + files. + + + + + + -v level + + + Sets the debugging level. + + + + + + -f + + + Force overwrite: Causes dnssec-revoke to + write the new key pair even if a file already exists matching + the algorithm and key ID of the revoked key. + + + + + + + + SEE ALSO + + dnssec-keygen8 + , + BIND 9 Administrator Reference Manual, + RFC 5011. + + + + + AUTHOR + Internet Systems Consortium + + + + diff --git a/bin/dnssec/dnssec-revoke.html b/bin/dnssec/dnssec-revoke.html new file mode 100644 index 0000000000..4352ebb9e6 --- /dev/null +++ b/bin/dnssec/dnssec-revoke.html @@ -0,0 +1,73 @@ + + + + + +dnssec-revoke + + +
+
+
+

Name

+

dnssec-revoke — Set the REVOKED bit on a DNSSEC key

+
+
+

Synopsis

+

dnssec-revoke [-v level] [-d directory] [-F] {keyfile}

+
+
+

DESCRIPTION

+

dnssec-revoke + reads a DNSSEC key file, sets the REVOKED bit on the key as defined + in RFC 5011, and creates a new pair of key files containing the now- + revoked key. +

+
+
+

OPTIONS

+
+
-d directory
+

+ Sets the directory in which the key files are to reside. +

+
-v level
+

+ Sets the debugging level. +

+
-F
+

+ Force overwrite: Causes dnssec-revoke to + write the new key pair even if a file already exists matching + the algorithm and key ID of the revoked key. +

+
+
+
+

SEE ALSO

+

dnssec-keygen(8), + BIND 9 Administrator Reference Manual, + RFC 5011. +

+
+
+

AUTHOR

+

Internet Systems Consortium +

+
+
+ diff --git a/bin/dnssec/win32/revoke.dsp b/bin/dnssec/win32/revoke.dsp new file mode 100644 index 0000000000..ce3b00cec8 --- /dev/null +++ b/bin/dnssec/win32/revoke.dsp @@ -0,0 +1,103 @@ +# Microsoft Developer Studio Project File - Name="revoke" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=revoke - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "revoke.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "revoke.mak" CFG="revoke - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "revoke - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "revoke - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "revoke - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/dns/include" /D "NDEBUG" /D "__STDC__" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 user32.lib advapi32.lib Release/dnssectool.lib ../../../lib/isc/win32/Release/libisc.lib ../../../lib/dns/win32/Release/libdns.lib /nologo /subsystem:console /machine:I386 /out:"../../../Build/Release/dnssec-revoke.exe" + +!ELSEIF "$(CFG)" == "revoke - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/dns/include" /D "_DEBUG" /D "WIN32" /D "__STDC__" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c +# SUBTRACT CPP /X /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 user32.lib advapi32.lib Debug/dnssectool.lib ../../../lib/isc/win32/Debug/libisc.lib ../../../lib/dns/win32/Debug/libdns.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../Build/Debug/dnssec-revoke.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "revoke - Win32 Release" +# Name "revoke - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\dnssec-revoke.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/bin/dnssec/win32/revoke.dsw b/bin/dnssec/win32/revoke.dsw new file mode 100644 index 0000000000..f588e21df5 --- /dev/null +++ b/bin/dnssec/win32/revoke.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "revoke"=".\revoke.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/bin/dnssec/win32/revoke.mak b/bin/dnssec/win32/revoke.mak new file mode 100644 index 0000000000..f8bcae0b49 --- /dev/null +++ b/bin/dnssec/win32/revoke.mak @@ -0,0 +1,324 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on revoke.dsp +!IF "$(CFG)" == "" +CFG=revoke - Win32 Debug +!MESSAGE No configuration specified. Defaulting to revoke - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "revoke - Win32 Release" && "$(CFG)" != "revoke - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "revoke.mak" CFG="revoke - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "revoke - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "revoke - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "revoke - Win32 Release" +_VC_MANIFEST_INC=0 +_VC_MANIFEST_BASENAME=__VC80 +!ELSE +_VC_MANIFEST_INC=1 +_VC_MANIFEST_BASENAME=__VC80.Debug +!ENDIF + +#################################################### +# Specifying name of temporary resource file used only in incremental builds: + +!if "$(_VC_MANIFEST_INC)" == "1" +_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res +!else +_VC_MANIFEST_AUTO_RES= +!endif + +#################################################### +# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE: + +!if "$(_VC_MANIFEST_INC)" == "1" + +#MT_SPECIAL_RETURN=1090650113 +#MT_SPECIAL_SWITCH=-notify_resource_update +MT_SPECIAL_RETURN=0 +MT_SPECIAL_SWITCH= +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \ +if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \ +rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \ +link $** /out:$@ $(LFLAGS) + +!else + +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1 + +!endif + +#################################################### +# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL: + +!if "$(_VC_MANIFEST_INC)" == "1" + +#MT_SPECIAL_RETURN=1090650113 +#MT_SPECIAL_SWITCH=-notify_resource_update +MT_SPECIAL_RETURN=0 +MT_SPECIAL_SWITCH= +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \ +if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \ +rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \ +link $** /out:$@ $(LFLAGS) + +!else + +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2 + +!endif +#################################################### +# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily: + +!if "$(_VC_MANIFEST_INC)" == "1" + +_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \ + $(_VC_MANIFEST_BASENAME).auto.rc \ + $(_VC_MANIFEST_BASENAME).auto.manifest + +!else + +_VC_MANIFEST_CLEAN= + +!endif + +!IF "$(CFG)" == "revoke - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "..\..\..\Build\Release\dnssec-revoke.exe" + + +CLEAN : + -@erase "$(INTDIR)\dnssec-revoke.obj" + -@erase "$(INTDIR)\dnssectool.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "..\..\..\Build\Release\dnssec-revoke.exe" + -@$(_VC_MANIFEST_CLEAN) + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "./" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/dns/include" /D "NDEBUG" /D "__STDC__" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\revoke.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\revoke.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=user32.lib advapi32.lib ../../../lib/isc/win32/Release/libisc.lib ../../../lib/dns/win32/Release/libdns.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\dnssec-revoke.pdb" /machine:I386 /out:"../../../Build/Release/dnssec-revoke.exe" +LINK32_OBJS= \ + "$(INTDIR)\dnssec-revoke.obj" \ + "$(INTDIR)\dnssectool.obj" + +"..\..\..\Build\Release\dnssec-revoke.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + $(_VC_MANIFEST_EMBED_EXE) + +!ELSEIF "$(CFG)" == "revoke - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "..\..\..\Build\Debug\dnssec-revoke.exe" "$(OUTDIR)\revoke.bsc" + + +CLEAN : + -@erase "$(INTDIR)\dnssec-revoke.obj" + -@erase "$(INTDIR)\dnssec-revoke.sbr" + -@erase "$(INTDIR)\dnssectool.obj" + -@erase "$(INTDIR)\dnssectool.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\dnssec-revoke.pdb" + -@erase "$(OUTDIR)\revoke.bsc" + -@erase "..\..\..\Build\Debug\dnssec-revoke.exe" + -@erase "..\..\..\Build\Debug\dnssec-revoke.ilk" + -@$(_VC_MANIFEST_CLEAN) + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/dns/include" /D "_DEBUG" /D "WIN32" /D "__STDC__" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\revoke.bsc" +BSC32_SBRS= \ + "$(INTDIR)\dnssec-revoke.sbr" \ + "$(INTDIR)\dnssectool.sbr" + +"$(OUTDIR)\revoke.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=user32.lib advapi32.lib ../../../lib/isc/win32/Debug/libisc.lib ../../../lib/dns/win32/Debug/libdns.lib /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\dnssec-revoke.pdb" /debug /machine:I386 /out:"../../../Build/Debug/dnssec-revoke.exe" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\dnssec-revoke.obj" \ + "$(INTDIR)\dnssectool.obj" + +"..\..\..\Build\Debug\dnssec-revoke.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + $(_VC_MANIFEST_EMBED_EXE) + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("revoke.dep") +!INCLUDE "revoke.dep" +!ELSE +!MESSAGE Warning: cannot find "revoke.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "revoke - Win32 Release" || "$(CFG)" == "revoke - Win32 Debug" +SOURCE="..\dnssec-revoke.c" + +!IF "$(CFG)" == "revoke - Win32 Release" + + +"$(INTDIR)\dnssec-revoke.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "revoke - Win32 Debug" + + +"$(INTDIR)\dnssec-revoke.obj" "$(INTDIR)\dnssec-revoke.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\dnssectool.c + +!IF "$(CFG)" == "revoke - Win32 Release" + + +"$(INTDIR)\dnssectool.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "revoke - Win32 Debug" + + +"$(INTDIR)\dnssectool.obj" "$(INTDIR)\dnssectool.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + + +!ENDIF + +#################################################### +# Commands to generate initial empty manifest file and the RC file +# that references it, and for generating the .res file: + +$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc + +$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest + type <<$@ +#include +1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest" +<< KEEP + +$(_VC_MANIFEST_BASENAME).auto.manifest : + type <<$@ + + + +<< KEEP diff --git a/bin/named/config.c b/bin/named/config.c index db650a85bd..9834c19935 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.c,v 1.97 2009/06/10 00:27:21 each Exp $ */ +/* $Id: config.c,v 1.98 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -225,6 +225,7 @@ view \"_bind\" chaos {\n\ type master;\n\ database \"_builtin authors\";\n\ };\n\ +\n\ zone \"id.server\" chaos {\n\ type master;\n\ database \"_builtin id\";\n\ @@ -232,6 +233,17 @@ view \"_bind\" chaos {\n\ };\n\ " +"#\n\ +# The \"_meta\" view is for zones that are used to store internal\n\ +# information for named, such as managed keys. The zones are defined\n\ +# elsewhere.\n\ +#\n\ +view \"_meta\" in {\n\ + recursion no;\n\ + notify no;\n\ +};\n\ +" + "#\n\ # Default trusted key(s) for builtin DLV support\n\ # (used if \"dnssec-lookaside auto;\" is set and\n\ diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 9a25a15f83..b076cbaa3f 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.98 2009/06/10 00:27:21 each Exp $ */ +/* $Id: server.h,v 1.99 2009/06/30 02:52:32 each Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -55,6 +55,8 @@ struct ns_server { char * statsfile; /*%< Statistics file name */ char * dumpfile; /*%< Dump file name */ char * bindkeysfile; /*%< bind.keys file name */ + isc_boolean_t managedkeys; /*%< A managed-keys + statement exists */ char * recfile; /*%< Recursive file name */ isc_boolean_t version_set; /*%< User has set version */ char * version; /*%< User-specified version */ diff --git a/bin/named/server.c b/bin/named/server.c index 4c92d7d2c1..01419d4d87 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.534 2009/06/10 23:47:47 tbox Exp $ */ +/* $Id: server.c,v 1.535 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -270,6 +270,9 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, cfg_aclconfctx_t *aclconf); +static isc_result_t +add_keydata_zone(dns_view_t *view, isc_mem_t *mctx); + static void end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); @@ -439,8 +442,8 @@ configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config, } static isc_result_t -configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, - dns_keytable_t *keytable, isc_mem_t *mctx) +dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key, + isc_boolean_t managed, dst_key_t **target, isc_mem_t *mctx) { dns_rdataclass_t viewclass; dns_rdata_dnskey_t keystruct; @@ -457,6 +460,8 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, isc_result_t result; dst_key_t *dstkey = NULL; + INSIST(target != NULL && *target == NULL); + flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); @@ -502,7 +507,8 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, keystruct.algorithm == DST_ALG_RSAMD5) && r.length > 1 && r.base[0] == 1 && r.base[1] == 3) cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, - "trusted key '%s' has a weak exponent", + "%s key '%s' has a weak exponent", + managed ? "managed" : "trusted", keynamestr); CHECK(dns_rdata_fromstruct(NULL, @@ -518,19 +524,20 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, mctx, &dstkey)); - CHECK(dns_keytable_add(keytable, &dstkey)); - INSIST(dstkey == NULL); + *target = dstkey; return (ISC_R_SUCCESS); cleanup: if (result == DST_R_NOCRYPTO) { cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, - "ignoring trusted key for '%s': no crypto support", + "ignoring %s key for '%s': no crypto support", + managed ? "managed" : "trusted", keynamestr); result = ISC_R_SUCCESS; } else { cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, - "configuring trusted key for '%s': %s", + "configuring %s key for '%s': %s", + managed ? "managed" : "trusted", keynamestr, isc_result_totext(result)); result = ISC_R_FAILURE; } @@ -541,15 +548,14 @@ configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, return (result); } - -static void -configure_view_dnsseckeylist(const cfg_obj_t *keys, const cfg_obj_t *vconfig, - dns_keytable_t *keytable, isc_mem_t *mctx) +static isc_result_t +load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig, + dns_view_t *view, isc_boolean_t managed, isc_mem_t *mctx) { const cfg_listelt_t *elt, *elt2; - const cfg_obj_t *key; - const cfg_obj_t *keylist; - isc_result_t result; + const cfg_obj_t *key, *keylist; + dst_key_t *dstkey = NULL; + isc_result_t result = ISC_R_SUCCESS; for (elt = cfg_list_first(keys); elt != NULL; @@ -560,49 +566,57 @@ configure_view_dnsseckeylist(const cfg_obj_t *keys, const cfg_obj_t *vconfig, elt2 != NULL; elt2 = cfg_list_next(elt2)) { key = cfg_listelt_value(elt2); - CHECK(configure_view_dnsseckey(vconfig, key, - keytable, mctx)); + CHECK(dstkey_fromconfig(vconfig, key, managed, + &dstkey, mctx)); + CHECK(dns_keytable_add(view->secroots, managed, + &dstkey)); } } cleanup: - return; + return (result); } /*% - * Configure DNSSEC keys for a view. Currently used only for the security - * roots. + * Configure DNSSEC keys for a view. * * The per-view configuration values and the server-global defaults are read - * from 'vconfig' and 'config'. The variable to be configured is '*target'. + * from 'vconfig' and 'config'. */ static isc_result_t -configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, - const cfg_obj_t *bindkeys, isc_boolean_t auto_dlv, - isc_mem_t *mctx, dns_keytable_t **target) +configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig, + const cfg_obj_t *config, const cfg_obj_t *bindkeys, + isc_boolean_t auto_dlv, isc_mem_t *mctx) { + isc_result_t result = ISC_R_SUCCESS; const cfg_obj_t *view_keys = NULL; const cfg_obj_t *global_keys = NULL; + const cfg_obj_t *global_managed_keys = NULL; const cfg_obj_t *builtin_keys = NULL; + const cfg_obj_t *builtin_managed_keys = NULL; const cfg_obj_t *maps[4]; const cfg_obj_t *voptions = NULL; const cfg_obj_t *options = NULL; - dns_keytable_t *keytable = NULL; - isc_result_t result; int i = 0; - CHECK(dns_keytable_create(mctx, &keytable)); + /* We don't need trust anchors for the _bind view */ + if (strcmp(view->name, "_bind") == 0) { + view->secroots = NULL; + return (ISC_R_SUCCESS); + } if (vconfig != NULL) { voptions = cfg_tuple_get(vconfig, "options"); if (voptions != NULL) { - (void)cfg_map_get(voptions, "trusted-keys", &view_keys); + (void) cfg_map_get(voptions, "trusted-keys", + &view_keys); maps[i++] = voptions; } } if (config != NULL) { (void)cfg_map_get(config, "trusted-keys", &global_keys); + (void)cfg_map_get(config, "managed-keys", &global_managed_keys); (void)cfg_map_get(config, "options", &options); if (options != NULL) { maps[i++] = options; @@ -612,35 +626,60 @@ configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, maps[i++] = ns_g_defaults; maps[i] = NULL; + if (view->secroots != NULL) + dns_keytable_detach(&view->secroots); + result = dns_keytable_create(mctx, &view->secroots); + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_ERROR, + "couldn't create keytable"); + return (ISC_R_UNEXPECTED); + } + + if (global_managed_keys != NULL) + ns_g_server->managedkeys = ISC_TRUE; + if (auto_dlv) { isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, - "using built-in trusted-keys"); + "using built-in trusted-keys for view %s", + view->name); /* - * If bind.keys exists, it overrides the trusted-keys + * If bind.keys exists, it overrides the managed-keys * clause hard-coded in ns_g_config. */ - if (bindkeys != NULL) + if (bindkeys != NULL) { (void)cfg_map_get(bindkeys, "trusted-keys", &builtin_keys); - else + (void)cfg_map_get(bindkeys, "managed-keys", + &builtin_managed_keys); + } else { (void)cfg_map_get(ns_g_config, "trusted-keys", &builtin_keys); + (void)cfg_map_get(ns_g_config, "managed-keys", + &builtin_managed_keys); + } - configure_view_dnsseckeylist(builtin_keys, vconfig, - keytable, mctx); + if (builtin_managed_keys != NULL) + ns_g_server->managedkeys = ISC_TRUE; + CHECK(load_view_keys(builtin_keys, vconfig, view, + ISC_FALSE, mctx)); + + if (strcmp(view->name, "_meta") == 0) + CHECK(load_view_keys(builtin_managed_keys, vconfig, + view, ISC_TRUE, mctx)); } - configure_view_dnsseckeylist(global_keys, vconfig, keytable, mctx); - configure_view_dnsseckeylist(view_keys, vconfig, keytable, mctx); + CHECK(load_view_keys(view_keys, vconfig, view, ISC_FALSE, mctx)); + CHECK(load_view_keys(global_keys, vconfig, view, ISC_FALSE, mctx)); - dns_keytable_detach(target); - *target = keytable; /* Transfer ownership. */ - keytable = NULL; + if (strcmp(view->name, "_meta") == 0) + CHECK(load_view_keys(global_managed_keys, vconfig, view, + ISC_TRUE, mctx)); - cleanup: - return (ISC_R_SUCCESS); + cleanup: + return (result); } static isc_result_t @@ -2082,8 +2121,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, * For now, there is only one kind of trusted keys, the * "security roots". */ - CHECK(configure_view_dnsseckeys(vconfig, config, bindkeys, auto_dlv, - mctx, &view->secroots)); + CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys, + auto_dlv, mctx)); dns_resolver_resetmustbesecure(view->resolver); obj = NULL; result = ns_config_get(maps, "dnssec-must-be-secure", &obj); @@ -2823,6 +2862,73 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, return (result); } +/* + * Configure built-in zone for storing managed-key data. + */ + +#define KEYZONE "managed-keys.bind" + +static isc_result_t +add_keydata_zone(dns_view_t *view, isc_mem_t *mctx) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_acl_t *none = NULL; + dns_name_t zname; + + if (!ns_g_server->managedkeys) + return (ISC_R_SUCCESS); + + REQUIRE(view != NULL); + + CHECK(dns_zone_create(&zone, mctx)); + + dns_name_init(&zname, NULL); + CHECK(dns_name_fromstring(&zname, KEYZONE, mctx)); + CHECK(dns_zone_setorigin(zone, &zname)); + dns_name_free(&zname, mctx); + + CHECK(dns_zone_setfile(zone, KEYZONE)); + + if (view->hints == NULL) + dns_view_sethints(view, ns_g_server->in_roothints); + + dns_zone_setview(zone, view); + dns_zone_settype(zone, dns_zone_key); + dns_zone_setclass(zone, view->rdclass); + + CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + + if (view->acache != NULL) + dns_zone_setacache(zone, view->acache); + + CHECK(dns_acl_none(mctx, &none)); + dns_zone_setqueryacl(zone, none); + dns_zone_setqueryonacl(zone, none); + dns_acl_detach(&none); + + dns_zone_setdialup(zone, dns_dialuptype_no); + dns_zone_setnotifytype(zone, dns_notifytype_no); + dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); + dns_zone_setjournalsize(zone, 0); + + dns_zone_setstats(zone, ns_g_server->zonestats); + CHECK(setquerystats(zone, mctx, ISC_FALSE)); + + CHECK(dns_view_addzone(view, zone)); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "set up %s meta-zone", KEYZONE); + +cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + if (none != NULL) + dns_acl_detach(&none); + + return (result); +} + /* * Configure a single server quota. */ @@ -3442,7 +3548,7 @@ load_configuration(const char *filename, ns_server_t *server, dns_view_t *view = NULL; dns_view_t *view_next; dns_viewlist_t tmpviewlist; - dns_viewlist_t viewlist; + dns_viewlist_t viewlist, builtin_viewlist; in_port_t listen_port, udpport_low, udpport_high; int i; isc_interval_t interval; @@ -3460,6 +3566,7 @@ load_configuration(const char *filename, ns_server_t *server, cfg_aclconfctx_init(&aclconfctx); ISC_LIST_INIT(viewlist); + ISC_LIST_INIT(builtin_viewlist); ISC_LIST_INIT(cachelist); /* Ensure exclusive access to configuration data. */ @@ -3908,7 +4015,7 @@ load_configuration(const char *filename, ns_server_t *server, /* * Create (or recreate) the built-in views. Currently - * there is only one, the _bind view. + * there is only one, the _bind view, but allow for others. */ builtin_views = NULL; RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", @@ -3918,32 +4025,43 @@ load_configuration(const char *filename, ns_server_t *server, element = cfg_list_next(element)) { const cfg_obj_t *vconfig = cfg_listelt_value(element); - CHECK(create_view(vconfig, &viewlist, &view)); + + CHECK(create_view(vconfig, &builtin_viewlist, &view)); CHECK(configure_view(view, config, vconfig, &cachelist, bindkeys, ns_g_mctx, &aclconfctx, ISC_FALSE)); + + if (!strcmp(view->name, "_meta")) { + result = add_keydata_zone(view, ns_g_mctx); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } + dns_view_freeze(view); dns_view_detach(&view); view = NULL; } - /* - * Swap our new view list with the production one. - */ + /* Now combine the two viewlists into one */ + ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link); + + /* Swap our new view list with the production one. */ tmpviewlist = server->viewlist; server->viewlist = viewlist; viewlist = tmpviewlist; - /* - * Swap our new cache list with the production one. - */ + /* Make the view list available to each of the views */ + view = ISC_LIST_HEAD(server->viewlist); + while (view != NULL) { + view->viewlist = &server->viewlist; + view = ISC_LIST_NEXT(view, link); + } + + /* Swap our new cache list with the production one. */ tmpcachelist = server->cachelist; server->cachelist = cachelist; cachelist = tmpcachelist; - /* - * Load the TKEY information from the configuration. - */ + /* Load the TKEY information from the configuration. */ if (options != NULL) { dns_tkeyctx_t *t = NULL; CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, @@ -4552,6 +4670,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { ISC_R_SUCCESS, "isc_mem_strdup"); + server->managedkeys = ISC_FALSE; + server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, "isc_mem_strdup"); @@ -6161,8 +6281,9 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { dns_zone_setupdatedisabled(zone, freeze); view = dns_zone_getview(zone); - if (strcmp(view->name, "_bind") == 0 || - strcmp(view->name, "_default") == 0) + if (strcmp(view->name, "_default") == 0 || + strcmp(view->name, "_bind") == 0 || + strcmp(view->name, "_meta")) { vname = ""; sep = ""; diff --git a/bin/named/xfrout.c b/bin/named/xfrout.c index 6236dfa4cc..4cd88ab82c 100644 --- a/bin/named/xfrout.c +++ b/bin/named/xfrout.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrout.c,v 1.135 2009/01/27 22:29:58 jinmei Exp $ */ +/* $Id: xfrout.c,v 1.136 2009/06/30 02:52:32 each Exp $ */ #include @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -112,43 +113,6 @@ } while (0) /**************************************************************************/ -/*% - * A db_rr_iterator_t is an iterator that iterates over an entire database, - * returning one RR at a time, in some arbitrary order. - */ - -typedef struct db_rr_iterator db_rr_iterator_t; - -/*% db_rr_iterator structure */ -struct db_rr_iterator { - isc_result_t result; - dns_db_t *db; - dns_dbiterator_t *dbit; - dns_dbversion_t *ver; - isc_stdtime_t now; - dns_dbnode_t *node; - dns_fixedname_t fixedname; - dns_rdatasetiter_t *rdatasetit; - dns_rdataset_t rdataset; - dns_rdata_t rdata; -}; - -static isc_result_t -db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, - isc_stdtime_t now); - -static isc_result_t -db_rr_iterator_first(db_rr_iterator_t *it); - -static isc_result_t -db_rr_iterator_next(db_rr_iterator_t *it); - -static void -db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, - isc_uint32_t *ttl, dns_rdata_t **rdata); - -static void -db_rr_iterator_destroy(db_rr_iterator_t *it); static inline void inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { @@ -160,145 +124,6 @@ inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { } } -static isc_result_t -db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, - isc_stdtime_t now) -{ - isc_result_t result; - it->db = db; - it->dbit = NULL; - it->ver = ver; - it->now = now; - it->node = NULL; - result = dns_db_createiterator(it->db, 0, &it->dbit); - if (result != ISC_R_SUCCESS) - return (result); - it->rdatasetit = NULL; - dns_rdata_init(&it->rdata); - dns_rdataset_init(&it->rdataset); - dns_fixedname_init(&it->fixedname); - INSIST(! dns_rdataset_isassociated(&it->rdataset)); - it->result = ISC_R_SUCCESS; - return (it->result); -} - -static isc_result_t -db_rr_iterator_first(db_rr_iterator_t *it) { - it->result = dns_dbiterator_first(it->dbit); - /* - * The top node may be empty when out of zone glue exists. - * Walk the tree to find the first node with data. - */ - while (it->result == ISC_R_SUCCESS) { - it->result = dns_dbiterator_current(it->dbit, &it->node, - dns_fixedname_name(&it->fixedname)); - if (it->result != ISC_R_SUCCESS) - return (it->result); - - it->result = dns_db_allrdatasets(it->db, it->node, - it->ver, it->now, - &it->rdatasetit); - if (it->result != ISC_R_SUCCESS) - return (it->result); - - it->result = dns_rdatasetiter_first(it->rdatasetit); - if (it->result != ISC_R_SUCCESS) { - /* - * This node is empty. Try next node. - */ - dns_rdatasetiter_destroy(&it->rdatasetit); - dns_db_detachnode(it->db, &it->node); - it->result = dns_dbiterator_next(it->dbit); - continue; - } - dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); - it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; - it->result = dns_rdataset_first(&it->rdataset); - return (it->result); - } - return (it->result); -} - - -static isc_result_t -db_rr_iterator_next(db_rr_iterator_t *it) { - if (it->result != ISC_R_SUCCESS) - return (it->result); - - INSIST(it->dbit != NULL); - INSIST(it->node != NULL); - INSIST(it->rdatasetit != NULL); - - it->result = dns_rdataset_next(&it->rdataset); - if (it->result == ISC_R_NOMORE) { - dns_rdataset_disassociate(&it->rdataset); - it->result = dns_rdatasetiter_next(it->rdatasetit); - /* - * The while loop body is executed more than once - * only when an empty dbnode needs to be skipped. - */ - while (it->result == ISC_R_NOMORE) { - dns_rdatasetiter_destroy(&it->rdatasetit); - dns_db_detachnode(it->db, &it->node); - it->result = dns_dbiterator_next(it->dbit); - if (it->result == ISC_R_NOMORE) { - /* We are at the end of the entire database. */ - return (it->result); - } - if (it->result != ISC_R_SUCCESS) - return (it->result); - it->result = dns_dbiterator_current(it->dbit, - &it->node, - dns_fixedname_name(&it->fixedname)); - if (it->result != ISC_R_SUCCESS) - return (it->result); - it->result = dns_db_allrdatasets(it->db, it->node, - it->ver, it->now, - &it->rdatasetit); - if (it->result != ISC_R_SUCCESS) - return (it->result); - it->result = dns_rdatasetiter_first(it->rdatasetit); - } - if (it->result != ISC_R_SUCCESS) - return (it->result); - dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); - it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; - it->result = dns_rdataset_first(&it->rdataset); - if (it->result != ISC_R_SUCCESS) - return (it->result); - } - return (it->result); -} - -static void -db_rr_iterator_pause(db_rr_iterator_t *it) { - RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS); -} - -static void -db_rr_iterator_destroy(db_rr_iterator_t *it) { - if (dns_rdataset_isassociated(&it->rdataset)) - dns_rdataset_disassociate(&it->rdataset); - if (it->rdatasetit != NULL) - dns_rdatasetiter_destroy(&it->rdatasetit); - if (it->node != NULL) - dns_db_detachnode(it->db, &it->node); - dns_dbiterator_destroy(&it->dbit); -} - -static void -db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, - isc_uint32_t *ttl, dns_rdata_t **rdata) -{ - REQUIRE(name != NULL && *name == NULL); - REQUIRE(it->result == ISC_R_SUCCESS); - *name = dns_fixedname_name(&it->fixedname); - *ttl = it->rdataset.ttl; - dns_rdata_reset(&it->rdata); - dns_rdataset_current(&it->rdataset, &it->rdata); - *rdata = &it->rdata; -} - /**************************************************************************/ /*% Log an RR (for debugging) */ @@ -488,7 +313,7 @@ static rrstream_methods_t ixfr_rrstream_methods = { typedef struct axfr_rrstream { rrstream_t common; - db_rr_iterator_t it; + dns_rriterator_t it; isc_boolean_t it_valid; } axfr_rrstream_t; @@ -516,7 +341,7 @@ axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, s->common.methods = &axfr_rrstream_methods; s->it_valid = ISC_FALSE; - CHECK(db_rr_iterator_init(&s->it, db, ver, 0)); + CHECK(dns_rriterator_init(&s->it, db, ver, 0)); s->it_valid = ISC_TRUE; *sp = (rrstream_t *) s; @@ -531,7 +356,7 @@ static isc_result_t axfr_rrstream_first(rrstream_t *rs) { axfr_rrstream_t *s = (axfr_rrstream_t *) rs; isc_result_t result; - result = db_rr_iterator_first(&s->it); + result = dns_rriterator_first(&s->it); if (result != ISC_R_SUCCESS) return (result); /* Skip SOA records. */ @@ -539,11 +364,11 @@ axfr_rrstream_first(rrstream_t *rs) { dns_name_t *name_dummy = NULL; isc_uint32_t ttl_dummy; dns_rdata_t *rdata = NULL; - db_rr_iterator_current(&s->it, &name_dummy, - &ttl_dummy, &rdata); + dns_rriterator_current(&s->it, &name_dummy, + &ttl_dummy, NULL, &rdata); if (rdata->type != dns_rdatatype_soa) break; - result = db_rr_iterator_next(&s->it); + result = dns_rriterator_next(&s->it); if (result != ISC_R_SUCCESS) break; } @@ -560,11 +385,11 @@ axfr_rrstream_next(rrstream_t *rs) { dns_name_t *name_dummy = NULL; isc_uint32_t ttl_dummy; dns_rdata_t *rdata = NULL; - result = db_rr_iterator_next(&s->it); + result = dns_rriterator_next(&s->it); if (result != ISC_R_SUCCESS) break; - db_rr_iterator_current(&s->it, &name_dummy, - &ttl_dummy, &rdata); + dns_rriterator_current(&s->it, &name_dummy, + &ttl_dummy, NULL, &rdata); if (rdata->type != dns_rdatatype_soa) break; } @@ -576,20 +401,20 @@ axfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, dns_rdata_t **rdata) { axfr_rrstream_t *s = (axfr_rrstream_t *) rs; - db_rr_iterator_current(&s->it, name, ttl, rdata); + dns_rriterator_current(&s->it, name, ttl, NULL, rdata); } static void axfr_rrstream_pause(rrstream_t *rs) { axfr_rrstream_t *s = (axfr_rrstream_t *) rs; - db_rr_iterator_pause(&s->it); + dns_rriterator_pause(&s->it); } static void axfr_rrstream_destroy(rrstream_t **rsp) { axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; if (s->it_valid) - db_rr_iterator_destroy(&s->it); + dns_rriterator_destroy(&s->it); isc_mem_put(s->common.mctx, s, sizeof(*s)); } diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index ef5c12a5d0..b8164657ed 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.163 2008/09/24 02:46:22 marka Exp $ +# $Id: Makefile.in,v 1.164 2009/06/30 02:52:32 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -58,14 +58,15 @@ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ cache.@O@ callbacks.@O@ compress.@O@ \ db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \ dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ journal.@O@ \ - keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \ + keydata.@O@ keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \ master.@O@ masterdump.@O@ message.@O@ \ - name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ portlist.@O@ \ + name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ \ + portlist.@O@ \ rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \ rdatalist.@O@ \ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \ - resolver.@O@ result.@O@ rootns.@O@ sdb.@O@ sdlz.@O@ \ - soa.@O@ ssu.@O@ \ + resolver.@O@ result.@O@ rootns.@O@ rriterator.@O@ sdb.@O@ \ + sdlz.@O@ soa.@O@ ssu.@O@ \ stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \ tsig.@O@ ttl.@O@ validator.@O@ \ version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@ @@ -84,13 +85,13 @@ DNSSRCS = acache.c acl.c adb.c byaddr.c \ cache.c callbacks.c compress.c \ db.c dbiterator.c dbtable.c diff.c dispatch.c \ dlz.c dnssec.c ds.c forward.c iptable.c journal.c \ - keytable.c lib.c log.c lookup.c \ + keydata.c keytable.c lib.c log.c lookup.c \ master.c masterdump.c message.c \ name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \ rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \ rdatalist.c \ rdataset.c rdatasetiter.c rdataslab.c request.c \ - resolver.c result.c rootns.c sdb.c sdlz.c \ + resolver.c result.c rootns.c rriterator.c sdb.c sdlz.c \ soa.c ssu.c \ stats.c tcpmsg.c time.c timer.c tkey.c \ tsig.c ttl.c validator.c \ diff --git a/lib/dns/db.c b/lib/dns/db.c index 83430c0bf7..58726b8eed 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.c,v 1.90 2009/04/29 23:48:02 tbox Exp $ */ +/* $Id: db.c,v 1.91 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -34,10 +34,12 @@ #include #include +#include #include #include #include #include +#include #include /*** @@ -926,3 +928,4 @@ dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version if (db->methods->resigned != NULL) (db->methods->resigned)(db, rdataset, version); } + diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 4fccc21605..aef4751533 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_api.c,v 1.20 2009/06/10 00:27:22 each Exp $ + * $Id: dst_api.c,v 1.21 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -1062,6 +1062,16 @@ dst_key_read_public(const char *filename, int type, return (ret); } +/*% + * Set the flags on a key, then recompute the key ID + */ +isc_result_t +dst_key_setflags(dst_key_t *key, isc_uint32_t flags) { + REQUIRE(VALID_KEY(key)); + key->key_flags = flags; + return (computeid(key)); +} + static isc_boolean_t issymmetric(const dst_key_t *key) { REQUIRE(dst_initialized == ISC_TRUE); diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index f531ad0650..7ff8d0d984 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_internal.h,v 1.13 2009/06/11 23:47:55 tbox Exp $ */ +/* $Id: dst_internal.h,v 1.14 2009/06/30 02:52:32 each Exp $ */ #ifndef DST_DST_INTERNAL_H #define DST_DST_INTERNAL_H 1 @@ -112,7 +112,7 @@ struct dst_key { dst_hmacsha512_key_t *hmacsha512; } keydata; /*%< pointer to key in crypto pkg fmt */ - dst_func_t * func; /*%< crypto package specific functions */ + dst_func_t * func; /*%< crypto package specific functions*/ }; struct dst_context { diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index e4e89efe1c..db396bed7b 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.h,v 1.97 2009/05/07 09:41:23 fdupont Exp $ */ +/* $Id: db.h,v 1.98 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_DB_H #define DNS_DB_H 1 @@ -59,7 +59,10 @@ #include #include +#include #include +#include +#include #include ISC_LANG_BEGINDECLS @@ -613,7 +616,7 @@ dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, * * Note: if '*versionp' is a read-write version and 'commit' is ISC_TRUE, * then all changes made in the version will take effect, otherwise they - * will be rolled back. The value if 'commit' is ignored for read-only + * will be rolled back. The value of 'commit' is ignored for read-only * versions. * * Requires: diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index 18659e27f9..ec4aee0185 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: events.h,v 1.51 2009/05/06 23:47:50 tbox Exp $ */ +/* $Id: events.h,v 1.52 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_EVENTS_H #define DNS_EVENTS_H 1 @@ -69,6 +69,7 @@ #define DNS_EVENT_ACACHECLEAN (ISC_EVENTCLASS_DNS + 39) #define DNS_EVENT_ACACHEOVERMEM (ISC_EVENTCLASS_DNS + 40) #define DNS_EVENT_RBTPRUNE (ISC_EVENTCLASS_DNS + 41) +#define DNS_EVENT_MANAGEKEYS (ISC_EVENTCLASS_DNS + 42) #define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) #define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) diff --git a/lib/dns/include/dns/keydata.h b/lib/dns/include/dns/keydata.h new file mode 100644 index 0000000000..f24ca06e7c --- /dev/null +++ b/lib/dns/include/dns/keydata.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: keydata.h,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +#ifndef DNS_KEYDATA_H +#define DNS_KEYDATA_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file dns/keydata.h + * \brief + * KEYDATA utilities. + */ + +/*** + *** Imports + ***/ + +#include +#include + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_keydata_todnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx); + +isc_result_t +dns_keydata_fromdnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, + isc_uint32_t refresh, isc_uint32_t addhd, + isc_uint32_t removehd, isc_mem_t *mctx); + +ISC_LANG_ENDDECLS + +#endif /* DNS_KEYDATA_H */ diff --git a/lib/dns/include/dns/keytable.h b/lib/dns/include/dns/keytable.h index 553aa990b6..2212fd08a3 100644 --- a/lib/dns/include/dns/keytable.h +++ b/lib/dns/include/dns/keytable.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keytable.h,v 1.16 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: keytable.h,v 1.17 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_KEYTABLE_H #define DNS_KEYTABLE_H 1 @@ -42,6 +42,10 @@ */ #include +#include +#include +#include +#include #include @@ -49,6 +53,33 @@ ISC_LANG_BEGINDECLS +struct dns_keytable { + /* Unlocked. */ + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_rwlock_t rwlock; + /* Locked by lock. */ + isc_uint32_t active_nodes; + /* Locked by rwlock. */ + isc_uint32_t references; + dns_rbt_t *table; +}; + +#define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l') +#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC) + +struct dns_keynode { + unsigned int magic; + isc_refcount_t refcount; + dst_key_t * key; + isc_boolean_t managed; + struct dns_keynode * next; +}; + +#define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd') +#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC) + isc_result_t dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep); /*%< @@ -106,16 +137,22 @@ dns_keytable_detach(dns_keytable_t **keytablep); */ isc_result_t -dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp); +dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed, + dst_key_t **keyp); /*%< - * Add '*keyp' to 'keytable'. + * Add '*keyp' to 'keytable' (using the name in '*keyp'). + * The value of keynode->managed is set to 'managed' * * Notes: * *\li Ownership of *keyp is transferred to the keytable. + *\li If the key already exists in the table, ISC_R_EXISTS is + * returned and the new key is freed. * * Requires: * + *\li 'keytable' points to a valid keytable. + * *\li keyp != NULL && *keyp is a valid dst_key_t *. * * Ensures: @@ -125,10 +162,123 @@ dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp); * Returns: * *\li ISC_R_SUCCESS + *\li ISC_R_EXISTS * *\li Any other result indicates failure. */ +isc_result_t +dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name); +/*%< + * Add a null key to 'keytable' for name 'name'. This marks the + * name as a secure domain, but doesn't supply any key data to allow the + * domain to be validated. (Used when automated trust anchor management + * has gotten broken by a zone misconfiguration; for exmaple, when the + * active key has been revoked but the stand-by key was still in its 30-day + * waiting period for validity.) + * + * Notes: + * + *\li If a key already exists in the table, ISC_R_EXISTS is + * returned and nothing is done. + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + * + *\li keyp != NULL && *keyp is a valid dst_key_t *. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_EXISTS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname); +/*%< + * Delete node(s) from 'keytable' matching name 'keyname' + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + * + *\li 'name' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey); +/*%< + * Delete node(s) from 'keytable' containing copies of the key pointed + * to by 'dstkey' + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + *\li 'dstkey' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname, + dns_keynode_t **keynodep); +/*%< + * Search for the first instance of a key named 'name' in 'keytable', + * without regard to keyid and algorithm. Use dns_keytable_nextkeynode() + * to find subsequent instances. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'name' is a valid absolute name. + * + *\li keynodep != NULL && *keynodep == NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + * + *\li Any other result indicates an error. + */ + +isc_result_t +dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, + dns_keynode_t **nextnodep); +/*%< + * Return for the next key after 'keynode' in 'keytable', without regard to + * keyid and algorithm. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'keynode' is a valid keynode. + * + *\li nextnodep != NULL && *nextnodep == NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + * + *\li Any other result indicates an error. + */ + isc_result_t dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, dns_secalg_t algorithm, dns_keytag_t tag, @@ -250,6 +400,30 @@ dns_keynode_key(dns_keynode_t *keynode); * Get the DST key associated with keynode. */ +isc_boolean_t +dns_keynode_managed(dns_keynode_t *keynode); +/*%< + * Is this flagged as a managed key? + */ + +isc_result_t +dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target); +/*%< + * Allocate space for a keynode + */ + +void +dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target); +/*%< + * Attach keynode 'source' to '*target' + */ + +void +dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **target); +/*%< + * Detach keynode. + */ + ISC_LANG_ENDDECLS #endif /* DNS_KEYTABLE_H */ diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h index eef496c9af..38d78fabc9 100644 --- a/lib/dns/include/dns/keyvalues.h +++ b/lib/dns/include/dns/keyvalues.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keyvalues.h,v 1.25 2009/06/04 02:56:47 tbox Exp $ */ +/* $Id: keyvalues.h,v 1.26 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_KEYVALUES_H #define DNS_KEYVALUES_H 1 @@ -42,7 +42,7 @@ #define DNS_KEYOWNER_ENTITY 0x0200 /*%< key is assoc. with entity eg host */ #define DNS_KEYOWNER_ZONE 0x0100 /*%< key is zone key */ #define DNS_KEYOWNER_RESERVED 0x0300 /*%< reserved meaning */ -#define DNS_KEYFLAG_REVOKE 0x0080 /*%< key revoked (per rfc5001) */ +#define DNS_KEYFLAG_REVOKE 0x0080 /*%< key revoked (per rfc5011) */ #define DNS_KEYFLAG_RESERVED9 0x0040 /*%< reserved - must be zero */ #define DNS_KEYFLAG_RESERVED10 0x0020 /*%< reserved - must be zero */ #define DNS_KEYFLAG_RESERVED11 0x0010 /*%< reserved - must be zero */ @@ -51,7 +51,6 @@ #define DNS_KEYFLAG_RESERVEDMASK (DNS_KEYFLAG_RESERVED2 | \ DNS_KEYFLAG_RESERVED4 | \ DNS_KEYFLAG_RESERVED5 | \ - DNS_KEYFLAG_RESERVED8 | \ DNS_KEYFLAG_RESERVED9 | \ DNS_KEYFLAG_RESERVED10 | \ DNS_KEYFLAG_RESERVED11 ) diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h index 93a782d82c..74888a7f42 100644 --- a/lib/dns/include/dns/master.h +++ b/lib/dns/include/dns/master.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.h,v 1.51 2008/04/02 02:37:42 marka Exp $ */ +/* $Id: master.h,v 1.52 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_MASTER_H #define DNS_MASTER_H 1 @@ -56,6 +56,7 @@ #define DNS_MASTER_CHECKMXFAIL 0x00001000 #define DNS_MASTER_RESIGN 0x00002000 +#define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */ ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index f42fcbb23c..4c6c523112 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.h,v 1.129 2009/03/11 07:02:34 each Exp $ */ +/* $Id: name.h,v 1.130 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_NAME_H #define DNS_NAME_H 1 @@ -1165,6 +1165,46 @@ dns_name_fromstring(dns_name_t *target, const char *src, isc_mem_t *mctx); *\li Any error that dns_name_dup() can return. */ +isc_result_t +dns_name_tostring(dns_name_t *source, char **target, isc_mem_t *mctx); +/*%< + * Convert 'name' to string format, allocating sufficient memory to + * hold it (free with isc_mem_free()). + * + * Differs from dns_name_format in that it allocates its own memory. + * + * Requires: + * + *\li 'name' is a valid name. + *\li 'target' is not NULL. + *\li '*target' is NULL. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any error that dns_name_totext() can return. + */ + +isc_result_t +dns_name_fromstring(dns_name_t *target, const char *src, isc_mem_t *mctx); +/*%< + * Convert a string to a name and place it in target, allocating memory + * as necessary. + * + * Requires: + * + * \li 'target' is a valid name that is not read-only. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_name_fromtext() can return. + * + *\li Any error that dns_name_dup() can return. + */ + isc_result_t dns_name_settotextfilter(dns_name_totextfilter_t proc); /*%< diff --git a/lib/dns/include/dns/rriterator.h b/lib/dns/include/dns/rriterator.h new file mode 100644 index 0000000000..0e4b0a469a --- /dev/null +++ b/lib/dns/include/dns/rriterator.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: rriterator.h,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +#ifndef DNS_RRITERATOR_H +#define DNS_RRITERATOR_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file dns/rriterator.h + * \brief + * Functions for "walking" a zone database, visiting each RR or RRset in turn. + */ + +/***** + ***** Imports + *****/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +ISC_LANG_BEGINDECLS + +/***** + ***** Types + *****/ + +/*% + * A dns_rriterator_t is an iterator that iterates over an entire database, + * returning one RR at a time, in some arbitrary order. + */ + +typedef struct dns_rriterator { + unsigned int magic; + isc_result_t result; + dns_db_t *db; + dns_dbiterator_t *dbit; + dns_dbversion_t *ver; + isc_stdtime_t now; + dns_dbnode_t *node; + dns_fixedname_t fixedname; + dns_rdatasetiter_t *rdatasetit; + dns_rdataset_t rdataset; + dns_rdata_t rdata; +} dns_rriterator_t; + +#define RRITERATOR_MAGIC ISC_MAGIC('R', 'R', 'I', 't') +#define VALID_RRITERATOR(m) ISC_MAGIC_VALID(m, RRITERATOR_MAGIC) + +isc_result_t +dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, + dns_dbversion_t *ver, isc_stdtime_t now); + +isc_result_t +dns_rriterator_first(dns_rriterator_t *it); + +isc_result_t +dns_rriterator_nextrrset(dns_rriterator_t *it); + +isc_result_t +dns_rriterator_next(dns_rriterator_t *it); + +void +dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name, + isc_uint32_t *ttl, dns_rdataset_t **rdataset, + dns_rdata_t **rdata); + +void +dns_rriterator_pause(dns_rriterator_t *it); + +void +dns_rriterator_destroy(dns_rriterator_t *it); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RRITERATOR_H */ diff --git a/lib/dns/include/dns/soa.h b/lib/dns/include/dns/soa.h index bb563655ce..a57939a24f 100644 --- a/lib/dns/include/dns/soa.h +++ b/lib/dns/include/dns/soa.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa.h,v 1.9 2007/06/19 23:47:17 tbox Exp $ */ +/* $Id: soa.h,v 1.10 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_SOA_H #define DNS_SOA_H 1 @@ -40,6 +40,12 @@ ISC_LANG_BEGINDECLS +isc_result_t +dns_soa_buildrdata(dns_name_t *origin, dns_name_t *contact, + dns_rdataclass_t rdclass, + isc_uint32_t serial, isc_uint32_t refresh, + isc_uint32_t retry, isc_uint32_t expire, + isc_uint32_t minimum, dns_rdata_t *rdata); isc_uint32_t dns_soa_getserial(dns_rdata_t *rdata); isc_uint32_t diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 292ec60042..d6d97b05af 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.133 2009/01/27 22:29:59 jinmei Exp $ */ +/* $Id: types.h,v 1.134 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -72,6 +72,7 @@ typedef struct dns_iptable dns_iptable_t; typedef isc_uint32_t dns_iterations_t; typedef isc_uint16_t dns_keyflags_t; typedef struct dns_keynode dns_keynode_t; +typedef ISC_LIST(dns_keynode_t) dns_keynodelist_t; typedef struct dns_keytable dns_keytable_t; typedef isc_uint16_t dns_keytag_t; typedef struct dns_loadctx dns_loadctx_t; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index d275b10fb6..0f511384d1 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.117 2009/05/29 22:22:37 jinmei Exp $ */ +/* $Id: view.h,v 1.118 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 @@ -92,8 +92,7 @@ struct dns_view { dns_cache_t * cache; dns_db_t * cachedb; dns_db_t * hints; - dns_keytable_t * secroots; - dns_keytable_t * trustedkeys; + dns_keytable_t * secroots; /* security roots */ isc_mutex_t lock; isc_boolean_t frozen; isc_task_t * task; @@ -165,6 +164,7 @@ struct dns_view { unsigned int attributes; /* Under owner's locking control. */ ISC_LINK(struct dns_view) link; + dns_viewlist_t * viewlist; }; #define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w') diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index b917b4d651..0f5c002300 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.164 2009/01/27 22:29:59 jinmei Exp $ */ +/* $Id: zone.h,v 1.165 2009/06/30 02:52:32 each Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -40,7 +40,8 @@ typedef enum { dns_zone_none, dns_zone_master, dns_zone_slave, - dns_zone_stub + dns_zone_stub, + dns_zone_key } dns_zonetype_t; #define DNS_ZONEOPT_SERVERS 0x00000001U /*%< perform server checks */ diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 0708e5fb04..b122a6addb 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst.h,v 1.14 2009/06/11 23:47:55 tbox Exp $ */ +/* $Id: dst.h,v 1.15 2009/06/30 02:52:32 each Exp $ */ #ifndef DST_DST_H #define DST_DST_H 1 @@ -639,6 +639,15 @@ dst_key_setbits(dst_key_t *key, isc_uint16_t bits); * "key" is a valid key. */ +isc_result_t +dst_key_setflags(dst_key_t *key, isc_uint32_t flags); +/* + * Set the key flags, and recompute the key ID. + * + * Requires: + * "key" is a valid key. + */ + ISC_LANG_ENDDECLS #endif /* DST_DST_H */ diff --git a/lib/dns/keydata.c b/lib/dns/keydata.c new file mode 100644 index 0000000000..588e31e1a1 --- /dev/null +++ b/lib/dns/keydata.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: keydata.c,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +/*! \file */ + +#include + + +#include +#include +#include +#include + +#include +#include +#include + +isc_result_t +dns_keydata_todnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx) +{ + REQUIRE(keydata != NULL && dnskey != NULL); + + dnskey->common.rdtype = dns_rdatatype_dnskey; + dnskey->common.rdclass = keydata->common.rdclass; + dnskey->mctx = mctx; + dnskey->flags = keydata->flags; + dnskey->protocol = keydata->protocol; + dnskey->algorithm = keydata->algorithm; + + dnskey->datalen = keydata->datalen; + + if (mctx == NULL) + dnskey->data = keydata->data; + else { + dnskey->data = isc_mem_allocate(mctx, dnskey->datalen); + if (dnskey->data == NULL) + return (ISC_R_NOMEMORY); + memcpy(dnskey->data, keydata->data, dnskey->datalen); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_keydata_fromdnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, + isc_uint32_t refresh, isc_uint32_t addhd, + isc_uint32_t removehd, isc_mem_t *mctx) +{ + REQUIRE(keydata != NULL && dnskey != NULL); + + keydata->common.rdtype = dns_rdatatype_keydata; + keydata->common.rdclass = dnskey->common.rdclass; + keydata->mctx = mctx; + keydata->refresh = refresh; + keydata->addhd = addhd; + keydata->removehd = removehd; + keydata->flags = dnskey->flags; + keydata->protocol = dnskey->protocol; + keydata->algorithm = dnskey->algorithm; + + keydata->datalen = dnskey->datalen; + if (mctx == NULL) + keydata->data = dnskey->data; + else { + keydata->data = isc_mem_allocate(mctx, keydata->datalen); + if (keydata->data == NULL) + return (ISC_R_NOMEMORY); + memcpy(keydata->data, dnskey->data, keydata->datalen); + } + + return (ISC_R_SUCCESS); +} diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c index bffd2d3ac7..32cc494dac 100644 --- a/lib/dns/keytable.c +++ b/lib/dns/keytable.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keytable.c,v 1.34 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: keytable.c,v 1.35 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -31,41 +31,12 @@ #include #include -struct dns_keytable { - /* Unlocked. */ - unsigned int magic; - isc_mem_t *mctx; - isc_mutex_t lock; - isc_rwlock_t rwlock; - /* Locked by lock. */ - isc_uint32_t active_nodes; - /* Locked by rwlock. */ - isc_uint32_t references; - dns_rbt_t *table; -}; - -#define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l') -#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC) - -struct dns_keynode { - unsigned int magic; - dst_key_t * key; - struct dns_keynode * next; -}; - -#define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd') -#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC) - static void free_keynode(void *node, void *arg) { dns_keynode_t *keynode = node; isc_mem_t *mctx = arg; - REQUIRE(VALID_KEYNODE(keynode)); - dst_key_free(&keynode->key); - if (keynode->next != NULL) - free_keynode(keynode->next, mctx); - isc_mem_put(mctx, keynode, sizeof(dns_keynode_t)); + dns_keynode_detach(mctx, &keynode); } isc_result_t @@ -116,7 +87,6 @@ dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) { return (result); } - void dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) { @@ -173,49 +143,218 @@ dns_keytable_detach(dns_keytable_t **keytablep) { *keytablep = NULL; } -isc_result_t -dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp) { +static isc_result_t +insert(dns_keytable_t *keytable, isc_boolean_t managed, + dns_name_t *keyname, dst_key_t **keyp) +{ isc_result_t result; - dns_keynode_t *knode; + dns_keynode_t *knode = NULL; dns_rbtnode_t *node; - dns_name_t *keyname; - - /* - * Add '*keyp' to 'keytable'. - */ + REQUIRE(keyp == NULL || *keyp != NULL); REQUIRE(VALID_KEYTABLE(keytable)); - REQUIRE(keyp != NULL); - keyname = dst_key_name(*keyp); + result = dns_keynode_create(keytable->mctx, &knode); + if (result != ISC_R_SUCCESS) + return (result); - knode = isc_mem_get(keytable->mctx, sizeof(*knode)); - if (knode == NULL) - return (ISC_R_NOMEMORY); + knode->managed = managed; RWLOCK(&keytable->rwlock, isc_rwlocktype_write); node = NULL; result = dns_rbt_addnode(keytable->table, keyname, &node); - if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) { - knode->magic = KEYNODE_MAGIC; - knode->key = *keyp; - knode->next = node->data; + if (keyp != NULL) { + if (result == ISC_R_EXISTS) { + /* Key already in table? */ + dns_keynode_t *k; + for (k = node->data; k != NULL; k = k->next) { + if (k->key == NULL) { + k->key = *keyp; + break; + } + if (dst_key_compare(k->key, *keyp) == ISC_TRUE) + break; + } + if (k == NULL) + result = ISC_R_SUCCESS; + else + dst_key_free(keyp); + } + + if (result == ISC_R_SUCCESS) { + knode->key = *keyp; + knode->next = node->data; + *keyp = NULL; + } + } + + if (result == ISC_R_SUCCESS) { node->data = knode; - *keyp = NULL; knode = NULL; - result = ISC_R_SUCCESS; } RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); if (knode != NULL) - isc_mem_put(keytable->mctx, knode, sizeof(*knode)); + dns_keynode_detach(keytable->mctx, &knode); return (result); } +isc_result_t +dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed, + dst_key_t **keyp) +{ + REQUIRE(keyp != NULL && *keyp != NULL); + return (insert(keytable, managed, dst_key_name(*keyp), keyp)); +} + +isc_result_t +dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name) { + return (insert(keytable, ISC_TRUE, name, NULL)); +} + +isc_result_t +dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname) { + isc_result_t result; + dns_rbtnode_t *node = NULL; + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(keyname != NULL); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_write); + result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + if (result == ISC_R_SUCCESS) { + if (node->data != NULL) + result = dns_rbt_deletenode(keytable->table, + node, ISC_FALSE); + else + result = ISC_R_NOTFOUND; + } else if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); + + return (result); +} + +isc_result_t +dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) { + isc_result_t result; + dns_name_t *keyname; + dns_rbtnode_t *node = NULL; + dns_keynode_t *knode = NULL, **kprev = NULL; + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(dstkey != NULL); + + keyname = dst_key_name(dstkey); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_write); + result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + + if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + if (result != ISC_R_SUCCESS) + goto finish; + + if (node->data == NULL) { + result = ISC_R_NOTFOUND; + goto finish; + } + + knode = node->data; + if (knode->next == NULL && + (knode->key == NULL || + dst_key_compare(knode->key, dstkey) == ISC_TRUE)) { + result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE); + goto finish; + } + + kprev = (dns_keynode_t **) &node->data; + while (knode != NULL) { + if (dst_key_compare(knode->key, dstkey) == ISC_TRUE) + break; + kprev = &knode; + knode = knode->next; + } + + if (knode != NULL) { + if (knode->key != NULL) + dst_key_free(&knode->key); + /* + * This is equivalent to: + * dns_keynode_attach(knode->next, &tmp); + * dns_keynode_detach(kprev); + * dns_keynode_attach(tmp, &kprev); + * dns_keynode_detach(&tmp); + */ + *kprev = knode->next; + knode->next = NULL; + dns_keynode_detach(keytable->mctx, &knode); + } else + result = DNS_R_PARTIALMATCH; + finish: + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); + return (result); +} + +isc_result_t +dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname, + dns_keynode_t **keynodep) +{ + isc_result_t result; + dns_rbtnode_t *node = NULL; + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(keyname != NULL); + REQUIRE(keynodep != NULL && *keynodep == NULL); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_read); + result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + if (result == ISC_R_SUCCESS) { + if (node->data != NULL) { + LOCK(&keytable->lock); + keytable->active_nodes++; + UNLOCK(&keytable->lock); + dns_keynode_attach(node->data, keynodep); + } else + result = ISC_R_NOTFOUND; + } else if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); + + return (result); +} + +isc_result_t +dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, + dns_keynode_t **nextnodep) +{ + /* + * Return the next key after 'keynode', regardless of + * properties. + */ + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(VALID_KEYNODE(keynode)); + REQUIRE(nextnodep != NULL && *nextnodep == NULL); + + if (keynode->next == NULL) + return (ISC_R_NOTFOUND); + + dns_keynode_attach(keynode->next, nextnodep); + LOCK(&keytable->lock); + keytable->active_nodes++; + UNLOCK(&keytable->lock); + + return (ISC_R_SUCCESS); +} + isc_result_t dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, dns_secalg_t algorithm, dns_keytag_t tag, @@ -250,6 +389,10 @@ dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, if (result == ISC_R_SUCCESS) { INSIST(data != NULL); for (knode = data; knode != NULL; knode = knode->next) { + if (knode->key == NULL) { + knode = NULL; + break; + } if (algorithm == dst_key_alg(knode->key) && tag == dst_key_id(knode->key)) break; @@ -258,7 +401,7 @@ dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, LOCK(&keytable->lock); keytable->active_nodes++; UNLOCK(&keytable->lock); - *keynodep = knode; + dns_keynode_attach(knode, keynodep); } else result = DNS_R_PARTIALMATCH; } else if (result == DNS_R_PARTIALMATCH) @@ -286,6 +429,10 @@ dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, REQUIRE(nextnodep != NULL && *nextnodep == NULL); for (knode = keynode->next; knode != NULL; knode = knode->next) { + if (knode->key == NULL) { + knode = NULL; + break; + } if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) && dst_key_id(keynode->key) == dst_key_id(knode->key)) break; @@ -295,7 +442,7 @@ dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, keytable->active_nodes++; UNLOCK(&keytable->lock); result = ISC_R_SUCCESS; - *nextnodep = knode; + dns_keynode_attach(knode, nextnodep); } else result = ISC_R_NOTFOUND; @@ -345,7 +492,7 @@ dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) keytable->active_nodes--; UNLOCK(&keytable->lock); - *keynodep = NULL; + dns_keynode_detach(keytable->mctx, keynodep); } isc_result_t @@ -393,3 +540,61 @@ dns_keynode_key(dns_keynode_t *keynode) { return (keynode->key); } + +isc_boolean_t +dns_keynode_managed(dns_keynode_t *keynode) { + /* + * Is this a managed key? + */ + REQUIRE(VALID_KEYNODE(keynode)); + + return (keynode->managed); +} + +isc_result_t +dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) { + isc_result_t result; + dns_keynode_t *knode = NULL; + + REQUIRE(target != NULL && *target == NULL); + + knode = isc_mem_get(mctx, sizeof(dns_keynode_t)); + if (knode == NULL) + return (ISC_R_NOMEMORY); + + knode->magic = KEYNODE_MAGIC; + knode->managed = ISC_FALSE; + knode->key = NULL; + knode->next = NULL; + + result = isc_refcount_init(&knode->refcount, 1); + if (result != ISC_R_SUCCESS) + return (result); + + *target = knode; + return (ISC_R_SUCCESS); +} + +void +dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) { + REQUIRE(VALID_KEYNODE(source)); + isc_refcount_increment(&source->refcount, NULL); + *target = source; +} + +void +dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) { + unsigned int refs; + dns_keynode_t *node = *keynode; + REQUIRE(VALID_KEYNODE(node)); + isc_refcount_decrement(&node->refcount, &refs); + if (refs == 0) { + if (node->key != NULL) + dst_key_free(&node->key); + if (node->next != NULL) + dns_keynode_detach(mctx, &node->next); + isc_refcount_destroy(&node->refcount); + isc_mem_put(mctx, node, sizeof(dns_keynode_t)); + } + *keynode = NULL; +} diff --git a/lib/dns/master.c b/lib/dns/master.c index ec45a72000..35543520ba 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.c,v 1.176 2009/02/16 03:19:40 marka Exp $ */ +/* $Id: master.c,v 1.177 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -862,6 +862,7 @@ generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs, if ((lctx->options & DNS_MASTER_ZONE) != 0 && (lctx->options & DNS_MASTER_SLAVE) == 0 && + (lctx->options & DNS_MASTER_KEY) == 0 && !dns_name_issubdomain(owner, lctx->top)) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -1502,6 +1503,7 @@ load_text(dns_loadctx_t *lctx) { } if ((lctx->options & DNS_MASTER_ZONE) != 0 && (lctx->options & DNS_MASTER_SLAVE) == 0 && + (lctx->options & DNS_MASTER_KEY) == 0 && !dns_name_issubdomain(new_name, lctx->top)) { char namebuf[DNS_NAME_FORMATSIZE]; diff --git a/lib/dns/rdata/generic/keydata_65533.c b/lib/dns/rdata/generic/keydata_65533.c new file mode 100644 index 0000000000..0d374a058d --- /dev/null +++ b/lib/dns/rdata/generic/keydata_65533.c @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: keydata_65533.c,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +#ifndef GENERIC_KEYDATA_65533_C +#define GENERIC_KEYDATA_65533_C 1 + +#include + +#define RRTYPE_KEYDATA_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC) + +static inline isc_result_t +fromtext_keydata(ARGS_FROMTEXT) { + isc_token_t token; + dns_secalg_t alg; + dns_secproto_t proto; + dns_keyflags_t flags; + isc_uint32_t refresh, addhd, removehd; + + REQUIRE(type == 65533); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(origin); + UNUSED(options); + UNUSED(callbacks); + + /* refresh timer */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &refresh)); + RETERR(uint32_tobuffer(refresh, target)); + + /* add hold-down */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &addhd)); + RETERR(uint32_tobuffer(addhd, target)); + + /* remove hold-down */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &removehd)); + RETERR(uint32_tobuffer(removehd, target)); + + /* flags */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion)); + RETERR(uint16_tobuffer(flags, target)); + + /* protocol */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion)); + RETERR(mem_tobuffer(target, &proto, 1)); + + /* algorithm */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion)); + RETERR(mem_tobuffer(target, &alg, 1)); + + /* No Key? */ + if ((flags & 0xc000) == 0xc000) + return (ISC_R_SUCCESS); + + return (isc_base64_tobuffer(lexer, target, -1)); +} + +static inline isc_result_t +totext_keydata(ARGS_TOTEXT) { + isc_region_t sr; + char buf[sizeof("64000")]; + unsigned int flags; + unsigned char algorithm; + unsigned long when; + + REQUIRE(rdata->type == 65533); + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, &sr); + + /* refresh timer */ + when = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + RETERR(dns_time32_totext(when, target)); + RETERR(str_totext(" ", target)); + + /* add hold-down */ + when = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + RETERR(dns_time32_totext(when, target)); + RETERR(str_totext(" ", target)); + + /* remove hold-down */ + when = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + RETERR(dns_time32_totext(when, target)); + RETERR(str_totext(" ", target)); + + /* flags */ + flags = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + sprintf(buf, "%u", flags); + RETERR(str_totext(buf, target)); + RETERR(str_totext(" ", target)); + + /* protocol */ + sprintf(buf, "%u", sr.base[0]); + isc_region_consume(&sr, 1); + RETERR(str_totext(buf, target)); + RETERR(str_totext(" ", target)); + + /* algorithm */ + algorithm = sr.base[0]; + sprintf(buf, "%u", algorithm); + isc_region_consume(&sr, 1); + RETERR(str_totext(buf, target)); + + /* No Key? */ + if ((flags & 0xc000) == 0xc000) + return (ISC_R_SUCCESS); + + /* key */ + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(" (", target)); + RETERR(str_totext(tctx->linebreak, target)); + RETERR(isc_base64_totext(&sr, tctx->width - 2, + tctx->linebreak, target)); + + if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0) + RETERR(str_totext(tctx->linebreak, target)); + else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(" ", target)); + + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(")", target)); + + if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0) { + isc_region_t tmpr; + + RETERR(str_totext(" ; key id = ", target)); + dns_rdata_toregion(rdata, &tmpr); + /* Skip over refresh, addhd, and removehd */ + isc_region_consume(&tmpr, 12); + sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm)); + RETERR(str_totext(buf, target)); + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_keydata(ARGS_FROMWIRE) { + isc_region_t sr; + + REQUIRE(type == 65533); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(dctx); + UNUSED(options); + + isc_buffer_activeregion(source, &sr); + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + + isc_buffer_forward(source, sr.length); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline isc_result_t +towire_keydata(ARGS_TOWIRE) { + isc_region_t sr; + + REQUIRE(rdata->type == 65533); + REQUIRE(rdata->length != 0); + + UNUSED(cctx); + + dns_rdata_toregion(rdata, &sr); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline int +compare_keydata(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 65533); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + return (isc_region_compare(&r1, &r2)); +} + +static inline isc_result_t +fromstruct_keydata(ARGS_FROMSTRUCT) { + dns_rdata_keydata_t *keydata = source; + + REQUIRE(type == 65533); + REQUIRE(source != NULL); + REQUIRE(keydata->common.rdtype == type); + REQUIRE(keydata->common.rdclass == rdclass); + + UNUSED(type); + UNUSED(rdclass); + + /* Refresh timer */ + RETERR(uint32_tobuffer(keydata->refresh, target)); + + /* Add hold-down */ + RETERR(uint32_tobuffer(keydata->addhd, target)); + + /* Remove hold-down */ + RETERR(uint32_tobuffer(keydata->removehd, target)); + + /* Flags */ + RETERR(uint16_tobuffer(keydata->flags, target)); + + /* Protocol */ + RETERR(uint8_tobuffer(keydata->protocol, target)); + + /* Algorithm */ + RETERR(uint8_tobuffer(keydata->algorithm, target)); + + /* Data */ + return (mem_tobuffer(target, keydata->data, keydata->datalen)); +} + +static inline isc_result_t +tostruct_keydata(ARGS_TOSTRUCT) { + dns_rdata_keydata_t *keydata = target; + isc_region_t sr; + + REQUIRE(rdata->type == 65533); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + keydata->common.rdclass = rdata->rdclass; + keydata->common.rdtype = rdata->type; + ISC_LINK_INIT(&keydata->common, link); + + dns_rdata_toregion(rdata, &sr); + + /* Refresh timer */ + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + keydata->refresh = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + + /* Add hold-down */ + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + keydata->addhd = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + + /* Remove hold-down */ + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + keydata->removehd = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + + /* Flags */ + if (sr.length < 2) + return (ISC_R_UNEXPECTEDEND); + keydata->flags = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + + /* Protocol */ + if (sr.length < 1) + return (ISC_R_UNEXPECTEDEND); + keydata->protocol = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + /* Algorithm */ + if (sr.length < 1) + return (ISC_R_UNEXPECTEDEND); + keydata->algorithm = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + /* Data */ + keydata->datalen = sr.length; + keydata->data = mem_maybedup(mctx, sr.base, keydata->datalen); + if (keydata->data == NULL) + return (ISC_R_NOMEMORY); + + keydata->mctx = mctx; + return (ISC_R_SUCCESS); +} + +static inline void +freestruct_keydata(ARGS_FREESTRUCT) { + dns_rdata_keydata_t *keydata = (dns_rdata_keydata_t *) source; + + REQUIRE(source != NULL); + REQUIRE(keydata->common.rdtype == 65533); + + if (keydata->mctx == NULL) + return; + + if (keydata->data != NULL) + isc_mem_free(keydata->mctx, keydata->data); + keydata->mctx = NULL; +} + +static inline isc_result_t +additionaldata_keydata(ARGS_ADDLDATA) { + REQUIRE(rdata->type == 65533); + + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_keydata(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == 65533); + + dns_rdata_toregion(rdata, &r); + + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_keydata(ARGS_CHECKOWNER) { + + REQUIRE(type == 65533); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_keydata(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == 65533); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +#endif /* GENERIC_KEYDATA_65533_C */ diff --git a/lib/dns/rdata/generic/keydata_65533.h b/lib/dns/rdata/generic/keydata_65533.h new file mode 100644 index 0000000000..8db827ecd3 --- /dev/null +++ b/lib/dns/rdata/generic/keydata_65533.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef GENERIC_KEYDATA_65533_H +#define GENERIC_KEYDATA_65533_H 1 + +/* $Id: keydata_65533.h,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +typedef struct dns_rdata_keydata { + dns_rdatacommon_t common; + isc_mem_t * mctx; + isc_uint32_t refresh; /* Timer for refreshing data */ + isc_uint32_t addhd; /* Hold-down timer for adding */ + isc_uint32_t removehd; /* Hold-down timer for removing */ + isc_uint16_t flags; /* Copy of DNSKEY_48 */ + isc_uint8_t protocol; + isc_uint8_t algorithm; + isc_uint16_t datalen; + unsigned char * data; +} dns_rdata_keydata_t; + +#endif /* GENERIC_KEYDATA_65533_H */ diff --git a/lib/dns/rriterator.c b/lib/dns/rriterator.c new file mode 100644 index 0000000000..c98caf324b --- /dev/null +++ b/lib/dns/rriterator.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $Id: rriterator.c,v 1.2 2009/06/30 02:52:32 each Exp $ */ + +/*! \file */ + +/*** + *** Imports + ***/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/*** + *** RRiterator methods + ***/ + +isc_result_t +dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now) +{ + isc_result_t result; + it->magic = RRITERATOR_MAGIC; + it->db = db; + it->dbit = NULL; + it->ver = ver; + it->now = now; + it->node = NULL; + result = dns_db_createiterator(it->db, 0, &it->dbit); + if (result != ISC_R_SUCCESS) + return (result); + it->rdatasetit = NULL; + dns_rdata_init(&it->rdata); + dns_rdataset_init(&it->rdataset); + dns_fixedname_init(&it->fixedname); + INSIST(! dns_rdataset_isassociated(&it->rdataset)); + it->result = ISC_R_SUCCESS; + return (it->result); +} + +isc_result_t +dns_rriterator_first(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + /* Reset state */ + if (dns_rdataset_isassociated(&it->rdataset)) + dns_rdataset_disassociate(&it->rdataset); + if (it->rdatasetit != NULL) + dns_rdatasetiter_destroy(&it->rdatasetit); + if (it->node != NULL) + dns_db_detachnode(it->db, &it->node); + it->result = dns_dbiterator_first(it->dbit); + + /* + * The top node may be empty when out of zone glue exists. + * Walk the tree to find the first node with data. + */ + while (it->result == ISC_R_SUCCESS) { + it->result = dns_dbiterator_current(it->dbit, &it->node, + dns_fixedname_name(&it->fixedname)); + if (it->result != ISC_R_SUCCESS) + return (it->result); + + it->result = dns_db_allrdatasets(it->db, it->node, it->ver, + it->now, &it->rdatasetit); + if (it->result != ISC_R_SUCCESS) + return (it->result); + + it->result = dns_rdatasetiter_first(it->rdatasetit); + if (it->result != ISC_R_SUCCESS) { + /* + * This node is empty. Try next node. + */ + dns_rdatasetiter_destroy(&it->rdatasetit); + dns_db_detachnode(it->db, &it->node); + it->result = dns_dbiterator_next(it->dbit); + continue; + } + dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); + it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; + it->result = dns_rdataset_first(&it->rdataset); + return (it->result); + } + return (it->result); +} + +isc_result_t +dns_rriterator_nextrrset(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + if (dns_rdataset_isassociated(&it->rdataset)) + dns_rdataset_disassociate(&it->rdataset); + it->result = dns_rdatasetiter_next(it->rdatasetit); + /* + * The while loop body is executed more than once + * only when an empty dbnode needs to be skipped. + */ + while (it->result == ISC_R_NOMORE) { + dns_rdatasetiter_destroy(&it->rdatasetit); + dns_db_detachnode(it->db, &it->node); + it->result = dns_dbiterator_next(it->dbit); + if (it->result == ISC_R_NOMORE) { + /* We are at the end of the entire database. */ + return (it->result); + } + if (it->result != ISC_R_SUCCESS) + return (it->result); + it->result = dns_dbiterator_current(it->dbit, &it->node, + dns_fixedname_name(&it->fixedname)); + if (it->result != ISC_R_SUCCESS) + return (it->result); + it->result = dns_db_allrdatasets(it->db, it->node, it->ver, + it->now, &it->rdatasetit); + if (it->result != ISC_R_SUCCESS) + return (it->result); + it->result = dns_rdatasetiter_first(it->rdatasetit); + } + if (it->result != ISC_R_SUCCESS) + return (it->result); + dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); + it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; + it->result = dns_rdataset_first(&it->rdataset); + return (it->result); +} + +isc_result_t +dns_rriterator_next(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + if (it->result != ISC_R_SUCCESS) + return (it->result); + + INSIST(it->dbit != NULL); + INSIST(it->node != NULL); + INSIST(it->rdatasetit != NULL); + + it->result = dns_rdataset_next(&it->rdataset); + if (it->result == ISC_R_NOMORE) + return (dns_rriterator_nextrrset(it)); + return (it->result); +} + +void +dns_rriterator_pause(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS); +} + +void +dns_rriterator_destroy(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + if (dns_rdataset_isassociated(&it->rdataset)) + dns_rdataset_disassociate(&it->rdataset); + if (it->rdatasetit != NULL) + dns_rdatasetiter_destroy(&it->rdatasetit); + if (it->node != NULL) + dns_db_detachnode(it->db, &it->node); + dns_dbiterator_destroy(&it->dbit); +} + +void +dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name, + isc_uint32_t *ttl, dns_rdataset_t **rdataset, + dns_rdata_t **rdata) +{ + REQUIRE(name != NULL && *name == NULL); + REQUIRE(VALID_RRITERATOR(it)); + REQUIRE(it->result == ISC_R_SUCCESS); + + *name = dns_fixedname_name(&it->fixedname); + *ttl = it->rdataset.ttl; + + dns_rdata_reset(&it->rdata); + dns_rdataset_current(&it->rdataset, &it->rdata); + + if (rdataset) + *rdataset = &it->rdataset; + + if (rdata) + *rdata = &it->rdata; +} diff --git a/lib/dns/soa.c b/lib/dns/soa.c index 83a1c1790e..c974d15d35 100644 --- a/lib/dns/soa.c +++ b/lib/dns/soa.c @@ -15,15 +15,17 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa.c,v 1.8 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: soa.c,v 1.9 2009/06/30 02:52:32 each Exp $ */ /*! \file */ #include +#include #include #include +#include #include static inline isc_uint32_t @@ -60,6 +62,37 @@ soa_get(dns_rdata_t *rdata, int offset) { return (decode_uint32(rdata->data + rdata->length - 20 + offset)); } +isc_result_t +dns_soa_buildrdata(dns_name_t *origin, dns_name_t *contact, + dns_rdataclass_t rdclass, + isc_uint32_t serial, isc_uint32_t refresh, + isc_uint32_t retry, isc_uint32_t expire, + isc_uint32_t minimum, dns_rdata_t *rdata) { + dns_rdata_soa_t soa; + char soadata[DNS_NAME_FORMATSIZE]; + isc_buffer_t rdatabuf; + + REQUIRE(origin != NULL); + REQUIRE(contact != NULL); + + soa.common.rdtype = dns_rdatatype_soa; + soa.common.rdclass = rdclass; + soa.mctx = NULL; + soa.serial = serial; + soa.refresh = refresh; + soa.retry = retry; + soa.expire = expire; + soa.minimum = minimum; + dns_name_init(&soa.origin, NULL); + dns_name_clone(origin, &soa.origin); + dns_name_init(&soa.contact, NULL); + dns_name_clone(contact, &soa.contact); + + isc_buffer_init(&rdatabuf, soadata, sizeof(soadata)); + return (dns_rdata_fromstruct(rdata, rdclass, dns_rdatatype_soa, + &soa, &rdatabuf)); +} + isc_uint32_t dns_soa_getserial(dns_rdata_t *rdata) { return soa_get(rdata, 0); diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 88f661a76a..8f8f331296 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.177 2009/06/09 22:57:09 marka Exp $ */ +/* $Id: validator.c,v 1.178 2009/06/30 02:52:32 each Exp $ */ #include @@ -1875,6 +1875,8 @@ validate(dns_validator_t *val, isc_boolean_t resume) { break; } val->key = dns_keynode_key(val->keynode); + if (val->key == NULL) + break; } else { if (get_dst_key(val, val->siginfo, val->keyset) != ISC_R_SUCCESS) @@ -2115,7 +2117,8 @@ dlv_validatezonekey(dns_validator_t *val) { } /*% - * Attempts positive response validation of an RRset containing zone keys. + * Attempts positive response validation of an RRset containing zone keys + * (i.e. a DNSKEY rrset). * * Returns: * \li ISC_R_SUCCESS Validation completed successfully @@ -2182,11 +2185,18 @@ validatezonekey(dns_validator_t *val) { atsep = ISC_TRUE; while (result == ISC_R_SUCCESS) { dstkey = dns_keynode_key(keynode); + if (dstkey == NULL) { + dns_keytable_detachkeynode( + val->keytable, + &keynode); + break; + } result = verify(val, dstkey, &sigrdata, sig.keyid); if (result == ISC_R_SUCCESS) { - dns_keytable_detachkeynode(val->keytable, - &keynode); + dns_keytable_detachkeynode( + val->keytable, + &keynode); break; } result = dns_keytable_findnextkeynode( @@ -2228,8 +2238,8 @@ validatezonekey(dns_validator_t *val) { sizeof(namebuf)); validator_log(val, ISC_LOG_DEBUG(2), "unable to find a DNSKEY which verifies " - "the DNSKEY RRset and also matches one " - "of specified trusted-keys for '%s'", + "the DNSKEY RRset and also matches a " + "trusted key for '%s'", namebuf); return (DNS_R_NOVALIDKEY); } diff --git a/lib/dns/view.c b/lib/dns/view.c index b5414d4cd3..57dc617472 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.154 2009/05/29 22:22:37 jinmei Exp $ */ +/* $Id: view.c,v 1.155 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -96,23 +96,6 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, goto cleanup_mutex; } view->secroots = NULL; - result = dns_keytable_create(mctx, &view->secroots); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "dns_keytable_create() failed: %s", - isc_result_totext(result)); - result = ISC_R_UNEXPECTED; - goto cleanup_zt; - } - view->trustedkeys = NULL; - result = dns_keytable_create(mctx, &view->trustedkeys); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "dns_keytable_create() failed: %s", - isc_result_totext(result)); - result = ISC_R_UNEXPECTED; - goto cleanup_secroots; - } view->fwdtable = NULL; result = dns_fwdtable_create(mctx, &view->fwdtable); if (result != ISC_R_SUCCESS) { @@ -120,7 +103,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, "dns_fwdtable_create() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; - goto cleanup_trustedkeys; + goto cleanup_zt; } view->acache = NULL; @@ -237,12 +220,6 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, cleanup_fwdtable: dns_fwdtable_destroy(&view->fwdtable); - cleanup_trustedkeys: - dns_keytable_detach(&view->trustedkeys); - - cleanup_secroots: - dns_keytable_detach(&view->secroots); - cleanup_zt: dns_zt_detach(&view->zonetable); @@ -365,8 +342,8 @@ destroy(dns_view_t *view) { isc_stats_detach(&view->resstats); if (view->resquerystats != NULL) dns_stats_detach(&view->resquerystats); - dns_keytable_detach(&view->trustedkeys); - dns_keytable_detach(&view->secroots); + if (view->secroots != NULL) + dns_keytable_detach(&view->secroots); dns_fwdtable_destroy(&view->fwdtable); dns_aclenv_destroy(&view->aclenv); DESTROYLOCK(&view->lock); @@ -990,7 +967,7 @@ dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname, isc_result_t dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, isc_stdtime_t now, unsigned int options, - isc_boolean_t use_hints, isc_boolean_t use_cache, + isc_boolean_t use_hints, isc_boolean_t use_cache, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { isc_result_t result; diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 4a568588fb..ff1575b4a3 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -226,17 +226,25 @@ dns_journal_print dns_journal_rollforward dns_journal_write_transaction dns_journal_writediff +dns_keydata_fromdnskey +dns_keydata_todnskey dns_keyflags_fromtext dns_keynode_key +dns_keynode_managed dns_keytable_add dns_keytable_attach dns_keytable_create +dns_keytable_delete +dns_keytable_deletekeynode dns_keytable_detach dns_keytable_detachkeynode +dns_keytable_find dns_keytable_finddeepestmatch dns_keytable_findkeynode dns_keytable_findnextkeynode dns_keytable_issecuredomain +dns_keytable_marksecure +dns_keytable_nextkeynode dns_lib_initmsgcat dns_loadctx_attach dns_loadctx_cancel @@ -332,6 +340,7 @@ dns_name_format dns_name_free dns_name_fromregion dns_name_fromtext +dns_name_fromstring dns_name_fromwire dns_name_fullcompare dns_name_getlabel @@ -353,6 +362,7 @@ dns_name_settotextfilter dns_name_split dns_name_tofilenametext dns_name_toregion +dns_name_tostring dns_name_totext dns_name_towire dns_ncache_add @@ -559,6 +569,13 @@ dns_result_register dns_result_torcode dns_result_totext dns_rootns_create +dns_rriterator_current +dns_rriterator_first +dns_rriterator_destroy +dns_rriterator_init +dns_rriterator_next +dns_rriterator_nextrrset +dns_rriterator_pause dns_sdb_putnamedrr dns_sdb_putrdata dns_sdb_putrr @@ -852,6 +869,7 @@ dst_key_paramcompare dst_key_proto dst_key_secretsize dst_key_setbits +dst_key_setflags dst_key_sigsize dst_key_size dst_key_tobuffer diff --git a/lib/dns/win32/libdns.dsp b/lib/dns/win32/libdns.dsp index ce283b2fe9..64e21b4ace 100644 --- a/lib/dns/win32/libdns.dsp +++ b/lib/dns/win32/libdns.dsp @@ -198,6 +198,10 @@ SOURCE=..\include\dns\journal.h # End Source File # Begin Source File +SOURCE=..\include\dns\keydata.h +# End Source File +# Begin Source File + SOURCE=..\include\dns\keyflags.h # End Source File # Begin Source File @@ -326,6 +330,10 @@ SOURCE=..\include\dns\rootns.h # End Source File # Begin Source File +SOURCE=..\include\dns\rriterator.h +# End Source File +# Begin Source File + SOURCE=..\include\dns\sdb.h # End Source File # Begin Source File @@ -494,6 +502,10 @@ SOURCE=..\journal.c # End Source File # Begin Source File +SOURCE=..\keydata.c +# End Source File +# Begin Source File + SOURCE=..\keytable.c # End Source File # Begin Source File @@ -602,6 +614,10 @@ SOURCE=..\rootns.c # End Source File # Begin Source File +SOURCE=..\rriterator.c +# End Source File +# Begin Source File + SOURCE=..\sdb.c # End Source File # Begin Source File diff --git a/lib/dns/win32/libdns.mak b/lib/dns/win32/libdns.mak index d4d3ef65fd..1dde5713df 100644 --- a/lib/dns/win32/libdns.mak +++ b/lib/dns/win32/libdns.mak @@ -148,6 +148,7 @@ CLEAN : -@erase "$(INTDIR)\iptable.obj" -@erase "$(INTDIR)\journal.obj" -@erase "$(INTDIR)\key.obj" + -@erase "$(INTDIR)\keydata.obj" -@erase "$(INTDIR)\keytable.obj" -@erase "$(INTDIR)\lib.obj" -@erase "$(INTDIR)\log.obj" @@ -179,6 +180,7 @@ CLEAN : -@erase "$(INTDIR)\resolver.obj" -@erase "$(INTDIR)\result.obj" -@erase "$(INTDIR)\rootns.obj" + -@erase "$(INTDIR)\rriterator.obj" -@erase "$(INTDIR)\sdb.obj" -@erase "$(INTDIR)\sdlz.obj" -@erase "$(INTDIR)\soa.obj" @@ -270,6 +272,7 @@ LINK32_OBJS= \ "$(INTDIR)\forward.obj" \ "$(INTDIR)\iptable.obj" \ "$(INTDIR)\journal.obj" \ + "$(INTDIR)\keydata.obj" \ "$(INTDIR)\keytable.obj" \ "$(INTDIR)\lib.obj" \ "$(INTDIR)\log.obj" \ @@ -297,6 +300,7 @@ LINK32_OBJS= \ "$(INTDIR)\resolver.obj" \ "$(INTDIR)\result.obj" \ "$(INTDIR)\rootns.obj" \ + "$(INTDIR)\rriterator.obj" \ "$(INTDIR)\sdb.obj" \ "$(INTDIR)\sdlz.obj" \ "$(INTDIR)\soa.obj" \ @@ -415,6 +419,8 @@ CLEAN : -@erase "$(INTDIR)\journal.sbr" -@erase "$(INTDIR)\key.obj" -@erase "$(INTDIR)\key.sbr" + -@erase "$(INTDIR)\keydata.obj" + -@erase "$(INTDIR)\keydata.sbr" -@erase "$(INTDIR)\keytable.obj" -@erase "$(INTDIR)\keytable.sbr" -@erase "$(INTDIR)\lib.obj" @@ -477,6 +483,8 @@ CLEAN : -@erase "$(INTDIR)\result.sbr" -@erase "$(INTDIR)\rootns.obj" -@erase "$(INTDIR)\rootns.sbr" + -@erase "$(INTDIR)\rriterator.obj" + -@erase "$(INTDIR)\rriterator.sbr" -@erase "$(INTDIR)\sdb.obj" -@erase "$(INTDIR)\sdb.sbr" -@erase "$(INTDIR)\sdlz.obj" @@ -585,6 +593,7 @@ BSC32_SBRS= \ "$(INTDIR)\forward.sbr" \ "$(INTDIR)\iptable.sbr" \ "$(INTDIR)\journal.sbr" \ + "$(INTDIR)\keydata.sbr" \ "$(INTDIR)\keytable.sbr" \ "$(INTDIR)\lib.sbr" \ "$(INTDIR)\log.sbr" \ @@ -612,6 +621,7 @@ BSC32_SBRS= \ "$(INTDIR)\resolver.sbr" \ "$(INTDIR)\result.sbr" \ "$(INTDIR)\rootns.sbr" \ + "$(INTDIR)\rriterator.sbr" \ "$(INTDIR)\sdb.sbr" \ "$(INTDIR)\sdlz.sbr" \ "$(INTDIR)\soa.sbr" \ @@ -673,6 +683,7 @@ LINK32_OBJS= \ "$(INTDIR)\forward.obj" \ "$(INTDIR)\iptable.obj" \ "$(INTDIR)\journal.obj" \ + "$(INTDIR)\key.obj" \ "$(INTDIR)\keytable.obj" \ "$(INTDIR)\lib.obj" \ "$(INTDIR)\log.obj" \ @@ -700,6 +711,7 @@ LINK32_OBJS= \ "$(INTDIR)\resolver.obj" \ "$(INTDIR)\result.obj" \ "$(INTDIR)\rootns.obj" \ + "$(INTDIR)\rriterator.obj" \ "$(INTDIR)\sdb.obj" \ "$(INTDIR)\sdlz.obj" \ "$(INTDIR)\soa.obj" \ @@ -1094,6 +1106,24 @@ SOURCE=..\journal.c $(CPP) $(CPP_PROJ) $(SOURCE) +!ENDIF + +SOURCE=..\keydata.c + +!IF "$(CFG)" == "libdns - Win32 Release" + + +"$(INTDIR)\keydata.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libdns - Win32 Debug" + + +"$(INTDIR)\keydata.obj" "$(INTDIR)\keydata.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + !ENDIF SOURCE=..\keytable.c @@ -1581,6 +1611,24 @@ SOURCE=..\rootns.c $(CPP) $(CPP_PROJ) $(SOURCE) +!ENDIF + +SOURCE=..\rriterator.c + +!IF "$(CFG)" == "libdns - Win32 Release" + + +"$(INTDIR)\rriterator.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libdns - Win32 Debug" + + +"$(INTDIR)\rriterator.obj" "$(INTDIR)\rriterator.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + !ENDIF SOURCE=..\sdb.c diff --git a/lib/dns/zone.c b/lib/dns/zone.c index ea8d1a1f70..b9cb07f012 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.493 2009/06/17 04:29:43 marka Exp $ */ +/* $Id: zone.c,v 1.494 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +133,7 @@ typedef struct dns_signing dns_signing_t; typedef ISC_LIST(dns_signing_t) dns_signinglist_t; typedef struct dns_nsec3chain dns_nsec3chain_t; typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t; +typedef struct dns_keyfetch dns_keyfetch_t; #define DNS_ZONE_CHECKLOCK #ifdef DNS_ZONE_CHECKLOCK @@ -200,6 +205,8 @@ struct dns_zone { isc_time_t keywarntime; isc_time_t signingtime; isc_time_t nsec3chaintime; + isc_time_t refreshkeytime; /* Used by key zones */ + isc_uint32_t refreshkeycount; isc_uint32_t serial; isc_uint32_t refresh; isc_uint32_t retry; @@ -274,13 +281,13 @@ struct dns_zone { /*% * Statistics counters about zone management. */ - isc_stats_t *stats; + isc_stats_t *stats; /*% * Optional per-zone statistics counters. Counted outside of this * module. */ - isc_boolean_t requeststats_on; - isc_stats_t *requeststats; + isc_boolean_t requeststats_on; + isc_stats_t *requeststats; isc_uint32_t notifydelay; dns_isselffunc_t isself; void *isselfarg; @@ -340,7 +347,7 @@ struct dns_zone { * from SOA (if not set, we * are still using * default timer values) */ -#define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */ +#define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */ #define DNS_ZONEFLG_NOREFRESH 0x00010000U #define DNS_ZONEFLG_DIALNOTIFY 0x00020000U #define DNS_ZONEFLG_DIALREFRESH 0x00040000U @@ -351,6 +358,7 @@ struct dns_zone { #define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U #define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U #define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U +#define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */ #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0) @@ -481,7 +489,7 @@ struct dns_io { * DNSKEY as result of an update. */ struct dns_signing { - unsigned int magic; + unsigned int magic; dns_db_t *db; dns_dbiterator_t *dbiterator; dns_secalg_t algorithm; @@ -492,15 +500,15 @@ struct dns_signing { }; struct dns_nsec3chain { - unsigned int magic; + unsigned int magic; dns_db_t *db; dns_dbiterator_t *dbiterator; dns_rdata_nsec3param_t nsec3param; unsigned char salt[255]; isc_boolean_t done; - isc_boolean_t seen_nsec; - isc_boolean_t delete_nsec; - isc_boolean_t save_delete_nsec; + isc_boolean_t seen_nsec; + isc_boolean_t delete_nsec; + isc_boolean_t save_delete_nsec; ISC_LINK(dns_nsec3chain_t) link; }; /*%< @@ -525,6 +533,19 @@ struct dns_nsec3chain { * so it can be recovered in the event of a error. */ +struct dns_keyfetch { + dns_fixedname_t name; + dns_rdataset_t keydataset; + dns_rdataset_t dnskeyset; + dns_rdataset_t dnskeysigset; + dns_zone_t *zone; + dns_db_t *db; + dns_fetch_t *fetch; +}; + +#define HOUR 3600 +#define DAY (24*HOUR) +#define MONTH (30*DAY) #define SEND_BUFFER_SIZE 2048 @@ -535,6 +556,10 @@ static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, static void notify_log(dns_zone_t *zone, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); static void queue_xfrin(dns_zone_t *zone); +static isc_result_t update_one_rr(dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, dns_diffop_t op, + dns_name_t *name, dns_ttl_t ttl, + dns_rdata_t *rdata); static void zone_unload(dns_zone_t *zone); static void zone_expire(dns_zone_t *zone); static void zone_iattach(dns_zone_t *source, dns_zone_t **target); @@ -718,6 +743,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { isc_time_settoepoch(&zone->keywarntime); isc_time_settoepoch(&zone->signingtime); isc_time_settoepoch(&zone->nsec3chaintime); + isc_time_settoepoch(&zone->refreshkeytime); + zone->refreshkeycount = 0; zone->serial = 0; zone->refresh = DNS_ZONE_DEFAULTREFRESH; zone->retry = DNS_ZONE_DEFAULTRETRY; @@ -1293,6 +1320,7 @@ zone_isdynamic(dns_zone_t *zone) { return (ISC_TF(zone->type == dns_zone_slave || zone->type == dns_zone_stub || + zone->type == dns_zone_key || (!zone->update_disabled && zone->ssutable != NULL) || (!zone->update_disabled && zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)))); @@ -1360,7 +1388,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) { */ if (zone->masterfile != NULL) { /* - * The file is already loaded. If we are just doing a + * The file is already loaded. If we are just doing a * "rndc reconfig", we are done. */ if (!isc_time_isepoch(&zone->loadtime) && @@ -1477,6 +1505,8 @@ get_master_options(dns_zone_t *zone) { options = DNS_MASTER_ZONE; if (zone->type == dns_zone_slave) options |= DNS_MASTER_SLAVE; + if (zone->type == dns_zone_key) + options |= DNS_MASTER_KEY; if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) options |= DNS_MASTER_CHECKNS; if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) @@ -2049,7 +2079,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) { /* * OpenSSL verification of RSA keys with exponent 3 is known to be - * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn + * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn * if they are in use. */ static void @@ -2299,7 +2329,7 @@ set_resigntime(dns_zone_t *zone) { dns_rdataset_init(&rdataset); dns_fixedname_init(&fixed); - result = dns_db_getsigningtime(zone->db, &rdataset, + result = dns_db_getsigningtime(zone->db, &rdataset, dns_fixedname_name(&fixed)); if (result != ISC_R_SUCCESS) { isc_time_settoepoch(&zone->resigntime); @@ -2403,6 +2433,588 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) { return (result); } +/* + * Set the timer for refreshing the key zone to the soonest future time + * of the set (current timer, keydata->refresh, keydata->addhd, + * keydata->removehd). + */ +static void +set_refreshkeytimer(dns_zone_t *zone, dns_rdata_keydata_t *key, + isc_stdtime_t now) { + const char me[] = "set_refreshkeytimer"; + isc_stdtime_t then; + isc_time_t timenow, timethen; + + ENTER; + then = key->refresh; + if (key->addhd > now && key->addhd < then) + then = key->addhd; + if (key->removehd > now && key->removehd < then) + then = key->removehd; + + isc_time_set(&timenow, now, 0); + isc_time_set(&timethen, ISC_MAX(then, now), 0); + if (isc_time_compare(&zone->refreshkeytime, &timenow) < 0 || + isc_time_compare(&timethen, &zone->refreshkeytime) < 0) { + zone->refreshkeytime = timethen; + } + zone_settimer(zone, &timenow); +} + +/* + * Convert key(s) linked from 'keynode' to KEYDATA and add to the key zone. + * If the key zone is changed, set '*changed' to ISC_TRUE. + */ +static isc_result_t +create_keydata(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, dns_name_t *name, dns_keytable_t *keytable, + dns_keynode_t *keynode, isc_boolean_t *changed) +{ + const char me[] = "create_keydata"; + isc_result_t result = ISC_R_SUCCESS; + isc_buffer_t keyb, dstb; + unsigned char key_buf[4096], dst_buf[DST_KEY_MAXSIZE]; + dns_rdata_keydata_t keydata; + dns_rdata_dnskey_t dnskey; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_keynode_t *nextnode = NULL; + isc_stdtime_t now; + isc_region_t r; + dst_key_t *key; + + ENTER; + isc_stdtime_get(&now); + + /* Loop in case there's more than one key. */ + while (result == ISC_R_SUCCESS) { + key = dns_keynode_key(keynode); + if (key == NULL) + goto skip; + + isc_buffer_init(&dstb, dst_buf, sizeof(dst_buf)); + CHECK(dst_key_todns(key, &dstb)); + + /* Convert DST key to DNSKEY. */ + dns_rdata_reset(&rdata); + isc_buffer_usedregion(&dstb, &r); + dns_rdata_fromregion(&rdata, dst_key_class(key), + dns_rdatatype_dnskey, &r); + + /* DSTKEY to KEYDATA. */ + dns_rdata_tostruct(&rdata, &dnskey, NULL); + dns_keydata_fromdnskey(&keydata, &dnskey, now, 0, 0, NULL); + + /* KEYDATA to rdata. */ + dns_rdata_reset(&rdata); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&rdata, + zone->rdclass, dns_rdatatype_keydata, + &keydata, &keyb); + + /* Add rdata to zone. */ + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, + name, 0, &rdata)); + *changed = ISC_TRUE; + + skip: + result = dns_keytable_nextkeynode(keytable, keynode, &nextnode); + if(result != ISC_R_NOTFOUND) { + dns_keytable_detachkeynode(keytable, &keynode); + keynode = nextnode; + } + } + + /* Refresh new keys from the zone apex as soon as possible. */ + if (*changed) + set_refreshkeytimer(zone, &keydata, now); + + return (ISC_R_SUCCESS); + + failure: + return (result); +} + +/* + * Remove from the key zone all the KEYDATA records found in rdataset. + */ +static isc_result_t +delete_keydata(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, + dns_name_t *name, dns_rdataset_t *rdataset) +{ + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result, uresult; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + uresult = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, + name, 0, &rdata); + if (uresult != ISC_R_SUCCESS) + return (uresult); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + return (result); +} + +/* + * Compute the DNSSEC key ID for a DNSKEY record. + */ +static isc_result_t +compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx, + dns_keytag_t *tag) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char data[4096]; + isc_buffer_t buffer; + dst_key_t *dstkey = NULL; + + isc_buffer_init(&buffer, data, sizeof(data)); + dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, + dns_rdatatype_dnskey, dnskey, &buffer); + + result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &dstkey); + if (result == ISC_R_SUCCESS) + *tag = dst_key_id(dstkey); + dst_key_free(&dstkey); + + return (result); +} + +/* + * Add key to the security roots for all views. + */ +static void +trust_key(dns_viewlist_t *viewlist, dns_name_t *keyname, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char data[4096]; + isc_buffer_t buffer; + dns_view_t *view; + + /* Convert dnskey to DST key. */ + isc_buffer_init(&buffer, data, sizeof(data)); + dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, + dns_rdatatype_dnskey, dnskey, &buffer); + + for (view = ISC_LIST_HEAD(*viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->secroots != NULL) { + dst_key_t *key = NULL; + CHECK(dns_dnssec_keyfromrdata(keyname, &rdata, + mctx, &key)); + CHECK(dns_keytable_add(view->secroots, ISC_TRUE, &key)); + } + } + + failure: + return; +} + +/* + * Remove key from the security roots for all views. + */ +static void +untrust_key(dns_viewlist_t *viewlist, dns_name_t *keyname, isc_mem_t *mctx, + dns_rdata_dnskey_t *dnskey) +{ + isc_result_t result; + unsigned char data[4096]; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t buffer; + dns_view_t *view; + dst_key_t *key = NULL; + + /* + * Clear the revoke bit, if set, so that the key will match what's + * in secroots now. + */ + dnskey->flags &= ~DNS_KEYFLAG_REVOKE; + + /* Convert dnskey to DST key. */ + isc_buffer_init(&buffer, data, sizeof(data)); + dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, + dns_rdatatype_dnskey, dnskey, &buffer); + result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key); + if (result != ISC_R_SUCCESS) + return; + + for (view = ISC_LIST_HEAD(*viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->secroots == NULL) + continue; + dns_keytable_deletekeynode(view->secroots, key); + } + + dst_key_free(&key); +} + +/* + * Add a null key to the security roots for all views, so that all queries + * to the zone will fail. + */ +static void +fail_secure(dns_viewlist_t *viewlist, dns_name_t *keyname) { + dns_view_t *view; + + for (view = ISC_LIST_HEAD(*viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->secroots != NULL) + dns_keytable_marksecure(view->secroots, keyname); + } +} + +/* + * Scan a set of KEYDATA records from the key zone. The ones that are + * valid (i.e., the add holddown timer has expired) become trusted keys for + * all views. + */ +static void +load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t keydata; + dns_rdata_dnskey_t dnskey; + isc_mem_t *mctx = zone->mctx; + dns_view_t *view = zone->view; + dns_viewlist_t *viewlist = view->viewlist; + int trusted = 0, revoked = 0, pending = 0; + isc_stdtime_t now; + + isc_stdtime_get(&now); + + /* For each view, delete references to this key from secroots. */ + for (view = ISC_LIST_HEAD(*viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->secroots != NULL) + dns_keytable_delete(view->secroots, name); + } + + /* Now insert all the accepted trust anchors from this keydata set. */ + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + + /* Convert rdata to keydata. */ + dns_rdata_tostruct(&rdata, &keydata, NULL); + + /* Set the key refresh timer. */ + set_refreshkeytimer(zone, &keydata, now); + + /* If the removal timer is nonzero, this key was revoked. */ + if (keydata.removehd != 0) { + revoked++; + continue; + } + + /* + * If the add timer is still pending, this key is not + * trusted yet. + */ + if (now < keydata.addhd) { + pending++; + continue; + } + + /* Convert keydata to dnskey. */ + dns_keydata_todnskey(&keydata, &dnskey, NULL); + + /* Add to keytables. */ + trusted++; + trust_key(viewlist, name, &dnskey, mctx); + } + + if (trusted == 0 && pending != 0) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namebuf, sizeof namebuf); + dns_zone_log(zone, ISC_LOG_ERROR, + "No valid trust anchors for '%s'!", namebuf); + dns_zone_log(zone, ISC_LOG_ERROR, + "%d key(s) revoked, %d still pending", + revoked, pending); + dns_zone_log(zone, ISC_LOG_ERROR, + "All queries to '%s' will fail", namebuf); + fail_secure(viewlist, name); + } +} + +static isc_result_t +do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff) +{ + dns_diff_t temp_diff; + isc_result_t result; + + /* + * Create a singleton diff. + */ + dns_diff_init(diff->mctx, &temp_diff); + temp_diff.resign = diff->resign; + ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); + + /* + * Apply it to the database. + */ + result = dns_diff_apply(&temp_diff, db, ver); + ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); + if (result != ISC_R_SUCCESS) { + dns_difftuple_free(tuple); + return (result); + } + + /* + * Merge it into the current pending journal entry. + */ + dns_diff_appendminimal(diff, tuple); + + /* + * Do not clear temp_diff. + */ + return (ISC_R_SUCCESS); +} + +static isc_result_t +update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, + dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, + dns_rdata_t *rdata) +{ + dns_difftuple_t *tuple = NULL; + isc_result_t result; + result = dns_difftuple_create(diff->mctx, op, + name, ttl, rdata, &tuple); + if (result != ISC_R_SUCCESS) + return (result); + return (do_one_tuple(&tuple, db, ver, diff)); +} + +static isc_result_t +increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, isc_mem_t *mctx) { + dns_difftuple_t *deltuple = NULL; + dns_difftuple_t *addtuple = NULL; + isc_uint32_t serial; + isc_result_t result; + + CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); + CHECK(dns_difftuple_copy(deltuple, &addtuple)); + addtuple->op = DNS_DIFFOP_ADD; + + serial = dns_soa_getserial(&addtuple->rdata); + + /* RFC1982 */ + serial = (serial + 1) & 0xFFFFFFFF; + if (serial == 0) + serial = 1; + + dns_soa_setserial(serial, &addtuple->rdata); + CHECK(do_one_tuple(&deltuple, db, ver, diff)); + CHECK(do_one_tuple(&addtuple, db, ver, diff)); + result = ISC_R_SUCCESS; + + failure: + if (addtuple != NULL) + dns_difftuple_free(&addtuple); + if (deltuple != NULL) + dns_difftuple_free(&deltuple); + return (result); +} + +/* + * Write all transactions in 'diff' to the zone journal file. + */ +static void +zone_journal(dns_zone_t *zone, dns_diff_t *diff, const char *caller) { + const char me[] = "zone_journal"; + const char *journalfile; + isc_result_t result; + dns_journal_t *journal = NULL; + + ENTER; + journalfile = dns_zone_getjournal(zone); + if (journalfile != NULL) { + result = dns_journal_open(zone->mctx, journalfile, + ISC_TRUE, &journal); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s:dns_journal_open -> %s\n", + caller, dns_result_totext(result)); + return; + } + + result = dns_journal_write_transaction(journal, diff); + dns_journal_destroy(&journal); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s:dns_journal_write_transaction -> %s\n", + caller, dns_result_totext(result)); + return; + } + } +} + +/* + * Synchronize the set of initializing keys found in managed-keys {} + * statements with the set of trust anchors found in the managed-keys.bind + * zone. If a domain is no longer named in managed-keys, delete all keys + * from that domain from the key zone. If a domain is mentioned in in + * managed-keys but there are no references to it in the key zone, load + * the key zone with the initializing key(s) for that domain. + */ +static isc_result_t +sync_keyzone(dns_zone_t *zone, dns_db_t *db, isc_boolean_t addsoa) { + isc_result_t result = ISC_R_SUCCESS; + isc_boolean_t changed = ISC_FALSE; + dns_rbtnodechain_t chain; + dns_fixedname_t fn; + dns_name_t foundname, *origin; + dns_keynode_t *keynode = NULL; + dns_view_t *view = zone->view; + dns_keytable_t *sr = view->secroots; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + dns_rriterator_t rrit; + + dns_zone_log(zone, ISC_LOG_DEBUG(1), "synchronizing trusted keys"); + + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fn); + origin = dns_fixedname_name(&fn); + + dns_diff_init(zone->mctx, &diff); + result = dns_db_newversion(db, &ver); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sync_keyzone:dns_db_newversion -> %s\n", + dns_result_totext(result)); + goto failure; + } + + if (addsoa) { + /* If this zone is being newly created, make an SOA record. */ + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_zone_log(zone, ISC_LOG_DEBUG(1), "creating key zone"); + + result = dns_soa_buildrdata(&zone->origin, dns_rootname, + zone->rdclass, + 0, 0, 0, 0, 0, &rdata); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sync_keyzone:dns_soa_buildrdata -> %s\n", + dns_result_totext(result)); + goto failure; + } + + CHECK(update_one_rr(db, ver, &diff, DNS_DIFFOP_ADD, + &zone->origin, 0, &rdata)); + } else { + /* + * Zone is not new, so walk the zone DB; if we find any keys + * whose names are no longer in managed-keys (or *are* + * in trusted-keys, meaning they are permanent and not + * RFC5011-maintained), delete them from the zone. Otherwise + * call load_secroots(), which loads keys into secroots as + * appropriate. + */ + dns_rriterator_init(&rrit, db, ver, 0); + for (result = dns_rriterator_first(&rrit); + result == ISC_R_SUCCESS; + result = dns_rriterator_nextrrset(&rrit)) { + dns_rdataset_t *rdataset; + dns_name_t *rrname = NULL; + isc_uint32_t ttl; + + dns_rriterator_current(&rrit, &rrname, &ttl, + &rdataset, NULL); + if (!dns_rdataset_isassociated(rdataset)) { + dns_rriterator_destroy(&rrit); + goto failure; + } + + if (rdataset->type != dns_rdatatype_keydata) + continue; + + result = dns_keytable_find(sr, rrname, &keynode); + + if ((result != ISC_R_SUCCESS && + result != DNS_R_PARTIALMATCH) || + dns_keynode_managed(keynode) == ISC_FALSE) { + CHECK(delete_keydata(db, ver, &diff, + rrname, rdataset)); + } else { + load_secroots(zone, rrname, rdataset); + } + + if (keynode != NULL) + dns_keytable_detachkeynode(sr, &keynode); + } + + dns_rriterator_destroy(&rrit); + } + + /* + * Now walk secroots to find any managed keys that aren't + * in the zone. If we find any, we add them to the zone. + */ + RWLOCK(&sr->rwlock, isc_rwlocktype_write); + dns_rbtnodechain_init(&chain, zone->mctx); + result = dns_rbtnodechain_first(&chain, sr->table, &foundname, origin); + if (result == ISC_R_NOTFOUND) + result = ISC_R_NOMORE; + while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { + dns_rbtnode_t *rbtnode = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &rbtnode); + keynode = rbtnode->data; + if (dns_keynode_managed(keynode)) { + dns_fixedname_t fname; + dns_fixedname_init(&fname); + dst_key_t *key = dns_keynode_key(keynode); + dns_name_t *keyname; + if (key == NULL) /* fail_secure() was called. */ + goto skip; + keyname = dst_key_name(key); + result = dns_db_find(db, keyname, ver, + dns_rdatatype_keydata, + DNS_DBFIND_NOWILD, 0, NULL, + dns_fixedname_name(&fname), + NULL, NULL); + if (result != ISC_R_SUCCESS) + result = create_keydata(zone, db, ver, &diff, + keyname, sr, keynode, + &changed); + if (result != ISC_R_SUCCESS) + break; + } + skip: + result = dns_rbtnodechain_next(&chain, &foundname, origin); + } + RWUNLOCK(&sr->rwlock, isc_rwlocktype_write); + + if (changed) { + /* Write changes to journal file. */ + result = increment_soa_serial(db, ver, &diff, zone->mctx); + if (result == ISC_R_SUCCESS) + zone_journal(zone, &diff, "sync_keyzone"); + + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); + zone_needdump(zone, 30); + } + + failure: + if (ver != NULL) + dns_db_closeversion(db, &ver, changed); + dns_diff_clear(&diff); + + return (result); +} + static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_result_t result) @@ -2435,12 +3047,15 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, "failed: %s", zone->masterfile, dns_result_totext(result)); - } else + } else { dns_zone_log(zone, ISC_LOG_ERROR, "loading from master file %s failed: %s", zone->masterfile, dns_result_totext(result)); - goto cleanup; + } + + if (zone->type != dns_zone_key) + goto cleanup; } dns_zone_log(zone, ISC_LOG_DEBUG(2), @@ -2498,7 +3113,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, result = zone_get_from_db(zone, db, &nscount, &soacount, &serial, &refresh, &retry, &expire, &minimum, &errors); - if (result != ISC_R_SUCCESS) { + if (result != ISC_R_SUCCESS && zone->type != dns_zone_key) { dns_zone_log(zone, ISC_LOG_ERROR, "could not find NS and/or SOA records"); } @@ -2616,6 +3231,13 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, zone->refreshtime = now; } break; + + case dns_zone_key: + result = sync_keyzone(zone, db, ISC_TF(soacount == 0)); + if (result != ISC_R_SUCCESS) + goto cleanup; + break; + default: UNEXPECTED_ERROR(__FILE__, __LINE__, "unexpected zone type %d", zone->type); @@ -2653,9 +3275,12 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); } + result = ISC_R_SUCCESS; + if (needdump) zone_needdump(zone, DNS_DUMP_DELAY); + if (zone->task != NULL) { if (zone->type == dns_zone_master) { set_resigntime(zone); @@ -2674,7 +3299,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, cleanup: if (zone->type == dns_zone_slave || - zone->type == dns_zone_stub) { + zone->type == dns_zone_stub || + zone->type == dns_zone_key) { if (zone->journal != NULL) zone_saveunique(zone, zone->journal, "jn-XXXXXXXX"); if (zone->masterfile != NULL) @@ -2972,7 +3598,7 @@ dns_zone_detach(dns_zone_t **zonep) { */ if (zone->task != NULL) { /* - * This zone is being managed. Post + * This zone is being managed. Post * its control event and let it clean * up synchronously in the context of * its task. @@ -3478,88 +4104,6 @@ was_dumping(dns_zone_t *zone) { #define MAXZONEKEYS 10 -static isc_result_t -do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, - dns_diff_t *diff) -{ - dns_diff_t temp_diff; - isc_result_t result; - - /* - * Create a singleton diff. - */ - dns_diff_init(diff->mctx, &temp_diff); - temp_diff.resign = diff->resign; - ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); - - /* - * Apply it to the database. - */ - result = dns_diff_apply(&temp_diff, db, ver); - ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); - if (result != ISC_R_SUCCESS) { - dns_difftuple_free(tuple); - return (result); - } - - /* - * Merge it into the current pending journal entry. - */ - dns_diff_appendminimal(diff, tuple); - - /* - * Do not clear temp_diff. - */ - return (ISC_R_SUCCESS); -} - -static isc_result_t -increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, - dns_diff_t *diff, isc_mem_t *mctx) -{ - dns_difftuple_t *deltuple = NULL; - dns_difftuple_t *addtuple = NULL; - isc_uint32_t serial; - isc_result_t result; - - CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); - CHECK(dns_difftuple_copy(deltuple, &addtuple)); - addtuple->op = DNS_DIFFOP_ADD; - - serial = dns_soa_getserial(&addtuple->rdata); - - /* RFC1982 */ - serial = (serial + 1) & 0xFFFFFFFF; - if (serial == 0) - serial = 1; - - dns_soa_setserial(serial, &addtuple->rdata); - CHECK(do_one_tuple(&deltuple, db, ver, diff)); - CHECK(do_one_tuple(&addtuple, db, ver, diff)); - result = ISC_R_SUCCESS; - - failure: - if (addtuple != NULL) - dns_difftuple_free(&addtuple); - if (deltuple != NULL) - dns_difftuple_free(&deltuple); - return (result); -} - -static isc_result_t -update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, - dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, - dns_rdata_t *rdata) -{ - dns_difftuple_t *tuple = NULL; - isc_result_t result; - result = dns_difftuple_create(diff->mctx, op, - name, ttl, rdata, &tuple); - if (result != ISC_R_SUCCESS) - return (result); - return (do_one_tuple(&tuple, db, ver, diff)); -} - static isc_boolean_t ksk_sanity(dns_db_t *db, dns_dbversion_t *ver) { isc_boolean_t ret = ISC_FALSE; @@ -3839,7 +4383,6 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, static void zone_resigninc(dns_zone_t *zone) { - const char *journalfile; dns_db_t *db = NULL; dns_dbversion_t *version = NULL; dns_diff_t sig_diff; @@ -3955,7 +4498,7 @@ zone_resigninc(dns_zone_t *zone) { dns_result_totext(result)); break; } - result = dns_db_getsigningtime(db, &rdataset, + result = dns_db_getsigningtime(db, &rdataset, dns_fixedname_name(&fixed)); if (nkeys == 0 && result == ISC_R_NOTFOUND) { result = ISC_R_SUCCESS; @@ -4001,31 +4544,10 @@ zone_resigninc(dns_zone_t *zone) { goto failure; } - journalfile = dns_zone_getjournal(zone); - if (journalfile != NULL) { - dns_journal_t *journal = NULL; - result = dns_journal_open(zone->mctx, journalfile, - ISC_TRUE, &journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_resigninc:dns_journal_open -> %s\n", - dns_result_totext(result)); - goto failure; - } + /* Write changes to journal file. */ + zone_journal(zone, &sig_diff, "zone_resigninc"); - result = dns_journal_write_transaction(journal, &sig_diff); - dns_journal_destroy(&journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_resigninc:dns_journal_write_transaction -> %s\n", - dns_result_totext(result)); - goto failure; - } - } - - /* - * Everything has succeeded. Commit the changes. - */ + /* Everything has succeeded. Commit the changes. */ dns_db_closeversion(db, &version, ISC_TRUE); failure: @@ -4652,7 +5174,6 @@ need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, */ static void zone_nsec3chain(dns_zone_t *zone) { - const char *journalfile; dns_db_t *db = NULL; dns_dbnode_t *node = NULL; dns_dbversion_t *version = NULL; @@ -5242,27 +5763,8 @@ zone_nsec3chain(dns_zone_t *zone) { goto failure; } - journalfile = dns_zone_getjournal(zone); - if (journalfile != NULL) { - dns_journal_t *journal = NULL; - result = dns_journal_open(zone->mctx, journalfile, - ISC_TRUE, &journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "dns_journal_open -> %s\n", - dns_result_totext(result)); - goto failure; - } - - result = dns_journal_write_transaction(journal, &sig_diff); - dns_journal_destroy(&journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "dns_journal_write_transaction -> %s\n", - dns_result_totext(result)); - goto failure; - } - } + /* Write changes to journal file. */ + zone_journal(zone, &sig_diff, "zone_nsec3chain"); LOCK_ZONE(zone); zone_needdump(zone, DNS_DUMP_DELAY); @@ -5447,7 +5949,6 @@ del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, */ static void zone_sign(dns_zone_t *zone) { - const char *journalfile; dns_db_t *db = NULL; dns_dbnode_t *node = NULL; dns_dbversion_t *version = NULL; @@ -5577,7 +6078,7 @@ zone_sign(dns_zone_t *zone) { ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (signing->done || signing->db != zone->db) { /* - * The zone has been reloaded. We will have + * The zone has been reloaded. We will have * created new signings as part of the reload * process so we can destroy this one. */ @@ -5696,7 +6197,8 @@ zone_sign(dns_zone_t *zone) { &sig_diff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "updatesignwithkey -> %s\n", + "updatesignwithkey " + "-> %s\n", dns_result_totext(result)); goto failure; } @@ -5804,28 +6306,8 @@ zone_sign(dns_zone_t *zone) { goto failure; } - journalfile = dns_zone_getjournal(zone); - if (journalfile != NULL) { - dns_journal_t *journal = NULL; - result = dns_journal_open(zone->mctx, journalfile, - ISC_TRUE, &journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:dns_journal_open -> %s\n", - dns_result_totext(result)); - goto failure; - } - - result = dns_journal_write_transaction(journal, &sig_diff); - dns_journal_destroy(&journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:dns_journal_write_transaction -> %s\n", - dns_result_totext(result)); - goto failure; - } - } - + /* Write changes to journal file. */ + zone_journal(zone, &sig_diff, "zone_sign"); /* * Pause all iterators so that dns_db_closeversion() can succeed. @@ -5903,6 +6385,788 @@ zone_sign(dns_zone_t *zone) { isc_time_settoepoch(&zone->signingtime); } +static void +normalize_key(dns_rdata_t *rr, dns_rdata_t *target, + unsigned char *data, int size) { + dns_rdata_dnskey_t dnskey; + dns_rdata_keydata_t keydata; + isc_buffer_t buf; + + dns_rdata_reset(target); + isc_buffer_init(&buf, data, size); + + switch (rr->type) { + case dns_rdatatype_dnskey: + dns_rdata_tostruct(rr, &dnskey, NULL); + dnskey.flags &= ~DNS_KEYFLAG_REVOKE; + dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, + &dnskey, &buf); + break; + case dns_rdatatype_keydata: + dns_rdata_tostruct(rr, &keydata, NULL); + dns_keydata_todnskey(&keydata, &dnskey, NULL); + dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, + &dnskey, &buf); + break; + default: + INSIST(0); + } +} + +/* + * 'rdset' contains either a DNSKEY rdataset from the zone apex, or + * a KEYDATA rdataset from the key zone. + * + * 'rr' contains either a DNSKEY record, or a KEYDATA record + * + * After normalizing keys to the same format (DNSKEY, with revoke bit + * cleared), return ISC_TRUE if a key that matches 'rr' is found in + * 'rdset', or ISC_FALSE if not. + */ + +static isc_boolean_t +matchkey(dns_rdataset_t *rdset, dns_rdata_t *rr) { + unsigned char data1[4096], data2[4096]; + dns_rdata_t rdata, rdata1, rdata2; + isc_result_t result; + + dns_rdata_init(&rdata); + dns_rdata_init(&rdata1); + dns_rdata_init(&rdata2); + + normalize_key(rr, &rdata1, data1, sizeof(data1)); + + for (result = dns_rdataset_first(rdset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdset, &rdata); + normalize_key(&rdata, &rdata2, data2, sizeof(data2)); + if (dns_rdata_compare(&rdata1, &rdata2) == 0) + return (ISC_TRUE); + } + + return (ISC_FALSE); +} + +/* + * Calculate the refresh interval for a keydata zone, per + * RFC5011: MAX(1 hr, + * MIN(15 days, + * 1/2 * OrigTTL, + * 1/2 * RRSigExpirationInterval)) + */ +static inline isc_stdtime_t +refresh_time(dns_keyfetch_t *kfetch) { + isc_result_t result; + isc_uint32_t t; + dns_rdataset_t *rdset; + dns_rdata_t sigrr = DNS_RDATA_INIT; + dns_rdata_sig_t sig; + isc_stdtime_t now; + + isc_stdtime_get(&now); + + if (dns_rdataset_isassociated(&kfetch->dnskeysigset)) + rdset = &kfetch->dnskeysigset; + else + return (now + HOUR); + + result = dns_rdataset_first(rdset); + if (result != ISC_R_SUCCESS) + return (now + HOUR); + + dns_rdataset_current(rdset, &sigrr); + result = dns_rdata_tostruct(&sigrr, &sig, NULL); + + t = sig.originalttl / 2; + + if (isc_serial_gt(sig.timeexpire, now)) { + isc_uint32_t exp = (sig.timeexpire - now) / 2; + if (t > exp) + t = exp; + } + + if (t > (15*DAY)) + t = (15*DAY); + + if (t < HOUR) + t = HOUR; + + return (now + t); +} + +/* + * This routine is called when no changes are needed in a KEYDATA + * record except to simply update the refresh timer. Caller should + * hold zone lock. + */ +static isc_result_t +minimal_update(dns_keyfetch_t *kfetch, dns_dbversion_t *ver, dns_diff_t *diff) { + isc_result_t result; + isc_buffer_t keyb; + unsigned char key_buf[4096]; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t keydata; + dns_name_t *name; + dns_zone_t *zone = kfetch->zone; + isc_stdtime_t now; + + name = dns_fixedname_name(&kfetch->name); + isc_stdtime_get(&now); + + for (result = dns_rdataset_first(&kfetch->keydataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->keydataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(&kfetch->keydataset, &rdata); + + /* Delete old version */ + CHECK(update_one_rr(kfetch->db, ver, diff, DNS_DIFFOP_DEL, + name, 0, &rdata)); + + /* Update refresh timer */ + dns_rdata_tostruct(&rdata, &keydata, NULL); + keydata.refresh = refresh_time(kfetch); + set_refreshkeytimer(zone, &keydata, now); + + dns_rdata_reset(&rdata); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&rdata, + zone->rdclass, dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert updated version */ + CHECK(update_one_rr(kfetch->db, ver, diff, DNS_DIFFOP_ADD, + name, 0, &rdata)); + } + result = ISC_R_SUCCESS; + failure: + return (result); +} + +/* + * Verify that DNSKEY set is signed by the key specified in 'keydata'. + */ +static isc_boolean_t +revocable(dns_keyfetch_t *kfetch, dns_rdata_keydata_t *keydata) { + isc_result_t result; + dns_name_t *keyname; + isc_mem_t *mctx; + dns_rdata_t sigrr = DNS_RDATA_INIT; + dns_rdata_t rr = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig; + dns_rdata_dnskey_t dnskey; + dst_key_t *dstkey = NULL; + unsigned char key_buf[4096]; + isc_buffer_t keyb; + isc_boolean_t answer = ISC_FALSE; + + REQUIRE(kfetch != NULL && keydata != NULL); + REQUIRE(dns_rdataset_isassociated(&kfetch->dnskeysigset)); + + keyname = dns_fixedname_name(&kfetch->name); + mctx = kfetch->zone->view->mctx; + + /* Generate a key from keydata */ + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_keydata_todnskey(keydata, &dnskey, NULL); + dns_rdata_fromstruct(&rr, keydata->common.rdclass, dns_rdatatype_dnskey, + &dnskey, &keyb); + result = dns_dnssec_keyfromrdata(keyname, &rr, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + + /* See if that key generated any of the signatures */ + for (result = dns_rdataset_first(&kfetch->dnskeysigset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->dnskeysigset)) { + dns_fixedname_t fixed; + dns_fixedname_init(&fixed); + + dns_rdata_reset(&sigrr); + dns_rdataset_current(&kfetch->dnskeysigset, &sigrr); + result = dns_rdata_tostruct(&sigrr, &sig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if (dst_key_alg(dstkey) == sig.algorithm && + (dst_key_id(dstkey) == sig.keyid || + (sig.algorithm != 1 && sig.keyid == + ((dst_key_id(dstkey) + 128) & 0xffff)))) { + result = dns_dnssec_verify2(keyname, + &kfetch->dnskeyset, + dstkey, ISC_FALSE, mctx, &sigrr, + dns_fixedname_name(&fixed)); + + dns_zone_log(kfetch->zone, ISC_LOG_DEBUG(3), + "Confirm revoked DNSKEY is self-signed: " + "%s", dns_result_totext(result)); + + if (result == ISC_R_SUCCESS) { + answer = ISC_TRUE; + break; + } + } + } + + dst_key_free(&dstkey); + return (answer); +} + +/* + * A DNSKEY set has been fetched from the zone apex of a zone whose trust + * anchors are being managed; scan the keyset, and update the key zone and the + * local trust anchors according to RFC5011. + */ +static void +keyfetch_done(isc_task_t *task, isc_event_t *event) { + isc_result_t result, eresult; + dns_fetchevent_t *devent; + dns_keyfetch_t *kfetch; + dns_zone_t *zone; + dns_keytable_t *secroots; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + isc_boolean_t changed = ISC_FALSE; + isc_boolean_t alldone = ISC_FALSE; + dns_name_t *keyname; + dns_rdata_t sigrr = DNS_RDATA_INIT; + dns_rdata_t dnskeyrr = DNS_RDATA_INIT; + dns_rdata_t keydatarr = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig; + dns_rdata_dnskey_t dnskey; + dns_rdata_keydata_t keydata; + isc_boolean_t initializing; + char namebuf[DNS_NAME_FORMATSIZE]; + unsigned char key_buf[4096]; + isc_buffer_t keyb; + dst_key_t *dstkey; + isc_stdtime_t now; + int pending = 0; + + UNUSED(task); + INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE); + INSIST(event->ev_arg != NULL); + + kfetch = event->ev_arg; + zone = kfetch->zone; + secroots = zone->view->secroots; + keyname = dns_fixedname_name(&kfetch->name); + + devent = (dns_fetchevent_t *) event; + eresult = devent->result; + + /* Free resources which are not of interest */ + if (devent->node != NULL) + dns_db_detachnode(devent->db, &devent->node); + if (devent->db != NULL) + dns_db_detach(&devent->db); + isc_event_free(&event); + dns_resolver_destroyfetch(&kfetch->fetch); + + isc_stdtime_get(&now); + dns_name_format(keyname, namebuf, sizeof(namebuf)); + + LOCK_ZONE(zone); + dns_db_newversion(kfetch->db, &ver); + dns_diff_init(zone->mctx, &diff); + + /* Fetch failed */ + if (eresult != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Unable to fetch DNSKEY set " + "'%s': %s", namebuf, dns_result_totext(eresult)); + CHECK(minimal_update(kfetch, ver, &diff)); + goto failure; + } + + /* + * Validate the dnskeyset against the current trusted keys. + * (Note, if a key has been revoked and isn't RSAMD5, then + * its key ID will have changed.) + */ + for (result = dns_rdataset_first(&kfetch->dnskeysigset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->dnskeysigset)) { + dns_keynode_t *keynode = NULL; + + dns_rdata_reset(&sigrr); + dns_rdataset_current(&kfetch->dnskeysigset, &sigrr); + result = dns_rdata_tostruct(&sigrr, &sig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + result = dns_keytable_find(secroots, keyname, &keynode); + while (result == ISC_R_SUCCESS) { + dns_keynode_t *nextnode = NULL; + dns_fixedname_t fixed; + dns_fixedname_init(&fixed); + + dstkey = dns_keynode_key(keynode); + if (dstkey == NULL) /* fail_secure() was called */ + break; + + if (dst_key_alg(dstkey) == sig.algorithm && + (dst_key_id(dstkey) == sig.keyid || + (sig.algorithm != 1 && sig.keyid == + ((dst_key_id(dstkey) + 128) & 0xffff)))) { + result = dns_dnssec_verify2(keyname, + &kfetch->dnskeyset, + dstkey, ISC_FALSE, + zone->view->mctx, &sigrr, + dns_fixedname_name(&fixed)); + + dns_zone_log(zone, ISC_LOG_DEBUG(3), + "Verifying DNSKEY set for zone " + "'%s': %s", namebuf, + dns_result_totext(result)); + + if (result == ISC_R_SUCCESS) { + kfetch->dnskeyset.trust = + dns_trust_secure; + kfetch->dnskeysigset.trust = + dns_trust_secure; + dns_keytable_detachkeynode(secroots, + &keynode); + break; + } + } + + result = dns_keytable_nextkeynode(secroots, + keynode, &nextnode); + dns_keytable_detachkeynode(secroots, &keynode); + keynode = nextnode; + } + + if (kfetch->dnskeyset.trust == dns_trust_secure) + break; + } + + /* Failed to validate? Let's go home. */ + if (kfetch->dnskeyset.trust != dns_trust_secure) { + dns_zone_log(zone, ISC_LOG_WARNING, + "DNSKEY set for zone '%s' failed to validate", + namebuf); + CHECK(minimal_update(kfetch, ver, &diff)); + changed = ISC_TRUE; + goto failure; + } + + /* + * First scan keydataset to find keys that are not in dnskeyset + * - Missing keys which are not scheduled for removal, + * log a warning + * - Missing keys which are scheduled for removal and + * the remove hold-down timer has completed should + * be removed from the key zone + * - Missing keys whose acceptance timers have not yet + * completed, log a warning and reset the acceptance + * timer to 30 days in the future + * - All keys not being removed have their refresh timers + * updated + */ + initializing = ISC_TRUE; + for (result = dns_rdataset_first(&kfetch->keydataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->keydataset)) { + dns_rdata_reset(&keydatarr); + dns_rdataset_current(&kfetch->keydataset, &keydatarr); + dns_rdata_tostruct(&keydatarr, &keydata, NULL); + + /* + * If any keydata record has a nonzero add holddown, then + * there was a pre-existing trust anchor for this domain; + * that means we are *not* initializing it and shouldn't + * automatically trust all the keys we find at the zone apex. + */ + initializing = initializing && ISC_TF(keydata.addhd == 0); + + if (! matchkey(&kfetch->dnskeyset, &keydatarr)) { + isc_boolean_t deletekey = ISC_FALSE; + + if (now < keydata.addhd) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Pending key unexpectedly missing " + "from %s; restarting acceptance " + "timer", namebuf); + keydata.addhd = now + MONTH; + keydata.refresh = refresh_time(kfetch); + } else if (keydata.addhd == 0) { + keydata.addhd = now; + } else if (keydata.removehd == 0) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Active key unexpectedly missing " + "from %s", namebuf); + keydata.refresh = now + HOUR; + } else if (now > keydata.removehd) { + deletekey = ISC_TRUE; + } else { + keydata.refresh = refresh_time(kfetch); + } + + /* Delete old version */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_DEL, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + + if (deletekey) + continue; + + dns_rdata_reset(&keydatarr); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&keydatarr, zone->rdclass, + dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert updated version */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_ADD, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + + set_refreshkeytimer(zone, &keydata, now); + } + } + + /* + * Next scan dnskeyset: + * - If new keys are found (i.e., lacking a match in keydataset) + * add them to the key zone and set the acceptance timer + * to 30 days in the future (or to immediately if we've + * determined that we're initializing the zone for the + * first time) + * - Previously-known keys that have been revoked + * must be scheduled for removal from the key zone (or, + * if they hadn't been accepted as trust anchors yet + * anyway, removed at once) + * - Previously-known unrevoked keys whose acceptance timers + * have completed are promoted to trust anchors + * - All keys not being removed have their refresh + * timers updated + */ + for (result = dns_rdataset_first(&kfetch->dnskeyset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->dnskeyset)) { + isc_boolean_t revoked = ISC_FALSE; + isc_boolean_t newkey = ISC_FALSE; + isc_boolean_t updatekey = ISC_FALSE; + isc_boolean_t deletekey = ISC_FALSE; + isc_boolean_t trustkey = ISC_FALSE; + + dns_rdata_reset(&dnskeyrr); + dns_rdataset_current(&kfetch->dnskeyset, &dnskeyrr); + dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); + + /* Skip ZSK's */ + if (!ISC_TF(dnskey.flags & DNS_KEYFLAG_KSK)) + continue; + + revoked = ISC_TF(dnskey.flags & DNS_KEYFLAG_REVOKE); + + if (matchkey(&kfetch->keydataset, &dnskeyrr)) { + dns_rdata_reset(&keydatarr); + dns_rdataset_current(&kfetch->keydataset, &keydatarr); + dns_rdata_tostruct(&keydatarr, &keydata, NULL); + + if (revoked) { + if (keydata.addhd > now) { + /* + * Key wasn't trusted yet, and now + * it's been revoked? Just remove it + */ + deletekey = ISC_TRUE; + } else if (keydata.removehd == 0) { + /* + * Newly revoked key? Make sure + * it signed itself + */ + if(! revocable(kfetch, &keydata)) { + dns_zone_log(zone, + ISC_LOG_WARNING, + "Active key for zone " + "'%s' is revoked but " + "did not self-sign; " + "ignoring.", namebuf); + continue; + } + + /* Remove from secroots */ + untrust_key(zone->view->viewlist, + keyname, zone->mctx, + &dnskey); + + /* If initializing, delete now */ + if (keydata.addhd == 0) + deletekey = ISC_TRUE; + else + keydata.removehd = now + MONTH; + } else if (keydata.removehd < now) { + /* Scheduled for removal */ + deletekey = ISC_TRUE; + } + } else { + if (keydata.removehd != 0) { + /* + * Key isn't revoked--but it + * seems it used to be. + * Remove it now and add it + * back as if it were a fresh key. + */ + deletekey = ISC_TRUE; + newkey = ISC_TRUE; + } else if (keydata.addhd > now) + pending++; + else if (keydata.addhd == 0) + keydata.addhd = now; + + if (keydata.addhd <= now) + trustkey = ISC_TRUE; + } + + if (!deletekey && !newkey) + updatekey = ISC_TRUE; + } else { + /* + * Key wasn't in the key zone but it's + * revoked now anyway, so just skip it + */ + if (revoked) + continue; + + /* Key wasn't in the key zone: add it */ + newkey = ISC_TRUE; + + if (initializing) { + dns_keytag_t tag = 0; + CHECK(compute_tag(keyname, &dnskey, + zone->mctx, &tag)); + dns_zone_log(zone, ISC_LOG_WARNING, + "Initializing automatic trust " + "anchor management for zone '%s'; " + "DNSKEY ID %d is now trusted, " + "waiving the normal 30-day " + "waiting period.", + namebuf, tag); + trustkey = ISC_TRUE; + } + } + + /* Delete old version */ + if (deletekey || !newkey) { + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_DEL, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } + + if (updatekey) { + /* Set refresh timer */ + keydata.refresh = refresh_time(kfetch); + dns_rdata_reset(&keydatarr); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&keydatarr, zone->rdclass, + dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert updated version */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_ADD, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } else if (newkey) { + /* Convert DNSKEY to KEYDATA */ + dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); + dns_keydata_fromdnskey(&keydata, &dnskey, 0, 0, 0, + NULL); + keydata.addhd = initializing ? now : now + MONTH; + keydata.refresh = refresh_time(kfetch); + dns_rdata_reset(&keydatarr); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&keydatarr, zone->rdclass, + dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert into key zone */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_ADD, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } + + if (trustkey) { + /* Trust this key in all views */ + dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); + trust_key(zone->view->viewlist, keyname, &dnskey, + zone->mctx); + } + + if (!deletekey) + set_refreshkeytimer(zone, &keydata, now); + } + + /* + * RFC5011 says, "A trust point that has all of its trust anchors + * revoked is considered deleted and is treated as if the trust + * point was never configured." But if someone revoked their + * active key before the standby was trusted, that would mean the + * zone would suddenly be nonsecured. We avoid this by checking to + * see if there's pending keydata. If so, we put a null key in + * the security roots; then all queries to the zone will fail. + */ + if (pending != 0) + fail_secure(zone->view->viewlist, keyname); + + failure: + zone->refreshkeycount--; + alldone = ISC_TF(zone->refreshkeycount == 0); + + if (changed) { + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); + zone_needdump(zone, 30); + } + + if (alldone) + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING); + + UNLOCK_ZONE(zone); + + /* Write changes to journal file. */ + if (alldone) { + result = increment_soa_serial(kfetch->db, ver, &diff, + zone->mctx); + if (result == ISC_R_SUCCESS) + zone_journal(zone, &diff, "keyfetch_done"); + } + + dns_diff_clear(&diff); + dns_db_closeversion(kfetch->db, &ver, alldone); + dns_db_detach(&kfetch->db); + + if (dns_rdataset_isassociated(&kfetch->keydataset)) + dns_rdataset_disassociate(&kfetch->keydataset); + if (dns_rdataset_isassociated(&kfetch->dnskeyset)) + dns_rdataset_disassociate(&kfetch->dnskeyset); + if (dns_rdataset_isassociated(&kfetch->dnskeysigset)) + dns_rdataset_disassociate(&kfetch->dnskeysigset); + + dns_name_free(keyname, zone->mctx); + isc_mem_put(zone->mctx, kfetch, sizeof(dns_keyfetch_t)); +} + +/* + * Refresh the data in the key zone. Initiate a fetch to get new DNSKEY + * records from the zone apex. + */ +static void +zone_refreshkeys(dns_zone_t *zone) { + const char me[] = "zone_refreshkeys"; + isc_result_t result; + dns_rriterator_t rrit; + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t kd; + isc_stdtime_t now; + + ENTER; + REQUIRE(zone->db != NULL); + + isc_stdtime_get(&now); + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + LOCK_ZONE(zone); + dns_db_newversion(db, &ver); + dns_diff_init(zone->mctx, &diff); + + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESHING); + + dns_rriterator_init(&rrit, db, ver, 0); + for (result = dns_rriterator_first(&rrit); + result == ISC_R_SUCCESS; + result = dns_rriterator_nextrrset(&rrit)) { + isc_stdtime_t timer = 0xffffffff; + dns_keyfetch_t *kfetch; + dns_rdataset_t *kdset; + dns_name_t *name = NULL; + isc_uint32_t ttl; + + dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL); + if (!dns_rdataset_isassociated(kdset)) + continue; + + if (kdset->type != dns_rdatatype_keydata) + continue; + + /* + * Scan the stored keys looking for ones that need + * removal or refreshing + */ + for (result = dns_rdataset_first(kdset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(kdset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(kdset, &rdata); + result = dns_rdata_tostruct(&rdata, &kd, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + /* Removal timer expired? */ + if (kd.removehd != 0 && kd.removehd < now) { + CHECK(update_one_rr(db, ver, &diff, + DNS_DIFFOP_DEL, name, ttl, + &rdata)); + continue; + } + + /* Acceptance timer expired? */ + if (kd.addhd != 0 && kd.addhd < now) + timer = kd.addhd; + + /* Or do we just need to refresh the keyset? */ + if (timer > kd.refresh) + timer = kd.refresh; + } + + if (timer > now) + continue; + + zone->refreshkeycount++; + + kfetch = isc_mem_get(zone->mctx, sizeof(dns_keyfetch_t)); + kfetch->zone = zone; + dns_fixedname_init(&kfetch->name); + dns_name_dup(name, zone->mctx, + dns_fixedname_name(&kfetch->name)); + dns_rdataset_init(&kfetch->dnskeyset); + dns_rdataset_init(&kfetch->dnskeysigset); + dns_rdataset_init(&kfetch->keydataset); + dns_rdataset_clone(kdset, &kfetch->keydataset); + kfetch->db = NULL; + dns_db_attach(db, &kfetch->db); + kfetch->fetch = NULL; + + dns_resolver_createfetch(zone->view->resolver, + dns_fixedname_name(&kfetch->name), + dns_rdatatype_dnskey, + NULL, NULL, NULL, + DNS_FETCHOPT_NOVALIDATE, + zone->task, keyfetch_done, kfetch, + &kfetch->dnskeyset, + &kfetch->dnskeysigset, + &kfetch->fetch); + } + failure: + UNLOCK_ZONE(zone); + + dns_rriterator_destroy(&rrit); + dns_diff_clear(&diff); + dns_db_closeversion(db, &ver, ISC_FALSE); + dns_db_detach(&db); +} + static void zone_maintenance(dns_zone_t *zone) { const char me[] = "zone_maintenance"; @@ -5916,7 +7180,7 @@ zone_maintenance(dns_zone_t *zone) { /* * Configuring the view of this zone may have * failed, for example because the config file - * had a syntax error. In that case, the view + * had a syntax error. In that case, the view * adb or resolver, and we had better not try * to do maintenance on it. */ @@ -5963,6 +7227,7 @@ zone_maintenance(dns_zone_t *zone) { switch (zone->type) { case dns_zone_master: case dns_zone_slave: + case dns_zone_key: LOCK_ZONE(zone); if (zone->masterfile != NULL && isc_time_compare(&now, &zone->dumptime) >= 0 && @@ -5984,6 +7249,20 @@ zone_maintenance(dns_zone_t *zone) { break; } + /* + * Do we need to refresh keys? + */ + switch (zone->type) { + case dns_zone_key: + if (isc_time_compare(&now, &zone->refreshkeytime) >= 0 && + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) + zone_refreshkeys(zone); + break; + default: + break; + } + switch (zone->type) { case dns_zone_master: case dns_zone_slave: @@ -8376,7 +9655,7 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) { /* * We have now canceled everything set the flag to allow exit_check() - * to succeed. We must not unlock between setting this flag and + * to succeed. We must not unlock between setting this flag and * calling exit_check(). */ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN); @@ -8407,6 +9686,7 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) { isc_time_t next; isc_result_t result; + ENTER; REQUIRE(DNS_ZONE_VALID(zone)); if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) return; @@ -8476,6 +9756,22 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) { } break; + case dns_zone_key: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + INSIST(!isc_time_isepoch(&zone->dumptime)); + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->dumptime, &next) < 0) + next = zone->dumptime; + } + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) { + if (isc_time_isepoch(&next) || + (!isc_time_isepoch(&zone->refreshkeytime) && + isc_time_compare(&zone->refreshkeytime, &next) < 0)) + next = zone->refreshkeytime; + } + break; + default: break; } @@ -9393,7 +10689,7 @@ notify_done(isc_task_t *task, isc_event_t *event) { dns_result_totext(result)); /* - * Old bind's return formerr if they see a soa record. Retry w/o + * Old bind's return formerr if they see a soa record. Retry w/o * the soa if we see a formerr and had sent a SOA. */ isc_event_free(&event); @@ -9448,7 +10744,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { "has %d SOA records", soacount); result = DNS_R_BADZONE; } - if (nscount == 0) { + if (nscount == 0 && zone->type != dns_zone_key) { dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records"); result = DNS_R_BADZONE; } @@ -9555,7 +10851,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { * being loaded from disk. Also, we have not * journaled diffs for this change. * Therefore, the on-disk journal is missing - * the deltas for this change. Since it can + * the deltas for this change. Since it can * no longer be used to bring the zone * up-to-date, it is useless and should be * removed. @@ -11190,7 +12486,7 @@ dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup) { case dns_dialuptype_no: break; case dns_dialuptype_yes: - DNS_ZONE_SETFLAG(zone, (DNS_ZONEFLG_DIALNOTIFY | + DNS_ZONE_SETFLAG(zone, (DNS_ZONEFLG_DIALNOTIFY | DNS_ZONEFLG_DIALREFRESH | DNS_ZONEFLG_NOREFRESH)); break; diff --git a/lib/isc/random.c b/lib/isc/random.c index 0329abde72..905697cc9f 100644 --- a/lib/isc/random.c +++ b/lib/isc/random.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: random.c,v 1.25 2007/06/19 23:47:17 tbox Exp $ */ +/* $Id: random.c,v 1.26 2009/06/30 02:52:32 each Exp $ */ /*! \file */ @@ -92,7 +92,7 @@ isc_random_get(isc_uint32_t *val) isc_uint32_t isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) { - REQUIRE(jitter < max); + REQUIRE(jitter < max || (jitter == 0 && max == 0)); if (jitter == 0) return (max); else diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 48f7913e36..f359b6398e 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.98 2009/06/10 23:47:47 tbox Exp $ */ +/* $Id: namedconf.c,v 1.99 2009/06/30 02:52:33 each Exp $ */ /*! \file */ @@ -361,9 +361,9 @@ static cfg_type_t cfg_type_category = { /*% - * A trusted key, as used in the "trusted-keys" statement. + * A dnssec key, as used in the "trusted-keys" or "managed-keys" statement. */ -static cfg_tuplefielddef_t trustedkey_fields[] = { +static cfg_tuplefielddef_t dnsseckey_fields[] = { { "name", &cfg_type_astring, 0 }, { "flags", &cfg_type_uint32, 0 }, { "protocol", &cfg_type_uint32, 0 }, @@ -371,9 +371,9 @@ static cfg_tuplefielddef_t trustedkey_fields[] = { { "key", &cfg_type_qstring, 0 }, { NULL, NULL, 0 } }; -static cfg_type_t cfg_type_trustedkey = { - "trustedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, - trustedkey_fields +static cfg_type_t cfg_type_dnsseckey = { + "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, dnsseckey_fields }; static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring }; @@ -459,13 +459,14 @@ static cfg_type_t cfg_type_optional_port = { /*% A list of keys, as in the "key" clause of the controls statement. */ static cfg_type_t cfg_type_keylist = { - "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, - &cfg_type_astring + "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring }; -static cfg_type_t cfg_type_trustedkeys = { - "trusted-keys", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, - &cfg_type_trustedkey +/*% A list of dnssec keys, as in "trusted-keys" and "managed-keys" stanzas */ +static cfg_type_t cfg_type_dnsseckeys = { + "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey }; static const char *forwardtype_enums[] = { "first", "only", NULL }; @@ -690,7 +691,8 @@ namedconf_or_view_clauses[] = { /* only 1 DLZ per view allowed */ { "dlz", &cfg_type_dynamically_loadable_zones, 0 }, { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, - { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI }, + { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, + { "managed-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } }; @@ -699,7 +701,8 @@ namedconf_or_view_clauses[] = { */ static cfg_clausedef_t bindkeys_clauses[] = { - { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI }, + { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, + { "managed-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } }; @@ -1086,7 +1089,7 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = { &cfg_rep_map, namedconf_clausesets }; -/*% The bind.keys syntax (trusted-keys only). */ +/*% The bind.keys syntax (trusted-keys/managed-keys only). */ static cfg_clausedef_t * bindkeys_clausesets[] = { bindkeys_clauses, diff --git a/win32utils/BINDBuild.dsw b/win32utils/BINDBuild.dsw index 03b7e0c5d1..bd6a3d9212 100644 --- a/win32utils/BINDBuild.dsw +++ b/win32utils/BINDBuild.dsw @@ -114,6 +114,27 @@ Package=<4> ############################################################################### +Project: "revoke"="..\bin\dnssec\win32\revoke.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libdns + End Project Dependency + Begin Project Dependency + Project_Dep_Name libisc + End Project Dependency + Begin Project Dependency + Project_Dep_Name dnssectool + End Project Dependency +}}} + +############################################################################### + Project: "keygen"="..\bin\dnssec\win32\keygen.dsp" - Package Owner=<4> Package=<5>