diff options
author | dougb <dougb@FreeBSD.org> | 2009-05-31 00:11:36 +0000 |
---|---|---|
committer | dougb <dougb@FreeBSD.org> | 2009-05-31 00:11:36 +0000 |
commit | fd553238c94c3abfef11bfdfc5cb05b32cbe5f76 (patch) | |
tree | 72d567a9bc3fb8adcfcbaa9baedc122d53071209 /lib/dns | |
parent | d342cb576b0154d48c90bc32e251331282264cd4 (diff) | |
download | FreeBSD-src-fd553238c94c3abfef11bfdfc5cb05b32cbe5f76.zip FreeBSD-src-fd553238c94c3abfef11bfdfc5cb05b32cbe5f76.tar.gz |
Vendor import of BIND 9.6.1rc1
Diffstat (limited to 'lib/dns')
282 files changed, 21418 insertions, 3918 deletions
diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index 286a5f9..ef5c12a 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -1,7 +1,7 @@ -# Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2003 Internet Software Consortium. # -# Permission to use, copy, modify, and distribute this software for any +# 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. # @@ -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.144.18.10 2006/01/06 00:01:43 marka Exp $ +# $Id: Makefile.in,v 1.163 2008/09/24 02:46:22 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -29,10 +29,14 @@ top_srcdir = @top_srcdir@ @BIND9_MAKE_INCLUDES@ +USE_ISC_SPNEGO = @USE_ISC_SPNEGO@ + CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} \ ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ -CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ +CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_PKCS11@ @USE_GSSAPI@ \ + ${USE_ISC_SPNEGO} + CWARNINGS = ISCLIBS = ../../lib/isc/libisc.@A@ @@ -43,7 +47,8 @@ LIBS = @LIBS@ # Alphabetically -DSTOBJS = dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ +DSTOBJS = @DST_EXTRA_OBJS@ \ + dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ \ openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \ opensslrsa_link.@O@ @@ -52,10 +57,10 @@ DSTOBJS = dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ 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@ journal.@O@ keytable.@O@ \ - lib.@O@ log.@O@ lookup.@O@ \ + dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ journal.@O@ \ + keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \ master.@O@ masterdump.@O@ message.@O@ \ - name.@O@ ncache.@O@ nsec.@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@ \ @@ -68,7 +73,8 @@ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} # Alphabetically -DSTSRCS = dst_api.c dst_lib.c dst_parse.c \ +DSTSRCS = @DST_EXTRA_SRCS@ \ + dst_api.c dst_lib.c dst_parse.c \ dst_result.c gssapi_link.c gssapictx.c \ hmac_link.c key.c \ openssl_link.c openssldh_link.c \ @@ -77,10 +83,10 @@ DSTSRCS = dst_api.c dst_lib.c dst_parse.c \ 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 journal.c keytable.c \ - lib.c log.c lookup.c \ + dlz.c dnssec.c ds.c forward.c iptable.c journal.c \ + keytable.c lib.c log.c lookup.c \ master.c masterdump.c message.c \ - name.c ncache.c nsec.c order.c peer.c portlist.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 \ @@ -169,3 +175,5 @@ subdirs: include/dns/enumtype.h include/dns/enumclass.h \ include/dns/rdatastruct.h code.h ${OBJS}: include/dns/enumtype.h include/dns/enumclass.h \ include/dns/rdatastruct.h + +spnego.@O@: spnego_asn1.c spnego.h diff --git a/lib/dns/acache.c b/lib/dns/acache.c index cd56c3c..2ad4981 100644 --- a/lib/dns/acache.c +++ b/lib/dns/acache.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 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 @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acache.c,v 1.3.2.18 2008/02/07 23:45:56 tbox Exp $ */ +/* $Id: acache.c,v 1.22 2008/02/07 23:46:54 tbox Exp $ */ #include <config.h> diff --git a/lib/dns/acl.c b/lib/dns/acl.c index 844c132..3af8dd3 100644 --- a/lib/dns/acl.c +++ b/lib/dns/acl.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,18 +15,25 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acl.c,v 1.25.18.5 2006/03/02 00:37:21 marka Exp $ */ +/* $Id: acl.c,v 1.50.44.3 2009/01/18 23:47:35 tbox Exp $ */ /*! \file */ #include <config.h> #include <isc/mem.h> +#include <isc/once.h> #include <isc/string.h> #include <isc/util.h> #include <dns/acl.h> +#include <dns/iptable.h> +/* + * Create a new ACL, including an IP table and an array with room + * for 'n' ACL elements. The elements are uninitialized and the + * length is 0. + */ isc_result_t dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) { isc_result_t result; @@ -43,14 +50,23 @@ dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) { return (ISC_R_NOMEMORY); acl->mctx = mctx; acl->name = NULL; + result = isc_refcount_init(&acl->refcount, 1); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, acl, sizeof(*acl)); return (result); } + + result = dns_iptable_create(mctx, &acl->iptable); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, acl, sizeof(*acl)); + return (result); + } + acl->elements = NULL; acl->alloc = 0; acl->length = 0; + acl->has_negatives = ISC_FALSE; ISC_LINK_INIT(acl, nextincache); /* @@ -73,111 +89,282 @@ dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) { return (result); } -isc_result_t -dns_acl_appendelement(dns_acl_t *acl, const dns_aclelement_t *elt) { - if (acl->length + 1 > acl->alloc) { - /* - * Resize the ACL. - */ - unsigned int newalloc; - void *newmem; - - newalloc = acl->alloc * 2; - if (newalloc < 4) - newalloc = 4; - newmem = isc_mem_get(acl->mctx, - newalloc * sizeof(dns_aclelement_t)); - if (newmem == NULL) - return (ISC_R_NOMEMORY); - memcpy(newmem, acl->elements, - acl->length * sizeof(dns_aclelement_t)); - isc_mem_put(acl->mctx, acl->elements, - acl->alloc * sizeof(dns_aclelement_t)); - acl->elements = newmem; - acl->alloc = newalloc; - } - /* - * Append the new element. - */ - acl->elements[acl->length++] = *elt; - - return (ISC_R_SUCCESS); -} - +/* + * Create a new ACL and initialize it with the value "any" or "none", + * depending on the value of the "neg" parameter. + * "any" is a positive iptable entry with bit length 0. + * "none" is the same as "!any". + */ static isc_result_t dns_acl_anyornone(isc_mem_t *mctx, isc_boolean_t neg, dns_acl_t **target) { isc_result_t result; dns_acl_t *acl = NULL; - result = dns_acl_create(mctx, 1, &acl); + result = dns_acl_create(mctx, 0, &acl); if (result != ISC_R_SUCCESS) return (result); - acl->elements[0].negative = neg; - acl->elements[0].type = dns_aclelementtype_any; - acl->length = 1; + + result = dns_iptable_addprefix(acl->iptable, NULL, 0, ISC_TF(!neg)); + if (result != ISC_R_SUCCESS) { + dns_acl_detach(&acl); + return (result); + } + *target = acl; return (result); } +/* + * Create a new ACL that matches everything. + */ isc_result_t dns_acl_any(isc_mem_t *mctx, dns_acl_t **target) { return (dns_acl_anyornone(mctx, ISC_FALSE, target)); } +/* + * Create a new ACL that matches nothing. + */ isc_result_t dns_acl_none(isc_mem_t *mctx, dns_acl_t **target) { return (dns_acl_anyornone(mctx, ISC_TRUE, target)); } +/* + * If pos is ISC_TRUE, test whether acl is set to "{ any; }" + * If pos is ISC_FALSE, test whether acl is set to "{ none; }" + */ +static isc_boolean_t +dns_acl_isanyornone(dns_acl_t *acl, isc_boolean_t pos) +{ + /* Should never happen but let's be safe */ + if (acl == NULL || + acl->iptable == NULL || + acl->iptable->radix == NULL || + acl->iptable->radix->head == NULL || + acl->iptable->radix->head->prefix == NULL) + return (ISC_FALSE); + + if (acl->length != 0 || acl->node_count != 1) + return (ISC_FALSE); + + if (acl->iptable->radix->head->prefix->bitlen == 0 && + acl->iptable->radix->head->data[0] != NULL && + acl->iptable->radix->head->data[0] == + acl->iptable->radix->head->data[1] && + *(isc_boolean_t *) (acl->iptable->radix->head->data[0]) == pos) + return (ISC_TRUE); + + return (ISC_FALSE); /* All others */ +} + +/* + * Test whether acl is set to "{ any; }" + */ +isc_boolean_t +dns_acl_isany(dns_acl_t *acl) +{ + return (dns_acl_isanyornone(acl, ISC_TRUE)); +} + +/* + * Test whether acl is set to "{ none; }" + */ +isc_boolean_t +dns_acl_isnone(dns_acl_t *acl) +{ + return (dns_acl_isanyornone(acl, ISC_FALSE)); +} + +/* + * Determine whether a given address or signer matches a given ACL. + * For a match with a positive ACL element or iptable radix entry, + * return with a positive value in match; for a match with a negated ACL + * element or radix entry, return with a negative value in match. + */ isc_result_t dns_acl_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, const dns_acl_t *acl, const dns_aclenv_t *env, int *match, - dns_aclelement_t const**matchelt) + const dns_aclelement_t **matchelt) { + isc_uint16_t bitlen, family; + isc_prefix_t pfx; + isc_radix_node_t *node = NULL; + const isc_netaddr_t *addr; + isc_netaddr_t v4addr; + isc_result_t result; + int match_num = -1; unsigned int i; REQUIRE(reqaddr != NULL); REQUIRE(matchelt == NULL || *matchelt == NULL); - + + if (env == NULL || env->match_mapped == ISC_FALSE || + reqaddr->family != AF_INET6 || + !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6)) + addr = reqaddr; + else { + isc_netaddr_fromv4mapped(&v4addr, reqaddr); + addr = &v4addr; + } + + /* Always match with host addresses. */ + family = addr->family; + bitlen = family == AF_INET6 ? 128 : 32; + NETADDR_TO_PREFIX_T(addr, pfx, bitlen); + + /* Assume no match. */ + *match = 0; + + /* Search radix. */ + result = isc_radix_search(acl->iptable->radix, &node, &pfx); + + /* Found a match. */ + if (result == ISC_R_SUCCESS && node != NULL) { + match_num = node->node_num[ISC_IS6(family)]; + if (*(isc_boolean_t *) node->data[ISC_IS6(family)] == ISC_TRUE) + *match = match_num; + else + *match = -match_num; + } + + /* Now search non-radix elements for a match with a lower node_num. */ for (i = 0; i < acl->length; i++) { dns_aclelement_t *e = &acl->elements[i]; + /* Already found a better match? */ + if (match_num != -1 && match_num < e->node_num) { + isc_refcount_destroy(&pfx.refcount); + return (ISC_R_SUCCESS); + } + if (dns_aclelement_match(reqaddr, reqsigner, e, env, matchelt)) { - *match = e->negative ? -((int)i+1) : ((int)i+1); + if (match_num == -1 || e->node_num < match_num) { + if (e->negative == ISC_TRUE) + *match = -e->node_num; + else + *match = e->node_num; + } + isc_refcount_destroy(&pfx.refcount); return (ISC_R_SUCCESS); } } - /* No match. */ - *match = 0; + + isc_refcount_destroy(&pfx.refcount); return (ISC_R_SUCCESS); } +/* + * Merge the contents of one ACL into another. Call dns_iptable_merge() + * for the IP tables, then concatenate the element arrays. + * + * If pos is set to false, then the nested ACL is to be negated. This + * means reverse the sense of each *positive* element or IP table node, + * but leave negatives alone, so as to prevent a double-negative causing + * an unexpected positive match in the parent ACL. + */ isc_result_t -dns_acl_elementmatch(const dns_acl_t *acl, - const dns_aclelement_t *elt, - const dns_aclelement_t **matchelt) +dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos) { - unsigned int i; + isc_result_t result; + unsigned int newalloc, nelem, i; + int max_node = 0, nodes; - REQUIRE(elt != NULL); - REQUIRE(matchelt == NULL || *matchelt == NULL); - - for (i = 0; i < acl->length; i++) { - dns_aclelement_t *e = &acl->elements[i]; + /* Resize the element array if needed. */ + if (dest->length + source->length > dest->alloc) { + void *newmem; - if (dns_aclelement_equal(e, elt) == ISC_TRUE) { - if (matchelt != NULL) - *matchelt = e; - return (ISC_R_SUCCESS); + newalloc = dest->alloc + source->alloc; + if (newalloc < 4) + newalloc = 4; + + newmem = isc_mem_get(dest->mctx, + newalloc * sizeof(dns_aclelement_t)); + if (newmem == NULL) + return (ISC_R_NOMEMORY); + + /* Copy in the original elements */ + memcpy(newmem, dest->elements, + dest->length * sizeof(dns_aclelement_t)); + + /* Release the memory for the old elements array */ + isc_mem_put(dest->mctx, dest->elements, + dest->alloc * sizeof(dns_aclelement_t)); + dest->elements = newmem; + dest->alloc = newalloc; + } + + /* + * Now copy in the new elements, increasing their node_num + * values so as to keep the new ACL consistent. If we're + * negating, then negate positive elements, but keep negative + * elements the same for security reasons. + */ + nelem = dest->length; + dest->length += source->length; + for (i = 0; i < source->length; i++) { + if (source->elements[i].node_num > max_node) + max_node = source->elements[i].node_num; + + /* Copy type. */ + dest->elements[nelem + i].type = source->elements[i].type; + + /* Adjust node numbering. */ + dest->elements[nelem + i].node_num = + source->elements[i].node_num + dest->node_count; + + /* Duplicate nested acl. */ + if (source->elements[i].type == dns_aclelementtype_nestedacl && + source->elements[i].nestedacl != NULL) + dns_acl_attach(source->elements[i].nestedacl, + &dest->elements[nelem + i].nestedacl); + + /* Duplicate key name. */ + if (source->elements[i].type == dns_aclelementtype_keyname) { + dns_name_init(&dest->elements[nelem+i].keyname, NULL); + result = dns_name_dup(&source->elements[i].keyname, + dest->mctx, + &dest->elements[nelem+i].keyname); + if (result != ISC_R_SUCCESS) + return result; + } + + /* reverse sense of positives if this is a negative acl */ + if (!pos && source->elements[i].negative == ISC_FALSE) { + dest->elements[nelem + i].negative = ISC_TRUE; + } else { + dest->elements[nelem + i].negative = + source->elements[i].negative; } } - return (ISC_R_NOTFOUND); + + /* + * Merge the iptables. Make sure the destination ACL's + * node_count value is set correctly afterward. + */ + nodes = max_node + dest->node_count; + result = dns_iptable_merge(dest->iptable, source->iptable, pos); + if (result != ISC_R_SUCCESS) + return (result); + if (nodes > dest->node_count) + dest->node_count = nodes; + + return (ISC_R_SUCCESS); } +/* + * Like dns_acl_match, but matches against the single ACL element 'e' + * rather than a complete ACL, and returns ISC_TRUE iff it matched. + * + * To determine whether the match was positive or negative, the + * caller should examine e->negative. Since the element 'e' may be + * a reference to a named ACL or a nested ACL, a matching element + * returned through 'matchelt' is not necessarily 'e' itself. + */ isc_boolean_t dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, @@ -186,92 +373,68 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_aclelement_t **matchelt) { dns_acl_t *inner = NULL; - const isc_netaddr_t *addr; - isc_netaddr_t v4addr; int indirectmatch; isc_result_t result; switch (e->type) { - case dns_aclelementtype_ipprefix: - if (env == NULL || - env->match_mapped == ISC_FALSE || - reqaddr->family != AF_INET6 || - !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6)) - addr = reqaddr; - else { - isc_netaddr_fromv4mapped(&v4addr, reqaddr); - addr = &v4addr; - } - - if (isc_netaddr_eqprefix(addr, - &e->u.ip_prefix.address, - e->u.ip_prefix.prefixlen)) - goto matched; - break; - case dns_aclelementtype_keyname: if (reqsigner != NULL && - dns_name_equal(reqsigner, &e->u.keyname)) - goto matched; - break; - + dns_name_equal(reqsigner, &e->keyname)) { + if (matchelt != NULL) + *matchelt = e; + return (ISC_TRUE); + } else { + return (ISC_FALSE); + } + case dns_aclelementtype_nestedacl: - inner = e->u.nestedacl; - nested: - result = dns_acl_match(reqaddr, reqsigner, - inner, - env, - &indirectmatch, matchelt); - INSIST(result == ISC_R_SUCCESS); - - /* - * Treat negative matches in indirect ACLs as - * "no match". - * That way, a negated indirect ACL will never become - * a surprise positive match through double negation. - * XXXDCL this should be documented. - */ - if (indirectmatch > 0) - goto matchelt_set; - - /* - * A negative indirect match may have set *matchelt, - * but we don't want it set when we return. - */ - if (matchelt != NULL) - *matchelt = NULL; + inner = e->nestedacl; break; - - case dns_aclelementtype_any: - matched: - if (matchelt != NULL) - *matchelt = e; - matchelt_set: - return (ISC_TRUE); - + case dns_aclelementtype_localhost: - if (env != NULL && env->localhost != NULL) { - inner = env->localhost; - goto nested; - } else { - break; - } - + if (env == NULL || env->localhost == NULL) + return (ISC_FALSE); + inner = env->localhost; + break; + case dns_aclelementtype_localnets: - if (env != NULL && env->localnets != NULL) { - inner = env->localnets; - goto nested; - } else { - break; - } - + if (env == NULL || env->localnets == NULL) + return (ISC_FALSE); + inner = env->localnets; + break; + default: + /* Should be impossible. */ INSIST(0); - break; } + result = dns_acl_match(reqaddr, reqsigner, inner, env, + &indirectmatch, matchelt); + INSIST(result == ISC_R_SUCCESS); + + /* + * Treat negative matches in indirect ACLs as "no match". + * That way, a negated indirect ACL will never become a + * surprise positive match through double negation. + * XXXDCL this should be documented. + */ + + if (indirectmatch > 0) { + if (matchelt != NULL) + *matchelt = e; + return (ISC_TRUE); + } + + /* + * A negative indirect match may have set *matchelt, but we don't + * want it set when we return. + */ + + if (matchelt != NULL) + *matchelt = NULL; + return (ISC_FALSE); -} +} void dns_acl_attach(dns_acl_t *source, dns_acl_t **target) { @@ -285,15 +448,10 @@ destroy(dns_acl_t *dacl) { unsigned int i; for (i = 0; i < dacl->length; i++) { dns_aclelement_t *de = &dacl->elements[i]; - switch (de->type) { - case dns_aclelementtype_keyname: - dns_name_free(&de->u.keyname, dacl->mctx); - break; - case dns_aclelementtype_nestedacl: - dns_acl_detach(&de->u.nestedacl); - break; - default: - break; + if (de->type == dns_aclelementtype_keyname) { + dns_name_free(&de->keyname, dacl->mctx); + } else if (de->type == dns_aclelementtype_nestedacl) { + dns_acl_detach(&de->nestedacl); } } if (dacl->elements != NULL) @@ -301,6 +459,8 @@ destroy(dns_acl_t *dacl) { dacl->alloc * sizeof(dns_aclelement_t)); if (dacl->name != NULL) isc_mem_free(dacl->mctx, dacl->name); + if (dacl->iptable != NULL) + dns_iptable_detach(&dacl->iptable); isc_refcount_destroy(&dacl->refcount); dacl->magic = 0; isc_mem_put(dacl->mctx, dacl, sizeof(*dacl)); @@ -317,69 +477,83 @@ dns_acl_detach(dns_acl_t **aclp) { *aclp = NULL; } -isc_boolean_t -dns_aclelement_equal(const dns_aclelement_t *ea, const dns_aclelement_t *eb) { - if (ea->type != eb->type) - return (ISC_FALSE); - switch (ea->type) { - case dns_aclelementtype_ipprefix: - if (ea->u.ip_prefix.prefixlen != - eb->u.ip_prefix.prefixlen) - return (ISC_FALSE); - return (isc_netaddr_eqprefix(&ea->u.ip_prefix.address, - &eb->u.ip_prefix.address, - ea->u.ip_prefix.prefixlen)); - case dns_aclelementtype_keyname: - return (dns_name_equal(&ea->u.keyname, &eb->u.keyname)); - case dns_aclelementtype_nestedacl: - return (dns_acl_equal(ea->u.nestedacl, eb->u.nestedacl)); - case dns_aclelementtype_localhost: - case dns_aclelementtype_localnets: - case dns_aclelementtype_any: - return (ISC_TRUE); - default: - INSIST(0); - return (ISC_FALSE); - } + +static isc_once_t insecure_prefix_once = ISC_ONCE_INIT; +static isc_mutex_t insecure_prefix_lock; +static isc_boolean_t insecure_prefix_found; + +static void +initialize_action(void) { + RUNTIME_CHECK(isc_mutex_init(&insecure_prefix_lock) == ISC_R_SUCCESS); } -isc_boolean_t -dns_acl_equal(const dns_acl_t *a, const dns_acl_t *b) { - unsigned int i; - if (a == b) - return (ISC_TRUE); - if (a->length != b->length) - return (ISC_FALSE); - for (i = 0; i < a->length; i++) { - if (! dns_aclelement_equal(&a->elements[i], - &b->elements[i])) - return (ISC_FALSE); +/* + * Called via isc_radix_walk() to find IP table nodes that are + * insecure. + */ +static void +is_insecure(isc_prefix_t *prefix, void **data) { + isc_boolean_t secure; + int bitlen, family; + + bitlen = prefix->bitlen; + family = prefix->family; + + /* Negated entries are always secure. */ + secure = * (isc_boolean_t *)data[ISC_IS6(family)]; + if (!secure) { + return; } - return (ISC_TRUE); -} -static isc_boolean_t -is_loopback(const dns_aclipprefix_t *p) { - switch (p->address.family) { + /* If loopback prefix found, return */ + switch (family) { case AF_INET: - if (p->prefixlen == 32 && - htonl(p->address.type.in.s_addr) == INADDR_LOOPBACK) - return (ISC_TRUE); + if (bitlen == 32 && + htonl(prefix->add.sin.s_addr) == INADDR_LOOPBACK) + return; break; case AF_INET6: - if (p->prefixlen == 128 && - IN6_IS_ADDR_LOOPBACK(&p->address.type.in6)) - return (ISC_TRUE); + if (bitlen == 128 && IN6_IS_ADDR_LOOPBACK(&prefix->add.sin6)) + return; break; default: break; } - return (ISC_FALSE); + + /* Non-negated, non-loopback */ + insecure_prefix_found = ISC_TRUE; /* LOCKED */ + return; } +/* + * Return ISC_TRUE iff the acl 'a' is considered insecure, that is, + * if it contains IP addresses other than those of the local host. + * This is intended for applications such as printing warning + * messages for suspect ACLs; it is not intended for making access + * control decisions. We make no guarantee that an ACL for which + * this function returns ISC_FALSE is safe. + */ isc_boolean_t dns_acl_isinsecure(const dns_acl_t *a) { unsigned int i; + isc_boolean_t insecure; + + RUNTIME_CHECK(isc_once_do(&insecure_prefix_once, + initialize_action) == ISC_R_SUCCESS); + + /* + * Walk radix tree to find out if there are any non-negated, + * non-loopback prefixes. + */ + LOCK(&insecure_prefix_lock); + insecure_prefix_found = ISC_FALSE; + isc_radix_process(a->iptable->radix, is_insecure); + insecure = insecure_prefix_found; + UNLOCK(&insecure_prefix_lock); + if (insecure) + return(ISC_TRUE); + + /* Now check non-radix elements */ for (i = 0; i < a->length; i++) { dns_aclelement_t *e = &a->elements[i]; @@ -388,23 +562,16 @@ dns_acl_isinsecure(const dns_acl_t *a) { continue; switch (e->type) { - case dns_aclelementtype_ipprefix: - /* The loopback address is considered secure. */ - if (! is_loopback(&e->u.ip_prefix)) - return (ISC_TRUE); - continue; - case dns_aclelementtype_keyname: case dns_aclelementtype_localhost: continue; case dns_aclelementtype_nestedacl: - if (dns_acl_isinsecure(e->u.nestedacl)) + if (dns_acl_isinsecure(e->nestedacl)) return (ISC_TRUE); continue; - + case dns_aclelementtype_localnets: - case dns_aclelementtype_any: return (ISC_TRUE); default: @@ -412,10 +579,14 @@ dns_acl_isinsecure(const dns_acl_t *a) { return (ISC_TRUE); } } + /* No insecure elements were found. */ return (ISC_FALSE); } +/* + * Initialize ACL environment, setting up localhost and localnets ACLs + */ isc_result_t dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) { isc_result_t result; diff --git a/lib/dns/adb.c b/lib/dns/adb.c index ae5dec8..7056215 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.215.18.24 2008/10/17 03:35:14 marka Exp $ */ +/* $Id: adb.c,v 1.243.42.4 2009/02/03 22:34:28 jinmei Exp $ */ /*! \file * @@ -26,13 +26,6 @@ * */ -/*% - * After we have cleaned all buckets, dump the database contents. - */ -#if 0 -#define DUMP_ADB_AFTER_CLEANING -#endif - #include <config.h> #include <limits.h> @@ -40,9 +33,9 @@ #include <isc/mutexblock.h> #include <isc/netaddr.h> #include <isc/random.h> -#include <isc/string.h> /* Required for HP/UX (and others?) */ +#include <isc/stats.h> +#include <isc/string.h> /* Required for HP/UX (and others?) */ #include <isc/task.h> -#include <isc/timer.h> #include <isc/util.h> #include <dns/adb.h> @@ -55,28 +48,29 @@ #include <dns/rdatatype.h> #include <dns/resolver.h> #include <dns/result.h> +#include <dns/stats.h> -#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b') -#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC) -#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N') -#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC) -#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H') +#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b') +#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC) +#define DNS_ADBNAME_MAGIC ISC_MAGIC('a', 'd', 'b', 'N') +#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC) +#define DNS_ADBNAMEHOOK_MAGIC ISC_MAGIC('a', 'd', 'N', 'H') #define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC) -#define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z') +#define DNS_ADBLAMEINFO_MAGIC ISC_MAGIC('a', 'd', 'b', 'Z') #define DNS_ADBLAMEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC) -#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E') -#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC) -#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4') -#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC) -#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6') -#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) +#define DNS_ADBENTRY_MAGIC ISC_MAGIC('a', 'd', 'b', 'E') +#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC) +#define DNS_ADBFETCH_MAGIC ISC_MAGIC('a', 'd', 'F', '4') +#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC) +#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6') +#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) /*! * The number of buckets needs to be a prime (for good hashing). * * XXXRTH How many buckets do we need? */ -#define NBUCKETS 1009 /*%< how many buckets for names/addrs */ +#define NBUCKETS 1009 /*%< how many buckets for names/addrs */ /*! * For type 3 negative cache entries, we will remember that the address is @@ -84,26 +78,25 @@ * The intent is to keep us from constantly asking about A/AAAA records * if the zone has extremely low TTLs. */ -#define ADB_CACHE_MINIMUM 10 /*%< seconds */ -#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */ -#define ADB_ENTRY_WINDOW 1800 /*%< seconds */ +#define ADB_CACHE_MINIMUM 10 /*%< seconds */ +#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */ +#define ADB_ENTRY_WINDOW 1800 /*%< seconds */ /*% - * Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all - * buckets are cleaned in CLEAN_PERIOD seconds. + * The period in seconds after which an ADB name entry is regarded as stale + * and forced to be cleaned up. + * TODO: This should probably be configurable at run-time. */ -#define CLEAN_PERIOD 3600 -/*% See #CLEAN_PERIOD */ -#define CLEAN_SECONDS 30 -/*% See #CLEAN_PERIOD */ -#define CLEAN_BUCKETS ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD) +#ifndef ADB_STALE_MARGIN +#define ADB_STALE_MARGIN 1800 +#endif -#define FREE_ITEMS 64 /*%< free count for memory pools */ -#define FILL_COUNT 16 /*%< fill count for memory pools */ +#define FREE_ITEMS 64 /*%< free count for memory pools */ +#define FILL_COUNT 16 /*%< fill count for memory pools */ -#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */ +#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */ -#define DNS_ADB_MINADBSIZE (1024*1024) /*%< 1 Megabyte */ +#define DNS_ADB_MINADBSIZE (1024*1024) /*%< 1 Megabyte */ typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t; typedef struct dns_adbnamehook dns_adbnamehook_t; @@ -115,61 +108,62 @@ typedef struct dns_adbfetch6 dns_adbfetch6_t; /*% dns adb structure */ struct dns_adb { - unsigned int magic; + unsigned int magic; - isc_mutex_t lock; - isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */ + isc_mutex_t lock; + isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */ isc_mutex_t overmemlock; /*%< Covers overmem */ - isc_mem_t *mctx; - dns_view_t *view; - isc_timermgr_t *timermgr; - isc_timer_t *timer; - isc_taskmgr_t *taskmgr; - isc_task_t *task; - isc_boolean_t overmem; - - isc_interval_t tick_interval; - int next_cleanbucket; - - unsigned int irefcnt; - unsigned int erefcnt; - - isc_mutex_t mplock; - isc_mempool_t *nmp; /*%< dns_adbname_t */ - isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */ - isc_mempool_t *limp; /*%< dns_adblameinfo_t */ - isc_mempool_t *emp; /*%< dns_adbentry_t */ - isc_mempool_t *ahmp; /*%< dns_adbfind_t */ - isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */ - isc_mempool_t *afmp; /*%< dns_adbfetch_t */ + isc_mem_t *mctx; + dns_view_t *view; + + isc_taskmgr_t *taskmgr; + isc_task_t *task; + isc_boolean_t overmem; + + isc_interval_t tick_interval; + int next_cleanbucket; + + unsigned int irefcnt; + unsigned int erefcnt; + + isc_mutex_t mplock; + isc_mempool_t *nmp; /*%< dns_adbname_t */ + isc_mempool_t *nhmp; /*%< dns_adbnamehook_t */ + isc_mempool_t *limp; /*%< dns_adblameinfo_t */ + isc_mempool_t *emp; /*%< dns_adbentry_t */ + isc_mempool_t *ahmp; /*%< dns_adbfind_t */ + isc_mempool_t *aimp; /*%< dns_adbaddrinfo_t */ + isc_mempool_t *afmp; /*%< dns_adbfetch_t */ /*! * Bucketized locks and lists for names. * * XXXRTH Have a per-bucket structure that contains all of these? */ - dns_adbnamelist_t names[NBUCKETS]; + dns_adbnamelist_t names[NBUCKETS]; + dns_adbnamelist_t deadnames[NBUCKETS]; /*% See dns_adbnamelist_t */ - isc_mutex_t namelocks[NBUCKETS]; + isc_mutex_t namelocks[NBUCKETS]; /*% See dns_adbnamelist_t */ - isc_boolean_t name_sd[NBUCKETS]; + isc_boolean_t name_sd[NBUCKETS]; /*% See dns_adbnamelist_t */ - unsigned int name_refcnt[NBUCKETS]; + unsigned int name_refcnt[NBUCKETS]; /*! * Bucketized locks for entries. * * XXXRTH Have a per-bucket structure that contains all of these? */ - dns_adbentrylist_t entries[NBUCKETS]; - isc_mutex_t entrylocks[NBUCKETS]; - isc_boolean_t entry_sd[NBUCKETS]; /*%< shutting down */ - unsigned int entry_refcnt[NBUCKETS]; - - isc_event_t cevent; - isc_boolean_t cevent_sent; - isc_boolean_t shutting_down; - isc_eventlist_t whenshutdown; + dns_adbentrylist_t entries[NBUCKETS]; + dns_adbentrylist_t deadentries[NBUCKETS]; + isc_mutex_t entrylocks[NBUCKETS]; + isc_boolean_t entry_sd[NBUCKETS]; /*%< shutting down */ + unsigned int entry_refcnt[NBUCKETS]; + + isc_event_t cevent; + isc_boolean_t cevent_sent; + isc_boolean_t shutting_down; + isc_eventlist_t whenshutdown; }; /* @@ -178,34 +172,35 @@ struct dns_adb { /*% dns_adbname structure */ struct dns_adbname { - unsigned int magic; - dns_name_t name; - dns_adb_t *adb; - unsigned int partial_result; - unsigned int flags; - int lock_bucket; - dns_name_t target; - isc_stdtime_t expire_target; - isc_stdtime_t expire_v4; - isc_stdtime_t expire_v6; - unsigned int chains; - dns_adbnamehooklist_t v4; - dns_adbnamehooklist_t v6; - dns_adbfetch_t *fetch_a; - dns_adbfetch_t *fetch_aaaa; - unsigned int fetch_err; - unsigned int fetch6_err; - dns_adbfindlist_t finds; - ISC_LINK(dns_adbname_t) plink; + unsigned int magic; + dns_name_t name; + dns_adb_t *adb; + unsigned int partial_result; + unsigned int flags; + int lock_bucket; + dns_name_t target; + isc_stdtime_t expire_target; + isc_stdtime_t expire_v4; + isc_stdtime_t expire_v6; + unsigned int chains; + dns_adbnamehooklist_t v4; + dns_adbnamehooklist_t v6; + dns_adbfetch_t *fetch_a; + dns_adbfetch_t *fetch_aaaa; + unsigned int fetch_err; + unsigned int fetch6_err; + dns_adbfindlist_t finds; + /* for LRU-based management */ + isc_stdtime_t last_used; + + ISC_LINK(dns_adbname_t) plink; }; /*% The adbfetch structure */ struct dns_adbfetch { - unsigned int magic; - dns_adbnamehook_t *namehook; - dns_adbentry_t *entry; - dns_fetch_t *fetch; - dns_rdataset_t rdataset; + unsigned int magic; + dns_fetch_t *fetch; + dns_rdataset_t rdataset; }; /*% @@ -214,9 +209,9 @@ struct dns_adbfetch { * namehook that will contain the next address this host has. */ struct dns_adbnamehook { - unsigned int magic; - dns_adbentry_t *entry; - ISC_LINK(dns_adbnamehook_t) plink; + unsigned int magic; + dns_adbentry_t *entry; + ISC_LINK(dns_adbnamehook_t) plink; }; /*% @@ -225,13 +220,13 @@ struct dns_adbnamehook { * extended to other types of information about zones. */ struct dns_adblameinfo { - unsigned int magic; + unsigned int magic; - dns_name_t qname; - dns_rdatatype_t qtype; - isc_stdtime_t lame_timer; + dns_name_t qname; + dns_rdatatype_t qtype; + isc_stdtime_t lame_timer; - ISC_LINK(dns_adblameinfo_t) plink; + ISC_LINK(dns_adblameinfo_t) plink; }; /*% @@ -240,16 +235,16 @@ struct dns_adblameinfo { * the host. */ struct dns_adbentry { - unsigned int magic; + unsigned int magic; - int lock_bucket; - unsigned int refcnt; + int lock_bucket; + unsigned int refcnt; - unsigned int flags; - unsigned int srtt; - isc_sockaddr_t sockaddr; + unsigned int flags; + unsigned int srtt; + isc_sockaddr_t sockaddr; - isc_stdtime_t expires; + isc_stdtime_t expires; /*%< * A nonzero 'expires' field indicates that the entry should * persist until that time. This allows entries found @@ -258,8 +253,8 @@ struct dns_adbentry { * name. */ - ISC_LIST(dns_adblameinfo_t) lameinfo; - ISC_LINK(dns_adbentry_t) plink; + ISC_LIST(dns_adblameinfo_t) lameinfo; + ISC_LINK(dns_adbentry_t) plink; }; /* @@ -284,7 +279,8 @@ static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **); static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *, unsigned int, int *); static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *, - isc_sockaddr_t *, int *); + isc_sockaddr_t *, int *, + isc_stdtime_t); static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t); static void print_dns_name(FILE *, dns_name_t *); static void print_namehook_list(FILE *, const char *legend, @@ -305,15 +301,15 @@ static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); static void clean_target(dns_adb_t *, dns_name_t *); static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int); -static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t, - isc_boolean_t); +static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t); +static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **, + isc_stdtime_t); static void cancel_fetches_at_name(dns_adbname_t *); static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, dns_rdatatype_t); static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, dns_rdatatype_t); static inline void check_exit(dns_adb_t *); -static void timer_cleanup(isc_task_t *, isc_event_t *); static void destroy(dns_adb_t *); static isc_boolean_t shutdown_names(dns_adb_t *); static isc_boolean_t shutdown_entries(dns_adb_t *); @@ -328,28 +324,34 @@ static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); /* * MUST NOT overlap DNS_ADBFIND_* flags! */ -#define FIND_EVENT_SENT 0x40000000 -#define FIND_EVENT_FREED 0x80000000 -#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0) -#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0) - -#define NAME_NEEDS_POKE 0x80000000 -#define NAME_IS_DEAD 0x40000000 -#define NAME_HINT_OK DNS_ADBFIND_HINTOK -#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK -#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE -#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0) -#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0) -#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0) -#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0) +#define FIND_EVENT_SENT 0x40000000 +#define FIND_EVENT_FREED 0x80000000 +#define FIND_EVENTSENT(h) (((h)->flags & FIND_EVENT_SENT) != 0) +#define FIND_EVENTFREED(h) (((h)->flags & FIND_EVENT_FREED) != 0) + +#define NAME_NEEDS_POKE 0x80000000 +#define NAME_IS_DEAD 0x40000000 +#define NAME_HINT_OK DNS_ADBFIND_HINTOK +#define NAME_GLUE_OK DNS_ADBFIND_GLUEOK +#define NAME_STARTATZONE DNS_ADBFIND_STARTATZONE +#define NAME_DEAD(n) (((n)->flags & NAME_IS_DEAD) != 0) +#define NAME_NEEDSPOKE(n) (((n)->flags & NAME_NEEDS_POKE) != 0) +#define NAME_GLUEOK(n) (((n)->flags & NAME_GLUE_OK) != 0) +#define NAME_HINTOK(n) (((n)->flags & NAME_HINT_OK) != 0) + +/* + * Private flag(s) for entries. + * MUST NOT overlap FCTX_ADDRINFO_xxx and DNS_FETCHOPT_NOEDNS0. + */ +#define ENTRY_IS_DEAD 0x80000000 /* * To the name, address classes are all that really exist. If it has a * V6 address it doesn't care if it came from a AAAA query. */ -#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4)) -#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6)) -#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n)) +#define NAME_HAS_V4(n) (!ISC_LIST_EMPTY((n)->v4)) +#define NAME_HAS_V6(n) (!ISC_LIST_EMPTY((n)->v6)) +#define NAME_HAS_ADDRS(n) (NAME_HAS_V4(n) || NAME_HAS_V6(n)) /* * Fetches are broken out into A and AAAA types. In some cases, @@ -358,34 +360,34 @@ static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA * are now equal to FETCH_V4 and FETCH_V6, respectively. */ -#define NAME_FETCH_A(n) ((n)->fetch_a != NULL) -#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL) -#define NAME_FETCH_V4(n) (NAME_FETCH_A(n)) -#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n)) -#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n)) +#define NAME_FETCH_A(n) ((n)->fetch_a != NULL) +#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL) +#define NAME_FETCH_V4(n) (NAME_FETCH_A(n)) +#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n)) +#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n)) /* * Find options and tests to see if there are addresses on the list. */ -#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) -#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) -#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ +#define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) +#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) +#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ != 0) -#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ +#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ != 0) -#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) -#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) -#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) -#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) +#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) +#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) +#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) +#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) /* * These are currently used on simple unsigned ints, so they are * not really associated with any particular type. */ -#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) -#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) +#define WANT_INET(x) (((x) & DNS_ADBFIND_INET) != 0) +#define WANT_INET6(x) (((x) & DNS_ADBFIND_INET6) != 0) -#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) +#define EXPIRE_OK(exp, now) ((exp == INT_MAX) || (exp < now)) /* * Find out if the flags on a name (nf) indicate if it is a hint or @@ -398,19 +400,19 @@ static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \ ((o) & DNS_ADBFIND_STARTATZONE)) -#define ENTER_LEVEL ISC_LOG_DEBUG(50) -#define EXIT_LEVEL ENTER_LEVEL -#define CLEAN_LEVEL ISC_LOG_DEBUG(100) -#define DEF_LEVEL ISC_LOG_DEBUG(5) -#define NCACHE_LEVEL ISC_LOG_DEBUG(20) +#define ENTER_LEVEL ISC_LOG_DEBUG(50) +#define EXIT_LEVEL ENTER_LEVEL +#define CLEAN_LEVEL ISC_LOG_DEBUG(100) +#define DEF_LEVEL ISC_LOG_DEBUG(5) +#define NCACHE_LEVEL ISC_LOG_DEBUG(20) -#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \ +#define NCACHE_RESULT(r) ((r) == DNS_R_NCACHENXDOMAIN || \ (r) == DNS_R_NCACHENXRRSET) -#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \ +#define AUTH_NX(r) ((r) == DNS_R_NXDOMAIN || \ (r) == DNS_R_NXRRSET) -#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \ +#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \ (r) == DNS_R_NCACHENXDOMAIN) -#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \ +#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \ (r) == DNS_R_NXRRSET || \ (r) == DNS_R_HINTNXRRSET) @@ -418,14 +420,14 @@ static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); * Error state rankings. */ -#define FIND_ERR_SUCCESS 0 /* highest rank */ -#define FIND_ERR_CANCELED 1 -#define FIND_ERR_FAILURE 2 -#define FIND_ERR_NXDOMAIN 3 -#define FIND_ERR_NXRRSET 4 -#define FIND_ERR_UNEXPECTED 5 -#define FIND_ERR_NOTFOUND 6 -#define FIND_ERR_MAX 7 +#define FIND_ERR_SUCCESS 0 /* highest rank */ +#define FIND_ERR_CANCELED 1 +#define FIND_ERR_FAILURE 2 +#define FIND_ERR_NXDOMAIN 3 +#define FIND_ERR_NXRRSET 4 +#define FIND_ERR_UNEXPECTED 5 +#define FIND_ERR_NOTFOUND 6 +#define FIND_ERR_MAX 7 static const char *errnames[] = { "success", @@ -437,7 +439,7 @@ static const char *errnames[] = { "not_found" }; -#define NEWERR(old, new) (ISC_MIN((old), (new))) +#define NEWERR(old, new) (ISC_MIN((old), (new))) static isc_result_t find_err_map[FIND_ERR_MAX] = { ISC_R_SUCCESS, @@ -446,7 +448,7 @@ static isc_result_t find_err_map[FIND_ERR_MAX] = { DNS_R_NXDOMAIN, DNS_R_NXRRSET, ISC_R_UNEXPECTED, - ISC_R_NOTFOUND /* not YET found */ + ISC_R_NOTFOUND /* not YET found */ }; static void @@ -463,6 +465,15 @@ DP(int level, const char *format, ...) { va_end(args); } +/*% + * Increment resolver-related statistics counters. + */ +static inline void +inc_stats(dns_adb_t *adb, isc_statscounter_t counter) { + if (adb->view->resstats != NULL) + isc_stats_increment(adb->view->resstats, counter); +} + static inline dns_ttl_t ttlclamp(dns_ttl_t ttl) { if (ttl < ADB_CACHE_MINIMUM) @@ -536,7 +547,8 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, goto fail; } - foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket); + foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket, + now); if (foundentry == NULL) { dns_adbentry_t *entry; @@ -617,6 +629,7 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev) { dns_adbname_t *name; isc_boolean_t result = ISC_FALSE; isc_boolean_t result4, result6; + int bucket; dns_adb_t *adb; INSIST(n != NULL); @@ -661,8 +674,13 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev) { if (result) result = dec_adb_irefcnt(adb); } else { - name->flags |= NAME_IS_DEAD; cancel_fetches_at_name(name); + if (!NAME_DEAD(name)) { + bucket = name->lock_bucket; + ISC_LIST_UNLINK(adb->names[bucket], name, plink); + ISC_LIST_APPEND(adb->deadnames[bucket], name, plink); + name->flags |= NAME_IS_DEAD; + } } return (result); } @@ -671,11 +689,8 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev) { * Requires the name's bucket be locked and no entry buckets be locked. */ static isc_boolean_t -check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now, - isc_boolean_t overmem) -{ +check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) { dns_adb_t *adb; - isc_boolean_t expire; isc_boolean_t result4 = ISC_FALSE; isc_boolean_t result6 = ISC_FALSE; @@ -683,20 +698,10 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now, adb = name->adb; INSIST(DNS_ADB_VALID(adb)); - if (overmem) { - isc_uint32_t val; - - isc_random_get(&val); - - expire = ISC_TF((val % 4) == 0); - } else - expire = ISC_FALSE; - /* * Check to see if we need to remove the v4 addresses */ - if (!NAME_FETCH_V4(name) && - (expire || EXPIRE_OK(name->expire_v4, now))) { + if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) { if (NAME_HAS_V4(name)) { DP(DEF_LEVEL, "expiring v4 for name %p", name); result4 = clean_namehooks(adb, &name->v4); @@ -709,8 +714,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now, /* * Check to see if we need to remove the v6 addresses */ - if (!NAME_FETCH_V6(name) && - (expire || EXPIRE_OK(name->expire_v6, now))) { + if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) { if (NAME_HAS_V6(name)) { DP(DEF_LEVEL, "expiring v6 for name %p", name); result6 = clean_namehooks(adb, &name->v6); @@ -723,7 +727,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now, /* * Check to see if we need to remove the alias target. */ - if (expire || EXPIRE_OK(name->expire_target, now)) { + if (EXPIRE_OK(name->expire_target, now)) { clean_target(adb, &name->target); name->expire_target = INT_MAX; } @@ -753,7 +757,10 @@ unlink_name(dns_adb_t *adb, dns_adbname_t *name) { bucket = name->lock_bucket; INSIST(bucket != DNS_ADB_INVALIDBUCKET); - ISC_LIST_UNLINK(adb->names[bucket], name, plink); + if (NAME_DEAD(name)) + ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink); + else + ISC_LIST_UNLINK(adb->names[bucket], name, plink); name->lock_bucket = DNS_ADB_INVALIDBUCKET; INSIST(adb->name_refcnt[bucket] > 0); adb->name_refcnt[bucket]--; @@ -767,6 +774,26 @@ unlink_name(dns_adb_t *adb, dns_adbname_t *name) { */ static inline void link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) { + int i; + dns_adbentry_t *e; + + if (adb->overmem) { + for (i = 0; i < 2; i++) { + e = ISC_LIST_TAIL(adb->entries[bucket]); + if (e == NULL) + break; + if (e->refcnt == 0) { + unlink_entry(adb, e); + free_adbentry(adb, &e); + continue; + } + INSIST((e->flags & ENTRY_IS_DEAD) == 0); + e->flags |= ENTRY_IS_DEAD; + ISC_LIST_UNLINK(adb->entries[bucket], e, plink); + ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink); + } + } + ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); entry->lock_bucket = bucket; adb->entry_refcnt[bucket]++; @@ -783,7 +810,10 @@ unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) { bucket = entry->lock_bucket; INSIST(bucket != DNS_ADB_INVALIDBUCKET); - ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); + if ((entry->flags & ENTRY_IS_DEAD) != 0) + ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink); + else + ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); entry->lock_bucket = DNS_ADB_INVALIDBUCKET; INSIST(adb->entry_refcnt[bucket] > 0); adb->entry_refcnt[bucket]--; @@ -862,7 +892,7 @@ shutdown_entries(dns_adb_t *adb) { adb->entry_sd[bucket] = ISC_TRUE; entry = ISC_LIST_HEAD(adb->entries[bucket]); - if (entry == NULL) { + if (adb->entry_refcnt[bucket] == 0) { /* * This bucket has no entries. We must decrement the * irefcnt ourselves, since it will not be @@ -1140,7 +1170,7 @@ check_exit(dns_adb_t *adb) { * If there aren't any external references either, we're * done. Send the control event to initiate shutdown. */ - INSIST(!adb->cevent_sent); /* Sanity check. */ + INSIST(!adb->cevent_sent); /* Sanity check. */ event = &adb->cevent; isc_task_send(adb->task, &event); adb->cevent_sent = ISC_TRUE; @@ -1220,7 +1250,8 @@ dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { destroy_entry = ISC_FALSE; if (entry->refcnt == 0 && - (adb->entry_sd[bucket] || entry->expires == 0)) { + (adb->entry_sd[bucket] || entry->expires == 0 || adb->overmem || + (entry->flags & ENTRY_IS_DEAD) != 0)) { destroy_entry = ISC_TRUE; result = unlink_entry(adb, entry); } @@ -1235,7 +1266,7 @@ dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) { free_adbentry(adb, &entry); if (result) - result =dec_adb_irefcnt(adb); + result = dec_adb_irefcnt(adb); return (result); } @@ -1463,31 +1494,13 @@ new_adbfetch(dns_adb_t *adb) { return (NULL); f->magic = 0; - f->namehook = NULL; - f->entry = NULL; f->fetch = NULL; - f->namehook = new_adbnamehook(adb, NULL); - if (f->namehook == NULL) - goto err; - - f->entry = new_adbentry(adb); - if (f->entry == NULL) - goto err; - dns_rdataset_init(&f->rdataset); f->magic = DNS_ADBFETCH_MAGIC; return (f); - - err: - if (f->namehook != NULL) - free_adbnamehook(adb, &f->namehook); - if (f->entry != NULL) - free_adbentry(adb, &f->entry); - isc_mempool_put(adb->afmp, f); - return (NULL); } static inline void @@ -1500,11 +1513,6 @@ free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) { f->magic = 0; - if (f->namehook != NULL) - free_adbnamehook(adb, &f->namehook); - if (f->entry != NULL) - free_adbentry(adb, &f->entry); - if (dns_rdataset_isassociated(&f->rdataset)) dns_rdataset_disassociate(&f->rdataset); @@ -1622,8 +1630,10 @@ find_name_and_lock(dns_adb_t *adb, dns_name_t *name, * the bucket changes. */ static inline dns_adbentry_t * -find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) { - dns_adbentry_t *entry; +find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp, + isc_stdtime_t now) +{ + dns_adbentry_t *entry, *entry_next; int bucket; bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS; @@ -1637,11 +1647,18 @@ find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) { *bucketp = bucket; } - entry = ISC_LIST_HEAD(adb->entries[bucket]); - while (entry != NULL) { - if (isc_sockaddr_equal(addr, &entry->sockaddr)) + /* Search the list, while cleaning up expired entries. */ + for (entry = ISC_LIST_HEAD(adb->entries[bucket]); + entry != NULL; + entry = entry_next) { + entry_next = ISC_LIST_NEXT(entry, plink); + (void)check_expire_entry(adb, &entry, now); + if (entry != NULL && + isc_sockaddr_equal(addr, &entry->sockaddr)) { + ISC_LIST_UNLINK(adb->entries[bucket], entry, plink); + ISC_LIST_PREPEND(adb->entries[bucket], entry, plink); return (entry); - entry = ISC_LIST_NEXT(entry, plink); + } } return (NULL); @@ -1775,19 +1792,12 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) { adb = ev->ev_arg; INSIST(DNS_ADB_VALID(adb)); + isc_event_free(&ev); /* * Wait for lock around check_exit() call to be released. */ LOCK(&adb->lock); - /* - * Kill the timer, and then the ADB itself. Note that this implies - * that this task was the one scheduled to get timer events. If - * this is not true (and it is unfortunate there is no way to INSIST() - * this) badness will occur. - */ - isc_timer_detach(&adb->timer); UNLOCK(&adb->lock); - isc_event_free(&ev); destroy(adb); } @@ -1826,6 +1836,62 @@ check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) { return (result); } +/*% + * Examine the tail entry of the LRU list to see if it expires or is stale + * (unused for some period); if so, the name entry will be freed. If the ADB + * is in the overmem condition, the tail and the next to tail entries + * will be unconditionally removed (unless they have an outstanding fetch). + * We don't care about a race on 'overmem' at the risk of causing some + * collateral damage or a small delay in starting cleanup, so we don't bother + * to lock ADB (if it's not locked). + * + * Name bucket must be locked; adb may be locked; no other locks held. + */ +static void +check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) { + int victims, max_victims; + isc_boolean_t result; + dns_adbname_t *victim, *next_victim; + isc_boolean_t overmem = adb->overmem; + int scans = 0; + + INSIST(bucket != DNS_ADB_INVALIDBUCKET); + + max_victims = overmem ? 2 : 1; + + /* + * We limit the number of scanned entries to 10 (arbitrary choice) + * in order to avoid examining too many entries when there are many + * tail entries that have fetches (this should be rare, but could + * happen). + */ + victim = ISC_LIST_TAIL(adb->names[bucket]); + for (victims = 0; + victim != NULL && victims < max_victims && scans < 10; + victim = next_victim) { + INSIST(!NAME_DEAD(victim)); + scans++; + next_victim = ISC_LIST_PREV(victim, plink); + result = check_expire_name(&victim, now); + if (victim == NULL) { + victims++; + goto next; + } + + if (!NAME_FETCH(victim) && + (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) { + RUNTIME_CHECK(kill_name(&victim, + DNS_EVENT_ADBCANCELED) == + ISC_FALSE); + victims++; + } + + next: + if (!overmem) + break; + } +} + /* * Entry bucket must be locked; adb may be locked; no other locks held. */ @@ -1833,7 +1899,6 @@ static isc_boolean_t check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) { dns_adbentry_t *entry; - isc_boolean_t expire; isc_boolean_t result = ISC_FALSE; INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp)); @@ -1842,16 +1907,7 @@ check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) if (entry->refcnt != 0) return (result); - if (adb->overmem) { - isc_uint32_t val; - - isc_random_get(&val); - - expire = ISC_TF((val % 4) == 0); - } else - expire = ISC_FALSE; - - if (entry->expires == 0 || (! expire && entry->expires > now)) + if (entry->expires == 0 || entry->expires > now) return (result); /* @@ -1888,7 +1944,7 @@ cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) { while (name != NULL) { next_name = ISC_LIST_NEXT(name, plink); INSIST(result == ISC_FALSE); - result = check_expire_namehooks(name, now, adb->overmem); + result = check_expire_namehooks(name, now); if (!result) result = check_expire_name(&name, now); name = next_name; @@ -1920,66 +1976,9 @@ cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) { } static void -timer_cleanup(isc_task_t *task, isc_event_t *ev) { - dns_adb_t *adb; - isc_stdtime_t now; - unsigned int i; - isc_interval_t interval; - - UNUSED(task); - - adb = ev->ev_arg; - INSIST(DNS_ADB_VALID(adb)); - - LOCK(&adb->lock); - - isc_stdtime_get(&now); - - for (i = 0; i < CLEAN_BUCKETS; i++) { - /* - * Call our cleanup routines. - */ - RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) == - ISC_FALSE); - RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now) - == ISC_FALSE); - - /* - * Set the next bucket to be cleaned. - */ - adb->next_cleanbucket++; - if (adb->next_cleanbucket >= NBUCKETS) { - adb->next_cleanbucket = 0; -#ifdef DUMP_ADB_AFTER_CLEANING - dump_adb(adb, stdout, ISC_TRUE, now); -#endif - } - } - - /* - * Reset the timer. - * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or - * ISC_R_NOMEMORY, but it isn't clear what could be done here - * if either one of those things happened. - */ - interval = adb->tick_interval; - if (adb->overmem) - isc_interval_set(&interval, 0, 1); - (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL, - &interval, ISC_FALSE); - - UNLOCK(&adb->lock); - - isc_event_free(&ev); -} - -static void destroy(dns_adb_t *adb) { adb->magic = 0; - /* - * The timer is already dead, from the task's shutdown callback. - */ isc_task_detach(&adb->task); isc_mempool_destroy(&adb->nmp); @@ -2016,10 +2015,12 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, REQUIRE(mem != NULL); REQUIRE(view != NULL); - REQUIRE(timermgr != NULL); + REQUIRE(timermgr != NULL); /* this is actually unused */ REQUIRE(taskmgr != NULL); REQUIRE(newadb != NULL && *newadb == NULL); + UNUSED(timermgr); + adb = isc_mem_get(mem, sizeof(dns_adb_t)); if (adb == NULL) return (ISC_R_NOMEMORY); @@ -2039,10 +2040,8 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, adb->aimp = NULL; adb->afmp = NULL; adb->task = NULL; - adb->timer = NULL; adb->mctx = NULL; adb->view = view; - adb->timermgr = timermgr; adb->taskmgr = taskmgr; adb->next_cleanbucket = 0; ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, @@ -2080,12 +2079,14 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, goto fail1; for (i = 0; i < NBUCKETS; i++) { ISC_LIST_INIT(adb->names[i]); + ISC_LIST_INIT(adb->deadnames[i]); adb->name_sd[i] = ISC_FALSE; adb->name_refcnt[i] = 0; adb->irefcnt++; } for (i = 0; i < NBUCKETS; i++) { ISC_LIST_INIT(adb->entries[i]); + ISC_LIST_INIT(adb->deadentries[i]); adb->entry_sd[i] = ISC_FALSE; adb->entry_refcnt[i] = 0; adb->irefcnt++; @@ -2118,25 +2119,12 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, #undef MPINIT /* - * Allocate a timer and a task for our periodic cleanup. + * Allocate an internal task. */ result = isc_task_create(adb->taskmgr, 0, &adb->task); if (result != ISC_R_SUCCESS) goto fail3; isc_task_setname(adb->task, "ADB", adb); - /* - * XXXMLG When this is changed to be a config file option, - */ - isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0); - result = isc_timer_create(adb->timermgr, isc_timertype_once, - NULL, &adb->tick_interval, adb->task, - timer_cleanup, adb, &adb->timer); - if (result != ISC_R_SUCCESS) - goto fail3; - - DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: " - "%u buckets every %u seconds, %u buckets in system, %u cl.interval", - CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD); /* * Normal return. @@ -2148,8 +2136,6 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, fail3: if (adb->task != NULL) isc_task_detach(&adb->task); - if (adb->timer != NULL) - isc_timer_detach(&adb->timer); /* clean up entrylocks */ DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); @@ -2328,18 +2314,18 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, * * Possibilities: Note that these are not always exclusive. * - * No name found. In this case, allocate a new name header and - * an initial namehook or two. If any of these allocations - * fail, clean up and return ISC_R_NOMEMORY. + * No name found. In this case, allocate a new name header and + * an initial namehook or two. If any of these allocations + * fail, clean up and return ISC_R_NOMEMORY. * - * Name found, valid addresses present. Allocate one addrinfo - * structure for each found and append it to the linked list - * of addresses for this header. + * Name found, valid addresses present. Allocate one addrinfo + * structure for each found and append it to the linked list + * of addresses for this header. * - * Name found, queries pending. In this case, if a task was - * passed in, allocate a job id, attach it to the name's job - * list and remember to tell the caller that there will be - * more info coming later. + * Name found, queries pending. In this case, if a task was + * passed in, allocate a job id, attach it to the name's job + * list and remember to tell the caller that there will be + * more info coming later. */ find = new_adbfind(adb); @@ -2374,6 +2360,12 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, * Nothing found. Allocate a new adbname structure for this name. */ if (adbname == NULL) { + /* + * See if there is any stale name at the end of list, and purge + * it if so. + */ + check_stale_name(adb, bucket, now); + adbname = new_adbname(adb, name); if (adbname == NULL) { RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); @@ -2387,13 +2379,17 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, adbname->flags |= NAME_GLUE_OK; if (FIND_STARTATZONE(find)) adbname->flags |= NAME_STARTATZONE; + } else { + /* Move this name forward in the LRU list */ + ISC_LIST_UNLINK(adb->names[bucket], adbname, plink); + ISC_LIST_PREPEND(adb->names[bucket], adbname, plink); } + adbname->last_used = now; /* * Expire old entries, etc. */ - RUNTIME_CHECK(check_expire_namehooks(adbname, now, adb->overmem) == - ISC_FALSE); + RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE); /* * Do we know that the name is an alias? @@ -2953,8 +2949,8 @@ print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list, static inline void print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) { - fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n", - type, ft, ft->namehook, ft->entry, ft->fetch); + fprintf(f, "\t\tFetch(%s): %p -> { fetch %p }\n", + type, ft, ft->fetch); } static void @@ -2991,7 +2987,7 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa); dns_fixedname_init(&foundname); - fname = dns_fixedname_name(&foundname); + fname = dns_fixedname_name(&foundname); dns_rdataset_init(&rdataset); if (rdtype == dns_rdatatype_a) @@ -3202,6 +3198,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { name->fetch_err = FIND_ERR_NXDOMAIN; else name->fetch_err = FIND_ERR_NXRRSET; + inc_stats(adb, dns_resstatscounter_gluefetchv4fail); } else { DP(NCACHE_LEVEL, "adb fetch name %p: " "caching negative entry for AAAA (ttl %u)", @@ -3212,6 +3209,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { name->fetch6_err = FIND_ERR_NXDOMAIN; else name->fetch6_err = FIND_ERR_NXRRSET; + inc_stats(adb, dns_resstatscounter_gluefetchv6fail); } goto out; } @@ -3251,9 +3249,11 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { if (address_type == DNS_ADBFIND_INET) { name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); name->fetch_err = FIND_ERR_FAILURE; + inc_stats(adb, dns_resstatscounter_gluefetchv4fail); } else { name->expire_v6 = ISC_MIN(name->expire_v6, now + 300); name->fetch6_err = FIND_ERR_FAILURE; + inc_stats(adb, dns_resstatscounter_gluefetchv6fail); } goto out; } @@ -3338,10 +3338,13 @@ fetch_name(dns_adbname_t *adbname, if (result != ISC_R_SUCCESS) goto cleanup; - if (type == dns_rdatatype_a) + if (type == dns_rdatatype_a) { adbname->fetch_a = fetch; - else + inc_stats(adb, dns_resstatscounter_gluefetchv4); + } else { adbname->fetch_aaaa = fetch; + inc_stats(adb, dns_resstatscounter_gluefetchv6); + } fetch = NULL; /* Keep us from cleaning this up below. */ cleanup: @@ -3464,7 +3467,7 @@ dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa, result = ISC_R_SUCCESS; bucket = DNS_ADB_INVALIDBUCKET; - entry = find_entry_and_lock(adb, sa, &bucket); + entry = find_entry_and_lock(adb, sa, &bucket, now); if (adb->entry_sd[bucket]) { result = ISC_R_SHUTTINGDOWN; goto unlock; @@ -3590,7 +3593,6 @@ static void water(void *arg, int mark) { dns_adb_t *adb = arg; isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); - isc_interval_t interval; REQUIRE(DNS_ADB_VALID(adb)); @@ -3604,11 +3606,6 @@ water(void *arg, int mark) { LOCK(&adb->overmemlock); if (adb->overmem != overmem) { adb->overmem = overmem; - if (overmem) { - isc_interval_set(&interval, 0, 1); - (void)isc_timer_reset(adb->timer, isc_timertype_once, - NULL, &interval, ISC_TRUE); - } isc_mem_waterack(adb->mctx, mark); } UNLOCK(&adb->overmemlock); diff --git a/lib/dns/api b/lib/dns/api index 0b8a3bc..5ef8dc0 100644 --- a/lib/dns/api +++ b/lib/dns/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 36 -LIBREVISION = 2 -LIBAGE = 0 +LIBINTERFACE = 51 +LIBREVISION = 1 +LIBAGE = 1 diff --git a/lib/dns/byaddr.c b/lib/dns/byaddr.c index 38d6e8b..234d6b2 100644 --- a/lib/dns/byaddr.c +++ b/lib/dns/byaddr.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: byaddr.c,v 1.34.18.3 2005/04/29 00:15:49 marka Exp $ */ +/* $Id: byaddr.c,v 1.39 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/cache.c b/lib/dns/cache.c index c9b4a95..aee824e 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,13 +15,14 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cache.c,v 1.57.18.18 2008/02/07 23:45:56 tbox Exp $ */ +/* $Id: cache.c,v 1.80.50.3 2009/05/06 23:34:30 jinmei Exp $ */ /*! \file */ #include <config.h> #include <isc/mem.h> +#include <isc/string.h> #include <isc/task.h> #include <isc/time.h> #include <isc/timer.h> @@ -47,7 +48,7 @@ * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize(). * See also DNS_CACHE_CLEANERINCREMENT */ -#define DNS_CACHE_MINSIZE 2097152 /*%< Bytes. 2097152 = 2 MB */ +#define DNS_CACHE_MINSIZE 2097152 /*%< Bytes. 2097152 = 2 MB */ /*! * Control incremental cleaning. * CLEANERINCREMENT is how many nodes are examined in one pass. @@ -60,7 +61,7 @@ ***/ /* - * A cache_cleaner_t encapsulsates the state of the periodic + * A cache_cleaner_t encapsulates the state of the periodic * cache cleaning. */ @@ -69,7 +70,7 @@ typedef struct cache_cleaner cache_cleaner_t; typedef enum { cleaner_s_idle, /*%< Waiting for cleaning-interval to expire. */ cleaner_s_busy, /*%< Currently cleaning. */ - cleaner_s_done /*%< Freed enough memory after being overmem. */ + cleaner_s_done /*%< Freed enough memory after being overmem. */ } cleaner_state_t; /* @@ -95,19 +96,19 @@ struct cache_cleaner { */ dns_cache_t *cache; - isc_task_t *task; + isc_task_t *task; unsigned int cleaning_interval; /*% The cleaning-interval from named.conf, in seconds. */ - isc_timer_t *cleaning_timer; + isc_timer_t *cleaning_timer; isc_event_t *resched_event; /*% Sent by cleaner task to itself to reschedule */ isc_event_t *overmem_event; dns_dbiterator_t *iterator; - unsigned int increment; /*% Number of names to + unsigned int increment; /*% Number of names to clean in one increment */ - cleaner_state_t state; /*% Idle/Busy. */ - isc_boolean_t overmem; /*% The cache is in an overmem state. */ + cleaner_state_t state; /*% Idle/Busy. */ + isc_boolean_t overmem; /*% The cache is in an overmem state. */ isc_boolean_t replaceiterator; }; @@ -133,7 +134,7 @@ struct dns_cache { char **db_argv; /* Locked by 'filelock'. */ - char * filename; + char *filename; /* Access to the on-disk cache file is also locked by 'filelock'. */ }; @@ -157,79 +158,6 @@ cleaner_shutdown_action(isc_task_t *task, isc_event_t *event); static void overmem_cleaning_action(isc_task_t *task, isc_event_t *event); -/*% - * Work out how many nodes can be cleaned in the time between two - * requests to the nameserver. Smooth the resulting number and use - * it as a estimate for the number of nodes to be cleaned in the next - * iteration. - */ -static void -adjust_increment(cache_cleaner_t *cleaner, unsigned int remaining, - isc_time_t *start) -{ - isc_time_t end; - isc_uint64_t usecs; - isc_uint64_t new; - unsigned int pps = dns_pps; - unsigned int interval; - unsigned int names; - - /* - * Tune for minumum of 100 packets per second (pps). - */ - if (pps < 100) - pps = 100; - - isc_time_now(&end); - - interval = 1000000 / pps; /* Interval between packets in usecs. */ - if (interval == 0) - interval = 1; - - INSIST(cleaner->increment >= remaining); - names = cleaner->increment - remaining; - usecs = isc_time_microdiff(&end, start); - - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, - ISC_LOG_DEBUG(1), "adjust_increment interval=%u " - "names=%u usec=%" ISC_PLATFORM_QUADFORMAT "u", - interval, names, usecs); - - if (usecs == 0) { - /* - * If we cleaned all the nodes in unmeasurable time - * double the number of nodes to be cleaned next time. - */ - if (names == cleaner->increment) { - cleaner->increment *= 2; - if (cleaner->increment > DNS_CACHE_CLEANERINCREMENT) - cleaner->increment = DNS_CACHE_CLEANERINCREMENT; - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), - "%p:new cleaner->increment = %u\n", - cleaner, cleaner->increment); - } - return; - } - - new = (names * interval); - new /= (usecs * 2); - if (new == 0) - new = 1; - - /* Smooth */ - new = (new + cleaner->increment * 7) / 8; - - if (new > DNS_CACHE_CLEANERINCREMENT) - new = DNS_CACHE_CLEANERINCREMENT; - - cleaner->increment = (unsigned int)new; - - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, - ISC_LOG_DEBUG(1), "%p:new cleaner->increment = %u\n", - cleaner, cleaner->increment); -} - static inline isc_result_t cache_create_db(dns_cache_t *cache, dns_db_t **db) { return (dns_db_create(cache->mctx, cache->db_type, dns_rootname, @@ -246,6 +174,7 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_result_t result; dns_cache_t *cache; int i; + isc_task_t *dbtask; REQUIRE(cachep != NULL); REQUIRE(*cachep == NULL); @@ -301,12 +230,29 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, result = cache_create_db(cache, &cache->db); if (result != ISC_R_SUCCESS) goto cleanup_dbargv; + if (taskmgr != NULL) { + dbtask = NULL; + result = isc_task_create(taskmgr, 1, &dbtask); + if (result != ISC_R_SUCCESS) + goto cleanup_db; + dns_db_settask(cache->db, dbtask); + isc_task_detach(&dbtask); + } cache->filename = NULL; cache->magic = CACHE_MAGIC; - result = cache_cleaner_init(cache, taskmgr, timermgr, &cache->cleaner); + /* + * RBT-type cache DB has its own mechanism of cache cleaning and doesn't + * need the control of the generic cleaner. + */ + if (strcmp(db_type, "rbt") == 0) + result = cache_cleaner_init(cache, NULL, NULL, &cache->cleaner); + else { + result = cache_cleaner_init(cache, taskmgr, timermgr, + &cache->cleaner); + } if (result != ISC_R_SUCCESS) goto cleanup_db; @@ -603,8 +549,7 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr, cleaner->cleaning_interval = 0; /* Initially turned off. */ result = isc_timer_create(timermgr, isc_timertype_inactive, - NULL, NULL, - cleaner->task, + NULL, NULL, cleaner->task, cleaning_timer_action, cleaner, &cleaner->cleaning_timer); if (result != ISC_R_SUCCESS) { @@ -848,7 +793,6 @@ incremental_cleaning_action(isc_task_t *task, isc_event_t *event) { "cache cleaner: dns_dbiterator_current() " "failed: %s", dns_result_totext(result)); - adjust_increment(cleaner, n_names, &start); end_cleaning(cleaner, event); return; } @@ -892,14 +836,11 @@ incremental_cleaning_action(isc_task_t *task, isc_event_t *event) { } } - adjust_increment(cleaner, n_names, &start); end_cleaning(cleaner, event); return; } } - adjust_increment(cleaner, 0U, &start); - /* * We have successfully performed a cleaning increment but have * not gone through the entire cache. Free the iterator locks @@ -929,7 +870,7 @@ dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) { REQUIRE(VALID_CACHE(cache)); - result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator); + result = dns_db_createiterator(cache->db, 0, &iterator); if (result != ISC_R_SUCCESS) return result; @@ -1002,7 +943,7 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) { REQUIRE(VALID_CACHE(cache)); /* - * Impose a minumum cache size; pathological things happen if there + * Impose a minimum cache size; pathological things happen if there * is too little room. */ if (size != 0 && size < DNS_CACHE_MINSIZE) diff --git a/lib/dns/callbacks.c b/lib/dns/callbacks.c index a487ed0..928f37d 100644 --- a/lib/dns/callbacks.c +++ b/lib/dns/callbacks.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: callbacks.c,v 1.13.18.2 2005/04/29 00:15:49 marka Exp $ */ +/* $Id: callbacks.c,v 1.17 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/compress.c b/lib/dns/compress.c index 2103767..11473ee 100644 --- a/lib/dns/compress.c +++ b/lib/dns/compress.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: compress.c,v 1.52.18.5 2006/03/02 00:37:21 marka Exp $ */ +/* $Id: compress.c,v 1.59 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/db.c b/lib/dns/db.c index 32ff6ae..a4c2864 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.c,v 1.74.18.6 2005/10/13 02:12:24 marka Exp $ */ +/* $Id: db.c,v 1.88 2008/09/24 02:46:22 marka Exp $ */ /*! \file */ @@ -95,7 +95,7 @@ static inline dns_dbimplementation_t * impfind(const char *name) { dns_dbimplementation_t *imp; - for (imp = ISC_LIST_HEAD(implementations); + for (imp = ISC_LIST_HEAD(implementations); imp != NULL; imp = ISC_LIST_NEXT(imp, link)) if (strcasecmp(name, imp->name) == 0) @@ -229,6 +229,21 @@ dns_db_isstub(dns_db_t *db) { } isc_boolean_t +dns_db_isdnssec(dns_db_t *db) { + + /* + * Is 'db' secure or partially secure? + */ + + REQUIRE(DNS_DB_VALID(db)); + REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0); + + if (db->methods->isdnssec != NULL) + return ((db->methods->isdnssec)(db)); + return ((db->methods->issecure)(db)); +} + +isc_boolean_t dns_db_issecure(dns_db_t *db) { /* @@ -450,6 +465,21 @@ dns_db_findnode(dns_db_t *db, dns_name_t *name, } isc_result_t +dns_db_findnsec3node(dns_db_t *db, dns_name_t *name, + isc_boolean_t create, dns_dbnode_t **nodep) +{ + + /* + * Find the node with name 'name'. + */ + + REQUIRE(DNS_DB_VALID(db)); + REQUIRE(nodep != NULL && *nodep == NULL); + + return ((db->methods->findnsec3node)(db, name, create, nodep)); +} + +isc_result_t dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, @@ -527,6 +557,30 @@ dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep) { ENSURE(*nodep == NULL); } +void +dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep, + dns_dbnode_t **targetp) +{ + REQUIRE(DNS_DB_VALID(db)); + REQUIRE(targetp != NULL && *targetp == NULL); + /* + * This doesn't check the implementation magic. If we find that + * we need such checks in future then this will be done in the + * method. + */ + REQUIRE(sourcep != NULL && *sourcep != NULL); + + UNUSED(db); + + if (db->methods->transfernode == NULL) { + *targetp = *sourcep; + *sourcep = NULL; + } else + (db->methods->transfernode)(db, sourcep, targetp); + + ENSURE(*sourcep == NULL); +} + isc_result_t dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { @@ -559,7 +613,7 @@ dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { ***/ isc_result_t -dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names, +dns_db_createiterator(dns_db_t *db, unsigned int flags, dns_dbiterator_t **iteratorp) { /* @@ -569,7 +623,7 @@ dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names, REQUIRE(DNS_DB_VALID(db)); REQUIRE(iteratorp != NULL && *iteratorp == NULL); - return (db->methods->createiterator(db, relative_names, iteratorp)); + return (db->methods->createiterator(db, flags, iteratorp)); } /*** @@ -687,7 +741,7 @@ dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, type, covers)); } -void +void dns_db_overmem(dns_db_t *db, isc_boolean_t overmem) { REQUIRE(DNS_DB_VALID(db)); @@ -713,11 +767,11 @@ dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp) dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0, (isc_stdtime_t)0, &rdataset, NULL); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) goto freenode; result = dns_rdataset_first(&rdataset); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) goto freerdataset; dns_rdataset_current(&rdataset, &rdata); result = dns_rdataset_next(&rdataset); @@ -770,7 +824,7 @@ dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg, RWUNLOCK(&implock, isc_rwlocktype_write); return (ISC_R_EXISTS); } - + imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t)); if (imp == NULL) { RWUNLOCK(&implock, isc_rwlocktype_write); @@ -819,3 +873,54 @@ dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { return (ISC_R_NOTFOUND); } + +dns_stats_t * +dns_db_getrrsetstats(dns_db_t *db) { + REQUIRE(DNS_DB_VALID(db)); + + if (db->methods->getrrsetstats != NULL) + return ((db->methods->getrrsetstats)(db)); + + return (NULL); +} + +isc_result_t +dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, + dns_hash_t *hash, isc_uint8_t *flags, + isc_uint16_t *iterations, + unsigned char *salt, size_t *salt_length) +{ + REQUIRE(DNS_DB_VALID(db)); + REQUIRE(dns_db_iszone(db) == ISC_TRUE); + + if (db->methods->getnsec3parameters != NULL) + return ((db->methods->getnsec3parameters)(db, version, hash, + flags, iterations, + salt, salt_length)); + + return (ISC_R_NOTFOUND); +} + +isc_result_t +dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, + isc_stdtime_t resign) +{ + if (db->methods->setsigningtime != NULL) + return ((db->methods->setsigningtime)(db, rdataset, resign)); + return (ISC_R_NOTIMPLEMENTED); +} + +isc_result_t +dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name) +{ + if (db->methods->getsigningtime != NULL) + return ((db->methods->getsigningtime)(db, rdataset, name)); + return (ISC_R_NOTFOUND); +} + +void +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/dbiterator.c b/lib/dns/dbiterator.c index d462ad5..8981e49 100644 --- a/lib/dns/dbiterator.c +++ b/lib/dns/dbiterator.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dbiterator.c,v 1.14.18.2 2005/04/29 00:15:50 marka Exp $ */ +/* $Id: dbiterator.c,v 1.18 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/dbtable.c b/lib/dns/dbtable.c index b091e42..57bbfc1 100644 --- a/lib/dns/dbtable.c +++ b/lib/dns/dbtable.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -16,7 +16,7 @@ */ /* - * $Id: dbtable.c,v 1.28.18.3 2005/07/12 01:22:19 marka Exp $ + * $Id: dbtable.c,v 1.33 2007/06/19 23:47:16 tbox Exp $ */ /*! \file diff --git a/lib/dns/diff.c b/lib/dns/diff.c index 22a3938..9489821 100644 --- a/lib/dns/diff.c +++ b/lib/dns/diff.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: diff.c,v 1.9.18.3 2005/04/27 05:01:15 sra Exp $ */ +/* $Id: diff.c,v 1.18.50.2 2009/01/05 23:47:22 tbox Exp $ */ /*! \file */ @@ -35,6 +35,7 @@ #include <dns/rdataclass.h> #include <dns/rdatalist.h> #include <dns/rdataset.h> +#include <dns/rdatastruct.h> #include <dns/rdatatype.h> #include <dns/result.h> @@ -120,6 +121,7 @@ dns_difftuple_copy(dns_difftuple_t *orig, dns_difftuple_t **copyp) { void dns_diff_init(isc_mem_t *mctx, dns_diff_t *diff) { diff->mctx = mctx; + diff->resign = 0; ISC_LIST_INIT(diff->tuples); diff->magic = DNS_DIFF_MAGIC; } @@ -192,6 +194,40 @@ dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep) ENSURE(*tuplep == NULL); } +static isc_stdtime_t +setresign(dns_rdataset_t *modified, isc_uint32_t delta) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig; + isc_stdtime_t when; + isc_result_t result; + + result = dns_rdataset_first(modified); + INSIST(result == ISC_R_SUCCESS); + dns_rdataset_current(modified, &rdata); + (void)dns_rdata_tostruct(&rdata, &sig, NULL); + if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) + when = 0; + else + when = sig.timeexpire - delta; + dns_rdata_reset(&rdata); + + result = dns_rdataset_next(modified); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(modified, &rdata); + (void)dns_rdata_tostruct(&rdata, &sig, NULL); + if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) { + goto next_rr; + } + if (when == 0 || sig.timeexpire - delta < when) + when = sig.timeexpire - delta; + next_rr: + dns_rdata_reset(&rdata); + result = dns_rdataset_next(modified); + } + INSIST(result == ISC_R_NOMORE); + return (when); +} + static isc_result_t diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, isc_boolean_t warn) @@ -220,14 +256,15 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, * but such diffs should never be created in the first * place. */ - node = NULL; - CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); while (t != NULL && dns_name_equal(&t->name, name)) { dns_rdatatype_t type, covers; dns_diffop_t op; dns_rdatalist_t rdl; dns_rdataset_t rds; + dns_rdataset_t ardataset; + dns_rdataset_t *modified = NULL; + isc_boolean_t offline; op = t->op; type = t->rdata.type; @@ -255,6 +292,16 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, ISC_LIST_INIT(rdl.rdata); ISC_LINK_INIT(&rdl, link); + node = NULL; + if (type != dns_rdatatype_nsec3 && + covers != dns_rdatatype_nsec3) + CHECK(dns_db_findnode(db, name, ISC_TRUE, + &node)); + else + CHECK(dns_db_findnsec3node(db, name, ISC_TRUE, + &node)); + + offline = ISC_FALSE; while (t != NULL && dns_name_equal(&t->name, name) && t->op == op && @@ -269,13 +316,15 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, sizeof(classbuf)); if (t->ttl != rdl.ttl && warn) isc_log_write(DIFF_COMMON_LOGARGS, - ISC_LOG_WARNING, + ISC_LOG_WARNING, "'%s/%s/%s': TTL differs in " "rdataset, adjusting " "%lu -> %lu", namebuf, typebuf, classbuf, (unsigned long) t->ttl, (unsigned long) rdl.ttl); + if (t->rdata.flags & DNS_RDATA_OFFLINE) + offline = ISC_TRUE; ISC_LIST_APPEND(rdl.rdata, &t->rdata, link); t = ISC_LIST_NEXT(t, link); } @@ -285,28 +334,52 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, */ dns_rdataset_init(&rds); CHECK(dns_rdatalist_tordataset(&rdl, &rds)); + if (rds.type == dns_rdatatype_rrsig) + switch (op) { + case DNS_DIFFOP_ADDRESIGN: + case DNS_DIFFOP_DELRESIGN: + modified = &ardataset; + dns_rdataset_init(modified); + break; + default: + break; + } rds.trust = dns_trust_ultimate; /* * Merge the rdataset into the database. */ - if (op == DNS_DIFFOP_ADD) { + switch (op) { + case DNS_DIFFOP_ADD: + case DNS_DIFFOP_ADDRESIGN: result = dns_db_addrdataset(db, node, ver, 0, &rds, DNS_DBADD_MERGE| DNS_DBADD_EXACT| DNS_DBADD_EXACTTTL, - NULL); - } else if (op == DNS_DIFFOP_DEL) { + modified); + break; + case DNS_DIFFOP_DEL: + case DNS_DIFFOP_DELRESIGN: result = dns_db_subtractrdataset(db, node, ver, &rds, DNS_DBSUB_EXACT, - NULL); - } else { + modified); + break; + default: INSIST(0); } - if (result == DNS_R_UNCHANGED) { - /* + + if (result == ISC_R_SUCCESS) { + if (modified != NULL) { + isc_stdtime_t resign; + resign = setresign(modified, + diff->resign); + dns_db_setsigningtime(db, modified, + resign); + } + } else if (result == DNS_R_UNCHANGED) { + /* * This will not happen when executing a * dynamic update, because that code will * generate strictly minimal diffs. @@ -318,16 +391,21 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, "update with no effect"); - } else if (result == ISC_R_SUCCESS || - result == DNS_R_NXRRSET) { + } else if (result == DNS_R_NXRRSET) { /* * OK. */ } else { + if (modified != NULL && + dns_rdataset_isassociated(modified)) + dns_rdataset_disassociate(modified); CHECK(result); } + dns_db_detachnode(db, &node); + if (modified != NULL && + dns_rdataset_isassociated(modified)) + dns_rdataset_disassociate(modified); } - dns_db_detachnode(db, &node); } return (ISC_R_SUCCESS); @@ -455,7 +533,7 @@ dns_diff_sort(dns_diff_t *diff, dns_diff_compare_func *compare) { /* * Create an rdataset containing the single RR of the given - * tuple. The caller must allocate the the rdata, rdataset and + * tuple. The caller must allocate the rdata, rdataset and * an rdatalist structure for it to refer to. */ @@ -485,6 +563,7 @@ dns_diff_print(dns_diff_t *diff, FILE *file) { dns_difftuple_t *t; char *mem = NULL; unsigned int size = 2048; + const char *op = NULL; REQUIRE(DNS_DIFF_VALID(diff)); @@ -536,15 +615,20 @@ dns_diff_print(dns_diff_t *diff, FILE *file) { buf.used--; isc_buffer_usedregion(&buf, &r); + switch (t->op) { + case DNS_DIFFOP_EXISTS: op = "exists"; break; + case DNS_DIFFOP_ADD: op = "add"; break; + case DNS_DIFFOP_DEL: op = "del"; break; + case DNS_DIFFOP_ADDRESIGN: op = "add re-sign"; break; + case DNS_DIFFOP_DELRESIGN: op = "del re-sign"; break; + } if (file != NULL) - fprintf(file, "%s %.*s\n", - t->op == DNS_DIFFOP_ADD ? "add" : "del", - (int) r.length, (char *) r.base); + fprintf(file, "%s %.*s\n", op, (int) r.length, + (char *) r.base); else isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG(7), - "%s %.*s", - t->op == DNS_DIFFOP_ADD ? "add" : "del", - (int) r.length, (char *) r.base); + "%s %.*s", op, (int) r.length, + (char *) r.base); } result = ISC_R_SUCCESS; cleanup: diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 794cdb5..9b4e968 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.116.18.37 2008/09/04 00:24:41 jinmei Exp $ */ +/* $Id: dispatch.c,v 1.155.12.7 2009/04/28 21:39:45 jinmei Exp $ */ /*! \file */ @@ -32,6 +32,7 @@ #include <isc/portset.h> #include <isc/print.h> #include <isc/random.h> +#include <isc/stats.h> #include <isc/string.h> #include <isc/task.h> #include <isc/time.h> @@ -43,14 +44,18 @@ #include <dns/log.h> #include <dns/message.h> #include <dns/portlist.h> +#include <dns/stats.h> #include <dns/tcpmsg.h> #include <dns/types.h> typedef ISC_LIST(dns_dispentry_t) dns_displist_t; -typedef struct dispsocket dispsocket_t; +typedef struct dispsocket dispsocket_t; typedef ISC_LIST(dispsocket_t) dispsocketlist_t; +typedef struct dispportentry dispportentry_t; +typedef ISC_LIST(dispportentry_t) dispportlist_t; + /* ARC4 Random generator state */ typedef struct arc4ctx { isc_uint8_t i; @@ -76,6 +81,7 @@ struct dns_dispatchmgr { isc_mem_t *mctx; dns_acl_t *blackhole; dns_portlist_t *portlist; + isc_stats_t *stats; isc_entropy_t *entropy; /*%< entropy source */ /* Locked by "lock". */ @@ -170,7 +176,8 @@ struct dispsocket { isc_socket_t *socket; dns_dispatch_t *disp; isc_sockaddr_t host; - in_port_t localport; + in_port_t localport; /* XXX: should be removed later */ + dispportentry_t *portentry; dns_dispentry_t *resp; isc_task_t *task; ISC_LINK(dispsocket_t) link; @@ -178,6 +185,21 @@ struct dispsocket { ISC_LINK(dispsocket_t) blink; }; +/*% + * A port table entry. We remember every port we first open in a table with a + * reference counter so that we can 'reuse' the same port (with different + * destination addresses) using the SO_REUSEADDR socket option. + */ +struct dispportentry { + in_port_t port; + unsigned int refs; + ISC_LINK(struct dispportentry) link; +}; + +#ifndef DNS_DISPATCH_PORTTABLESIZE +#define DNS_DISPATCH_PORTTABLESIZE 1024 +#endif + #define INVALID_BUCKET (0xffffdead) /*% @@ -227,6 +249,8 @@ struct dns_dispatch { dns_tcpmsg_t tcpmsg; /*%< for tcp streams */ dns_qid_t *qid; arc4ctx_t arc4ctx; /*%< for QID/UDP port num */ + dispportlist_t *port_table; /*%< hold ports 'owned' by us */ + isc_mempool_t *portpool; /*%< port table entries */ }; #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') @@ -330,6 +354,12 @@ mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) { level, "dispatchmgr %p: %s", mgr, msgbuf); } +static inline void +inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) { + if (mgr->stats != NULL) + isc_stats_increment(mgr->stats, counter); +} + static void dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); @@ -677,6 +707,64 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { } /*% + * Manipulate port table per dispatch: find an entry for a given port number, + * create a new entry, and decrement a given entry with possible clean-up. + */ +static dispportentry_t * +port_search(dns_dispatch_t *disp, in_port_t port) { + dispportentry_t *portentry; + + REQUIRE(disp->port_table != NULL); + + portentry = ISC_LIST_HEAD(disp->port_table[port % + DNS_DISPATCH_PORTTABLESIZE]); + while (portentry != NULL) { + if (portentry->port == port) + return (portentry); + portentry = ISC_LIST_NEXT(portentry, link); + } + + return (NULL); +} + +static dispportentry_t * +new_portentry(dns_dispatch_t *disp, in_port_t port) { + dispportentry_t *portentry; + + REQUIRE(disp->port_table != NULL); + + portentry = isc_mempool_get(disp->portpool); + if (portentry == NULL) + return (portentry); + + portentry->port = port; + portentry->refs = 0; + ISC_LINK_INIT(portentry, link); + ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE], + portentry, link); + + return (portentry); +} + +static void +deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { + dispportentry_t *portentry = *portentryp; + + REQUIRE(disp->port_table != NULL); + REQUIRE(portentry != NULL && portentry->refs > 0); + + portentry->refs--; + if (portentry->refs == 0) { + ISC_LIST_UNLINK(disp->port_table[portentry->port % + DNS_DISPATCH_PORTTABLESIZE], + portentry, link); + isc_mempool_put(disp->portpool, portentry); + } + + *portentryp = NULL; +} + +/*% * Find a dispsocket for socket address 'dest', and port number 'port'. * Return NULL if no such entry exists. */ @@ -692,7 +780,7 @@ socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port, while (dispsock != NULL) { if (isc_sockaddr_equal(dest, &dispsock->host) && - dispsock->localport == port) + dispsock->portentry->port == port) return (dispsock); dispsock = ISC_LIST_NEXT(dispsock, blink); } @@ -720,6 +808,8 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, dispsocket_t *dispsock; unsigned int nports; in_port_t *ports; + unsigned int bindoptions; + dispportentry_t *portentry = NULL; if (isc_sockaddr_pf(&disp->local) == AF_INET) { nports = disp->mgr->nv4ports; @@ -745,6 +835,7 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, dispsock->socket = NULL; dispsock->disp = disp; dispsock->resp = NULL; + dispsock->portentry = NULL; isc_random_get(&r); dispsock->task = NULL; isc_task_attach(disp->task[r % disp->ntasks], &dispsock->task); @@ -767,16 +858,29 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, bucket = dns_hash(qid, dest, 0, port); if (socket_search(qid, dest, port, bucket) != NULL) continue; - - result = open_socket(sockmgr, &localaddr, 0, &sock); - if (result == ISC_R_SUCCESS || result != ISC_R_ADDRINUSE) + bindoptions = 0; + portentry = port_search(disp, port); + if (portentry != NULL) + bindoptions |= ISC_SOCKET_REUSEADDRESS; + result = open_socket(sockmgr, &localaddr, bindoptions, &sock); + if (result == ISC_R_SUCCESS) { + if (portentry == NULL) { + portentry = new_portentry(disp, port); + if (portentry == NULL) { + result = ISC_R_NOMEMORY; + break; + } + } + portentry->refs++; + break; + } else if (result != ISC_R_ADDRINUSE) break; } if (result == ISC_R_SUCCESS) { dispsock->socket = sock; dispsock->host = *dest; - dispsock->localport = port; + dispsock->portentry = portentry; dispsock->bucket = bucket; ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); *dispsockp = dispsock; @@ -813,6 +917,8 @@ destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { disp->nsockets--; dispsock->magic = 0; + if (dispsock->portentry != NULL) + deref_portentry(disp, &dispsock->portentry); if (dispsock->socket != NULL) isc_socket_detach(&dispsock->socket); if (ISC_LINK_LINKED(dispsock, blink)) { @@ -847,6 +953,9 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { dispsock->resp->dispsocket = NULL; } + INSIST(dispsock->portentry != NULL); + deref_portentry(disp, &dispsock->portentry); + if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) destroy_dispsocket(disp, &dispsock); else { @@ -1161,6 +1270,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { bucket, (resp == NULL ? "not found" : "found")); if (resp == NULL) { + inc_stats(mgr, dns_resstatscounter_mismatch); free_buffer(disp, ev->region.base, ev->region.length); goto unlock; } @@ -1168,6 +1278,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { &resp->host)) { dispatch_log(disp, LVL(90), "response to an exclusive socket doesn't match"); + inc_stats(mgr, dns_resstatscounter_mismatch); free_buffer(disp, ev->region.base, ev->region.length); goto unlock; } @@ -1603,6 +1714,9 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { if (mgr->blackhole != NULL) dns_acl_detach(&mgr->blackhole); + if (mgr->stats != NULL) + isc_stats_detach(&mgr->stats); + if (mgr->v4ports != NULL) { isc_mem_put(mctx, mgr->v4ports, mgr->nv4ports * sizeof(in_port_t)); @@ -1628,6 +1742,7 @@ open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, isc_sockettype_udp, &sock); if (result != ISC_R_SUCCESS) return (result); + isc_socket_setname(sock, "dispatcher", NULL); } else { result = isc_socket_open(sock); if (result != ISC_R_SUCCESS) @@ -1692,6 +1807,7 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_mem_attach(mctx, &mgr->mctx); mgr->blackhole = NULL; + mgr->stats = NULL; result = isc_mutex_init(&mgr->lock); if (result != ISC_R_SUCCESS) @@ -2001,6 +2117,15 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { destroy_mgr(&mgr); } +void +dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + REQUIRE(ISC_LIST_EMPTY(mgr->list)); + REQUIRE(mgr->stats == NULL); + + isc_stats_attach(stats, &mgr->stats); +} + static int port_cmp(const void *key, const void *ent) { in_port_t p1 = *(const in_port_t *)key; @@ -2269,6 +2394,8 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, ISC_LIST_INIT(disp->inactivesockets); disp->nsockets = 0; dispatch_arc4init(&disp->arc4ctx, mgr->entropy, NULL); + disp->port_table = NULL; + disp->portpool = NULL; result = isc_mutex_init(&disp->lock); if (result != ISC_R_SUCCESS) @@ -2298,13 +2425,14 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, /* - * MUST be unlocked, and not used by anthing. + * MUST be unlocked, and not used by anything. */ static void dispatch_free(dns_dispatch_t **dispp) { dns_dispatch_t *disp; dns_dispatchmgr_t *mgr; + int i; REQUIRE(VALID_DISPATCH(*dispp)); disp = *dispp; @@ -2329,6 +2457,18 @@ dispatch_free(dns_dispatch_t **dispp) if (disp->qid != NULL) qid_destroy(mgr->mctx, &disp->qid); + + if (disp->port_table != NULL) { + for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) + INSIST(ISC_LIST_EMPTY(disp->port_table[i])); + isc_mem_put(mgr->mctx, disp->port_table, + sizeof(disp->port_table[0]) * + DNS_DISPATCH_PORTTABLESIZE); + } + + if (disp->portpool != NULL) + isc_mempool_destroy(&disp->portpool); + disp->mgr = NULL; DESTROYLOCK(&disp->lock); disp->magic = 0; @@ -2462,9 +2602,8 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, } /* - * First, see if we have a dispatcher that matches. + * See if we have a dispatcher that matches. */ - disp = NULL; result = dispatch_find(mgr, localaddr, attributes, mask, &disp); if (result == ISC_R_SUCCESS) { disp->refcount++; @@ -2569,6 +2708,15 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, * If this fails 1024 times, we then ask the kernel for * choosing one. */ + } else { + /* Allow to reuse address for non-random ports. */ + result = open_socket(sockmgr, localaddr, + ISC_SOCKET_REUSEADDRESS, &sock); + + if (result == ISC_R_SUCCESS) + *sockp = sock; + + return (result); } memset(held, 0, sizeof(held)); @@ -2650,6 +2798,21 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, if (result != ISC_R_SUCCESS) goto deallocate_dispatch; } + + disp->port_table = isc_mem_get(mgr->mctx, + sizeof(disp->port_table[0]) * + DNS_DISPATCH_PORTTABLESIZE); + if (disp->port_table == NULL) + goto deallocate_dispatch; + for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) + ISC_LIST_INIT(disp->port_table[i]); + + result = isc_mempool_create(mgr->mctx, sizeof(dispportentry_t), + &disp->portpool); + if (result != ISC_R_SUCCESS) + goto deallocate_dispatch; + isc_mempool_setname(disp->portpool, "disp_portpool"); + isc_mempool_setfreemax(disp->portpool, 128); } disp->socktype = isc_sockettype_udp; disp->socket = sock; @@ -2829,6 +2992,8 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, oldestresp->item_out = ISC_TRUE; isc_task_send(oldestresp->task, ISC_EVENT_PTR(&rev)); + inc_stats(disp->mgr, + dns_resstatscounter_dispabort); } } @@ -2852,6 +3017,7 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, if (result != ISC_R_SUCCESS) { UNLOCK(&qid->lock); UNLOCK(&disp->lock); + inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); return (result); } } else { diff --git a/lib/dns/dlz.c b/lib/dns/dlz.c index ee6c03b..75486af 100644 --- a/lib/dns/dlz.c +++ b/lib/dns/dlz.c @@ -1,8 +1,8 @@ /* - * Portions Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlz.c,v 1.2.2.2 2005/09/06 03:47:17 marka Exp $ */ +/* $Id: dlz.c,v 1.5.332.2 2009/01/18 23:47:35 tbox Exp $ */ /*! \file */ @@ -126,7 +126,7 @@ dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name, dlzdatabase = view->dlzdatabase; allowzonexfr = dlzdatabase->implementation->methods->allowzonexfr; result = (*allowzonexfr)(dlzdatabase->implementation->driverarg, - dlzdatabase->dbdata, dlzdatabase->mctx, + dlzdatabase->dbdata, dlzdatabase->mctx, view->rdclass, name, clientaddr, dbp); if (result == ISC_R_NOTIMPLEMENTED) @@ -275,7 +275,7 @@ dns_dlzfindzone(dns_view_t *view, dns_name_t *name, unsigned int minlabels, * trying shorter names portions of the name until we find a * match, have an error, or are below the 'minlabels' * threshold. minlabels is 0, if the standard database didn't - * have a zone name match. Otherwise minlables is the number + * have a zone name match. Otherwise minlabels is the number * of labels in that name. We need to beat that for a * "better" match for the DLZ database to be authoritative * instead of the standard database. diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 75ca440..f06d715 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +16,7 @@ */ /* - * $Id: dnssec.c,v 1.81.18.10 2007/09/14 04:35:42 marka Exp $ + * $Id: dnssec.c,v 1.93 2008/11/14 23:47:33 tbox Exp $ */ /*! \file */ @@ -366,6 +366,9 @@ dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, if (ret != ISC_R_SUCCESS) return (ret); + if (set->type != sig.covered) + return (DNS_R_SIGINVALID); + if (isc_serial_lt(sig.timeexpire, sig.timesigned)) return (DNS_R_SIGINVALID); @@ -382,6 +385,27 @@ dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, } /* + * NS, SOA and DNSSKEY records are signed by their owner. + * DS records are signed by the parent. + */ + switch (set->type) { + case dns_rdatatype_ns: + case dns_rdatatype_soa: + case dns_rdatatype_dnskey: + if (!dns_name_equal(name, &sig.signer)) + return (DNS_R_SIGINVALID); + break; + case dns_rdatatype_ds: + if (dns_name_equal(name, &sig.signer)) + return (DNS_R_SIGINVALID); + /* FALLTHROUGH */ + default: + if (!dns_name_issubdomain(name, &sig.signer)) + return (DNS_R_SIGINVALID); + break; + } + + /* * Is the key allowed to sign data? */ flags = dst_key_flags(key); @@ -407,7 +431,7 @@ dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, dns_fixedname_init(&fnewname); labels = dns_name_countlabels(name) - 1; RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), - NULL) == ISC_R_SUCCESS); + NULL) == ISC_R_SUCCESS); if (labels - sig.labels > 0) dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1, NULL, dns_fixedname_name(&fnewname)); @@ -487,9 +511,9 @@ cleanup_struct: dns_rdata_freestruct(&sig); if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) { - if (wild != NULL) + if (wild != NULL) RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, - dns_fixedname_name(&fnewname), + dns_fixedname_name(&fnewname), wild, NULL) == ISC_R_SUCCESS); ret = DNS_R_FROMWILDCARD; } @@ -541,6 +565,9 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, if (!is_zone_key(pubkey) || (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0) goto next; + /* Corrupted .key file? */ + if (!dns_name_equal(name, dst_key_name(pubkey))) + goto next; keys[count] = NULL; result = dst_key_fromfile(dst_key_name(pubkey), dst_key_id(pubkey), @@ -802,7 +829,7 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, RETERR(dst_context_create(key, mctx, &ctx)); /* - * Digest the SIG(0) record, except for the signature. + * Digest the SIG(0) record, except for the signature. */ dns_rdata_toregion(&rdata, &r); r.length -= sig.siglen; diff --git a/lib/dns/ds.c b/lib/dns/ds.c index 7cd1609..e994cc5 100644 --- a/lib/dns/ds.c +++ b/lib/dns/ds.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds.c,v 1.4.20.5 2006/02/22 23:50:09 marka Exp $ */ +/* $Id: ds.c,v 1.11 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 7d98e10..144c685 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -1,9 +1,22 @@ /* - * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2003 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_api.c,v 1.1.6.7 2006/01/27 23:57:44 marka Exp $ + * $Id: dst_api.c,v 1.16.12.3 2009/03/02 02:00:34 marka Exp $ */ /*! \file */ @@ -60,6 +73,8 @@ static isc_entropy_t *dst_entropy_pool = NULL; static unsigned int dst_entropy_flags = 0; static isc_boolean_t dst_initialized = ISC_FALSE; +void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); + isc_mem_t *dst__memory_pool = NULL; /* @@ -110,19 +125,21 @@ static isc_result_t addsuffix(char *filename, unsigned int len, return (_r); \ } while (0); \ +#ifdef OPENSSL static void * default_memalloc(void *arg, size_t size) { - UNUSED(arg); - if (size == 0U) - size = 1; - return (malloc(size)); + UNUSED(arg); + if (size == 0U) + size = 1; + return (malloc(size)); } static void default_memfree(void *arg, void *ptr) { - UNUSED(arg); - free(ptr); + UNUSED(arg); + free(ptr); } +#endif isc_result_t dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { @@ -147,6 +164,7 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { NULL, &dst__memory_pool, 0); if (result != ISC_R_SUCCESS) return (result); + isc_mem_setname(dst__memory_pool, "dst", NULL); isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); #else isc_mem_attach(mctx, &dst__memory_pool); @@ -167,8 +185,10 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { RETERR(dst__openssl_init()); RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5])); RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1])); + RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1])); #ifdef HAVE_OPENSSL_DSA RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); + RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); #endif RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); #endif /* OPENSSL */ @@ -223,7 +243,7 @@ dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { if (key->func->createctx == NULL) return (DST_R_UNSUPPORTEDALG); - if (key->opaque == NULL) + if (key->keydata.generic == NULL) return (DST_R_NULLKEY); dctx = isc_mem_get(mctx, sizeof(dst_context_t)); @@ -273,8 +293,9 @@ dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { key = dctx->key; CHECKALG(key->key_alg); - if (key->opaque == NULL) + if (key->keydata.generic == NULL) return (DST_R_NULLKEY); + if (key->func->sign == NULL) return (DST_R_NOTPRIVATEKEY); if (key->func->isprivate == NULL || @@ -290,7 +311,7 @@ dst_context_verify(dst_context_t *dctx, isc_region_t *sig) { REQUIRE(sig != NULL); CHECKALG(dctx->key->key_alg); - if (dctx->key->opaque == NULL) + if (dctx->key->keydata.generic == NULL) return (DST_R_NULLKEY); if (dctx->key->func->verify == NULL) return (DST_R_NOTPUBLICKEY); @@ -309,7 +330,7 @@ dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, CHECKALG(pub->key_alg); CHECKALG(priv->key_alg); - if (pub->opaque == NULL || priv->opaque == NULL) + if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) return (DST_R_NULLKEY); if (pub->key_alg != priv->key_alg || @@ -383,10 +404,8 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, return (result); } - if (!dns_name_equal(name, key->key_name) || - id != key->key_id || - alg != key->key_alg) - { + if (!dns_name_equal(name, key->key_name) || id != key->key_id || + alg != key->key_alg) { dst_key_free(&key); return (DST_R_INVALIDPRIVATEKEY); } @@ -427,8 +446,7 @@ dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, return (result); if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || - (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) - { + (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { result = computeid(pubkey); if (result != ISC_R_SUCCESS) { dst_key_free(&pubkey); @@ -512,7 +530,7 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { & 0xffff)); } - if (key->opaque == NULL) /*%< NULL KEY */ + if (key->keydata.generic == NULL) /*%< NULL KEY */ return (ISC_R_SUCCESS); return (key->func->todns(key, target)); @@ -620,20 +638,71 @@ dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { return (result); } +gss_ctx_id_t +dst_key_getgssctx(const dst_key_t *key) +{ + REQUIRE(key != NULL); + + return (key->keydata.gssctx); +} + isc_result_t -dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx, +dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, dst_key_t **keyp) { dst_key_t *key; - REQUIRE(opaque != NULL); + REQUIRE(gssctx != NULL); REQUIRE(keyp != NULL && *keyp == NULL); key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 0, dns_rdataclass_in, mctx); if (key == NULL) return (ISC_R_NOMEMORY); - key->opaque = opaque; + + key->keydata.gssctx = gssctx; + *keyp = key; + return (ISC_R_SUCCESS); +} + +isc_result_t +dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + const char *engine, const char *label, const char *pin, + isc_mem_t *mctx, dst_key_t **keyp) +{ + dst_key_t *key; + isc_result_t result; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(dns_name_isabsolute(name)); + REQUIRE(mctx != NULL); + REQUIRE(keyp != NULL && *keyp == NULL); + REQUIRE(label != NULL); + + CHECKALG(alg); + + key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); + if (key == NULL) + return (ISC_R_NOMEMORY); + + if (key->func->fromlabel == NULL) { + dst_key_free(&key); + return (DST_R_UNSUPPORTEDALG); + } + + result = key->func->fromlabel(key, engine, label, pin); + if (result != ISC_R_SUCCESS) { + dst_key_free(&key); + return (result); + } + + result = computeid(key); + if (result != ISC_R_SUCCESS) { + dst_key_free(&key); + return (result); + } + *keyp = key; return (ISC_R_SUCCESS); } @@ -734,11 +803,14 @@ dst_key_free(dst_key_t **keyp) { key = *keyp; mctx = key->mctx; - if (key->opaque != NULL) { + if (key->keydata.generic != NULL) { INSIST(key->func->destroy != NULL); key->func->destroy(key); } - + if (key->engine != NULL) + isc_mem_free(mctx, key->engine); + if (key->label != NULL) + isc_mem_free(mctx, key->label); dns_name_free(key->key_name, mctx); isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); memset(key, 0, sizeof(dst_key_t)); @@ -775,9 +847,11 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) { switch (key->key_alg) { case DST_ALG_RSAMD5: case DST_ALG_RSASHA1: + case DST_ALG_NSEC3RSASHA1: *n = (key->key_size + 7) / 8; break; case DST_ALG_DSA: + case DST_ALG_NSEC3DSA: *n = DNS_SIG_DSASIGSIZE; break; case DST_ALG_HMACMD5: @@ -860,7 +934,7 @@ get_key_struct(dns_name_t *name, unsigned int alg, key->key_flags = flags; key->key_proto = protocol; key->mctx = mctx; - key->opaque = NULL; + key->keydata.generic = NULL; key->key_size = bits; key->key_class = rdclass; key->func = dst_t_func[alg]; @@ -925,6 +999,13 @@ dst_key_read_public(const char *filename, int type, NEXTTOKEN(lex, opt, &token); if (token.type != isc_tokentype_string) BADTOKEN(); + + /* + * We don't support "@" in .key files. + */ + if (!strcmp(DST_AS_STR(token), "@")) + BADTOKEN(); + dns_fixedname_init(&name); isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); isc_buffer_add(&b, strlen(DST_AS_STR(token))); @@ -990,7 +1071,9 @@ issymmetric(const dst_key_t *key) { switch (key->key_alg) { case DST_ALG_RSAMD5: case DST_ALG_RSASHA1: + case DST_ALG_NSEC3RSASHA1: case DST_ALG_DSA: + case DST_ALG_NSEC3DSA: case DST_ALG_DH: return (ISC_FALSE); case DST_ALG_HMACMD5: @@ -1080,9 +1163,12 @@ write_public_key(const dst_key_t *key, int type, const char *directory) { fwrite(r.base, 1, r.length, fp); fputc('\n', fp); + fflush(fp); + if (ferror(fp)) + ret = DST_R_WRITEERROR; fclose(fp); - return (ISC_R_SUCCESS); + return (ret); } static isc_result_t @@ -1116,8 +1202,10 @@ buildfilename(dns_name_t *name, dns_keytag_t id, len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; if (isc_buffer_availablelength(out) < len) return (ISC_R_NOSPACE); - sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix); + sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, + suffix); isc_buffer_add(out, len); + return (ISC_R_SUCCESS); } @@ -1186,7 +1274,8 @@ algorithm_status(unsigned int alg) { #ifndef OPENSSL if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || alg == DST_ALG_DSA || alg == DST_ALG_DH || - alg == DST_ALG_HMACMD5) + alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || + alg == DST_ALG_NSEC3RSASHA1) return (DST_R_NOCRYPTO); #endif return (DST_R_UNSUPPORTEDALG); @@ -1219,3 +1308,8 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { flags &= ~ISC_ENTROPY_GOODONLY; return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); } + +unsigned int +dst__entropy_status(void) { + return (isc_entropy_status(dst_entropy_pool)); +} diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index f2deb72..0c1a71c 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -1,9 +1,22 @@ /* - * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 2000-2002 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -16,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_internal.h,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ */ +/* $Id: dst_internal.h,v 1.11 2008/04/01 23:47:10 tbox Exp $ */ #ifndef DST_DST_INTERNAL_H #define DST_DST_INTERNAL_H 1 @@ -27,9 +40,22 @@ #include <isc/magic.h> #include <isc/region.h> #include <isc/types.h> +#include <isc/md5.h> +#include <isc/sha1.h> +#include <isc/hmacmd5.h> +#include <isc/hmacsha.h> #include <dst/dst.h> +#ifdef OPENSSL +#include <openssl/dh.h> +#include <openssl/dsa.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/rsa.h> +#endif + ISC_LANG_BEGINDECLS #define KEY_MAGIC ISC_MAGIC('D','S','T','K') @@ -46,6 +72,13 @@ extern isc_mem_t *dst__memory_pool; typedef struct dst_func dst_func_t; +typedef struct dst_hmacmd5_key dst_hmacmd5_key_t; +typedef struct dst_hmacsha1_key dst_hmacsha1_key_t; +typedef struct dst_hmacsha224_key dst_hmacsha224_key_t; +typedef struct dst_hmacsha256_key dst_hmacsha256_key_t; +typedef struct dst_hmacsha384_key dst_hmacsha384_key_t; +typedef struct dst_hmacsha512_key dst_hmacsha512_key_t; + /*% DST Key Structure */ struct dst_key { unsigned int magic; @@ -58,7 +91,27 @@ struct dst_key { isc_uint16_t key_bits; /*%< hmac digest bits */ dns_rdataclass_t key_class; /*%< class of the key record */ isc_mem_t *mctx; /*%< memory context */ - void * opaque; /*%< pointer to key in crypto pkg fmt */ + char *engine; /*%< engine name (HSM) */ + char *label; /*%< engine label (HSM) */ + union { + void *generic; + gss_ctx_id_t gssctx; +#ifdef OPENSSL +#if USE_EVP_RSA + RSA *rsa; +#endif + DSA *dsa; + DH *dh; + EVP_PKEY *pkey; +#endif + dst_hmacmd5_key_t *hmacmd5; + dst_hmacsha1_key_t *hmacsha1; + dst_hmacsha224_key_t *hmacsha224; + dst_hmacsha256_key_t *hmacsha256; + dst_hmacsha384_key_t *hmacsha384; + dst_hmacsha512_key_t *hmacsha512; + + } keydata; /*%< pointer to key in crypto pkg fmt */ dst_func_t * func; /*%< crypto package specific functions */ }; @@ -66,7 +119,21 @@ struct dst_context { unsigned int magic; dst_key_t *key; isc_mem_t *mctx; - void *opaque; + union { + void *generic; + dst_gssapi_signverifyctx_t *gssctx; + isc_md5_t *md5ctx; + isc_sha1_t *sha1ctx; + isc_hmacmd5_t *hmacmd5ctx; + isc_hmacsha1_t *hmacsha1ctx; + isc_hmacsha224_t *hmacsha224ctx; + isc_hmacsha256_t *hmacsha256ctx; + isc_hmacsha384_t *hmacsha384ctx; + isc_hmacsha512_t *hmacsha512ctx; +#ifdef OPENSSL + EVP_MD_CTX *evp_md_ctx; +#endif + } ctxdata; }; struct dst_func { @@ -100,6 +167,9 @@ struct dst_func { /* cleanup */ void (*cleanup)(void); + + isc_result_t (*fromlabel)(dst_key_t *key, const char *engine, + const char *label, const char *pin); }; /*% @@ -136,6 +206,11 @@ void * dst__mem_realloc(void *ptr, size_t size); isc_result_t dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo); +/* + * Entropy status hook. + */ +unsigned int dst__entropy_status(void); + ISC_LANG_ENDDECLS #endif /* DST_DST_INTERNAL_H */ diff --git a/lib/dns/dst_lib.c b/lib/dns/dst_lib.c index 305051c..f1021d3 100644 --- a/lib/dns/dst_lib.c +++ b/lib/dns/dst_lib.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -17,7 +17,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_lib.c,v 1.1.6.3 2005/04/29 00:15:51 marka Exp $ + * $Id: dst_lib.c,v 1.5 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/dst_openssl.h b/lib/dns/dst_openssl.h index 79e10b0..80eef93 100644 --- a/lib/dns/dst_openssl.h +++ b/lib/dns/dst_openssl.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_openssl.h,v 1.1.4.3 2005/04/29 00:15:52 marka Exp $ */ +/* $Id: dst_openssl.h,v 1.7 2008/04/01 23:47:10 tbox Exp $ */ #ifndef DST_OPENSSL_H #define DST_OPENSSL_H 1 @@ -28,6 +28,12 @@ ISC_LANG_BEGINDECLS isc_result_t dst__openssl_toresult(isc_result_t fallback); +ENGINE * +dst__openssl_getengine(const char *name); + +isc_result_t +dst__openssl_setdefault(const char *name); + ISC_LANG_ENDDECLS #endif /* DST_OPENSSL_H */ diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index ce361ef..2da72ae 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -1,6 +1,19 @@ /* - * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * * Permission to use, copy, modify, and/or distribute this software for any @@ -18,7 +31,7 @@ /*% * Principal Author: Brian Wellington - * $Id: dst_parse.c,v 1.1.6.9 2008/01/22 23:27:05 tbox Exp $ + * $Id: dst_parse.c,v 1.14.120.2 2009/03/02 23:47:11 tbox Exp $ */ #include <config.h> @@ -54,6 +67,9 @@ static struct parse_map map[] = { {TAG_RSA_EXPONENT1, "Exponent1:"}, {TAG_RSA_EXPONENT2, "Exponent2:"}, {TAG_RSA_COEFFICIENT, "Coefficient:"}, + {TAG_RSA_ENGINE, "Engine:" }, + {TAG_RSA_LABEL, "Label:" }, + {TAG_RSA_PIN, "PIN:" }, {TAG_DH_PRIME, "Prime(p):"}, {TAG_DH_GENERATOR, "Generator(g):"}, @@ -115,16 +131,39 @@ find_tag(const int value) { static int check_rsa(const dst_private_t *priv) { int i, j; - if (priv->nelements != RSA_NTAGS) - return (-1); - for (i = 0; i < RSA_NTAGS; i++) { - for (j = 0; j < priv->nelements; j++) + isc_boolean_t have[RSA_NTAGS]; + isc_boolean_t ok; + unsigned int mask; + + for (i = 0; i < RSA_NTAGS; i++) + have[i] = ISC_FALSE; + for (j = 0; j < priv->nelements; j++) { + for (i = 0; i < RSA_NTAGS; i++) if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i)) break; - if (j == priv->nelements) + if (i == RSA_NTAGS) return (-1); + have[i] = ISC_TRUE; } - return (0); + + mask = ~0; + mask <<= sizeof(mask) * 8 - TAG_SHIFT; + mask >>= sizeof(mask) * 8 - TAG_SHIFT; + + if (have[TAG_RSA_ENGINE & mask]) + ok = have[TAG_RSA_MODULUS & mask] && + have[TAG_RSA_PUBLICEXPONENT & mask] && + have[TAG_RSA_LABEL & mask]; + else + ok = have[TAG_RSA_MODULUS & mask] && + have[TAG_RSA_PUBLICEXPONENT & mask] && + have[TAG_RSA_PRIVATEEXPONENT & mask] && + have[TAG_RSA_PRIME1 & mask] && + have[TAG_RSA_PRIME2 & mask] && + have[TAG_RSA_EXPONENT1 & mask] && + have[TAG_RSA_EXPONENT2 & mask] && + have[TAG_RSA_COEFFICIENT & mask]; + return (ok ? 0 : -1 ); } static int @@ -486,8 +525,10 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, fprintf(fp, "\n"); } + fflush(fp); + iret = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS; fclose(fp); - return (ISC_R_SUCCESS); + return (iret); } /*! \file */ diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h index 665fcfc..27c7580 100644 --- a/lib/dns/dst_parse.h +++ b/lib/dns/dst_parse.h @@ -1,6 +1,19 @@ /* - * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 2000-2002 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_parse.h,v 1.1.6.7 2008/05/15 23:46:06 tbox Exp $ */ +/* $Id: dst_parse.h,v 1.11 2008/05/15 00:50:26 each Exp $ */ /*! \file */ #ifndef DST_DST_PARSE_H @@ -37,7 +50,7 @@ #define TAG(alg, off) (((alg) << TAG_SHIFT) + (off)) /* These are used by both RSA-MD5 and RSA-SHA1 */ -#define RSA_NTAGS 8 +#define RSA_NTAGS 11 #define TAG_RSA_MODULUS ((DST_ALG_RSAMD5 << TAG_SHIFT) + 0) #define TAG_RSA_PUBLICEXPONENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 1) #define TAG_RSA_PRIVATEEXPONENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 2) @@ -46,6 +59,9 @@ #define TAG_RSA_EXPONENT1 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 5) #define TAG_RSA_EXPONENT2 ((DST_ALG_RSAMD5 << TAG_SHIFT) + 6) #define TAG_RSA_COEFFICIENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 7) +#define TAG_RSA_ENGINE ((DST_ALG_RSAMD5 << TAG_SHIFT) + 8) +#define TAG_RSA_LABEL ((DST_ALG_RSAMD5 << TAG_SHIFT) + 9) +#define TAG_RSA_PIN ((DST_ALG_RSAMD5 << TAG_SHIFT) + 10) #define DH_NTAGS 4 #define TAG_DH_PRIME ((DST_ALG_DH << TAG_SHIFT) + 0) diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c index c9bf073..429dbb2 100644 --- a/lib/dns/dst_result.c +++ b/lib/dns/dst_result.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -17,7 +17,7 @@ /*% * Principal Author: Brian Wellington - * $Id: dst_result.c,v 1.1.6.3 2005/04/29 00:15:52 marka Exp $ + * $Id: dst_result.c,v 1.7 2008/04/01 23:47:10 tbox Exp $ */ #include <config.h> @@ -49,7 +49,8 @@ static const char *text[DST_R_NRESULTS] = { "not a key that can compute a secret", /*%< 17 */ "failure computing a shared secret", /*%< 18 */ "no randomness available", /*%< 19 */ - "bad key type" /*%< 20 */ + "bad key type", /*%< 20 */ + "no engine" /*%< 21 */ }; #define DST_RESULT_RESULTSET 2 diff --git a/lib/dns/forward.c b/lib/dns/forward.c index e80a477..39e2ef5 100644 --- a/lib/dns/forward.c +++ b/lib/dns/forward.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: forward.c,v 1.6.18.4 2005/07/12 01:22:20 marka Exp $ */ +/* $Id: forward.c,v 1.12 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/gen-unix.h b/lib/dns/gen-unix.h index fc2dbf2..4186f63 100644 --- a/lib/dns/gen-unix.h +++ b/lib/dns/gen-unix.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gen-unix.h,v 1.14.18.3 2005/06/08 02:07:54 marka Exp $ */ +/* $Id: gen-unix.h,v 1.19.332.2 2009/01/18 23:47:35 tbox Exp $ */ /*! \file * \brief @@ -23,7 +23,7 @@ * directly portable between Unix-like systems and Windows NT, option * parsing and directory scanning. It is here because it was decided * that the "gen" build utility was not to depend on libisc.a, so - * the functions delcared in isc/commandline.h and isc/dir.h could not + * the functions declared in isc/commandline.h and isc/dir.h could not * be used. * * The commandline stuff is really just a wrapper around getopt(). diff --git a/lib/dns/gen.c b/lib/dns/gen.c index 1e6212a..ede8bc0 100644 --- a/lib/dns/gen.c +++ b/lib/dns/gen.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gen.c,v 1.73.18.6 2006/10/02 06:36:43 marka Exp $ */ +/* $Id: gen.c,v 1.83 2008/09/25 04:02:38 tbox Exp $ */ /*! \file */ @@ -41,6 +41,8 @@ #include "gen-unix.h" #endif +#define TYPECLASSLEN 21 + #define FROMTEXTARGS "rdclass, type, lexer, origin, options, target, callbacks" #define FROMTEXTCLASS "rdclass" #define FROMTEXTTYPE "type" @@ -134,21 +136,21 @@ const char copyright[] = struct cc { struct cc *next; int rdclass; - char classname[11]; + char classname[TYPECLASSLEN]; } *classes; struct tt { struct tt *next; int rdclass; int type; - char classname[11]; - char typename[11]; + char classname[TYPECLASSLEN]; + char typename[TYPECLASSLEN]; char dirname[256]; /* XXX Should be max path length */ } *types; struct ttnam { - char typename[11]; - char macroname[11]; + char typename[TYPECLASSLEN]; + char macroname[TYPECLASSLEN]; char attr[256]; unsigned int sorted; int type; @@ -215,7 +217,7 @@ doswitch(const char *name, const char *function, const char *args, int first = 1; int lasttype = 0; int subswitch = 0; - char buf1[11], buf2[11]; + char buf1[TYPECLASSLEN], buf2[TYPECLASSLEN]; const char *result = " result ="; if (res == NULL) @@ -281,7 +283,7 @@ doswitch(const char *name, const char *function, const char *args, void dodecl(char *type, char *function, char *args) { struct tt *tt; - char buf1[11], buf2[11]; + char buf1[TYPECLASSLEN], buf2[TYPECLASSLEN]; fputs("\n", stdout); for (tt = types; tt; tt = tt->next) @@ -332,7 +334,7 @@ insert_into_typenames(int type, const char *typename, const char *attr) { fprintf(stderr, "Error: typenames array too small\n"); exit(1); } - + if (strlen(typename) > sizeof(ttn->typename) - 1) { fprintf(stderr, "Error: type name %s is too long\n", typename); @@ -392,6 +394,8 @@ add(int rdclass, const char *classname, int type, const char *typename, newtt->type = type; strcpy(newtt->classname, classname); strcpy(newtt->typename, typename); + if (strncmp(dirname, "./", 2) == 0) + dirname += 2; strcpy(newtt->dirname, dirname); tt = types; @@ -449,16 +453,16 @@ add(int rdclass, const char *classname, int type, const char *typename, void sd(int rdclass, const char *classname, const char *dirname, char filetype) { - char buf[sizeof("0123456789_65535.h")]; - char fmt[sizeof("%10[-0-9a-z]_%d.h")]; + char buf[sizeof("01234567890123456789_65535.h")]; + char fmt[sizeof("%20[-0-9a-z]_%d.h")]; int type; - char typename[11]; + char typename[TYPECLASSLEN]; isc_dir_t dir; if (!start_directory(dirname, &dir)) return; - sprintf(fmt,"%s%c", "%10[-0-9a-z]_%d.", filetype); + sprintf(fmt,"%s%c", "%20[-0-9a-z]_%d.", filetype); while (next_file(&dir)) { if (sscanf(dir.filename, fmt, typename, &type) != 2) continue; @@ -495,7 +499,7 @@ main(int argc, char **argv) { char buf[256]; /* XXX Should be max path length */ char srcdir[256]; /* XXX Should be max path length */ int rdclass; - char classname[11]; + char classname[TYPECLASSLEN]; struct tt *tt; struct cc *cc; struct ttnam *ttn, *ttn2; @@ -510,7 +514,7 @@ main(int argc, char **argv) { int structs = 0; int depend = 0; int c, i, j; - char buf1[11]; + char buf1[TYPECLASSLEN]; char filetype = 'c'; FILE *fd; char *prefix = NULL; @@ -594,7 +598,7 @@ main(int argc, char **argv) { sd(0, "", buf, filetype); if (time(&now) != -1) { - if ((tm = localtime(&now)) != NULL && tm->tm_year > 104) + if ((tm = localtime(&now)) != NULL && tm->tm_year > 104) sprintf(year, "-%d", tm->tm_year + 1900); else year[0] = 0; @@ -692,7 +696,7 @@ main(int argc, char **argv) { "\t\t strncasecmp(_s,(_tn)," "(sizeof(_s) - 1)) == 0) { \\\n"); fprintf(stdout, "\t\t\tif ((dns_rdatatype_attributes(_d) & " - "DNS_RDATATYPEATTR_RESERVED) != 0) \\\n"); + "DNS_RDATATYPEATTR_RESERVED) != 0) \\\n"); fprintf(stdout, "\t\t\t\treturn (ISC_R_NOTIMPLEMENTED); \\\n"); fprintf(stdout, "\t\t\t*(_tp) = _d; \\\n"); fprintf(stdout, "\t\t\treturn (ISC_R_SUCCESS); \\\n"); @@ -743,7 +747,7 @@ main(int argc, char **argv) { if (ttn == NULL) continue; fprintf(stdout, "\tcase %u: return (%s); \\\n", - i, upper(ttn->attr)); + i, upper(ttn->attr)); } fprintf(stdout, "\t}\n"); @@ -755,7 +759,7 @@ main(int argc, char **argv) { continue; fprintf(stdout, "\tcase %u: return " "(str_totext(\"%s\", target)); \\\n", - i, upper(ttn->typename)); + i, upper(ttn->typename)); } fprintf(stdout, "\t}\n"); diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c index a6a367a..0dd27bb 100644 --- a/lib/dns/gssapi_link.c +++ b/lib/dns/gssapi_link.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -16,13 +16,13 @@ */ /* - * $Id: gssapi_link.c,v 1.1.6.3 2005/04/29 00:15:53 marka Exp $ + * $Id: gssapi_link.c,v 1.12 2008/11/11 03:55:01 marka Exp $ */ -#ifdef GSSAPI - #include <config.h> +#ifdef GSSAPI + #include <isc/buffer.h> #include <isc/mem.h> #include <isc/string.h> @@ -33,60 +33,73 @@ #include "dst_internal.h" #include "dst_parse.h" -#include <gssapi/gssapi.h> +#include <dst/gssapi.h> #define INITIAL_BUFFER_SIZE 1024 #define BUFFER_EXTRA 1024 #define REGION_TO_GBUFFER(r, gb) \ do { \ - (gb).length = (r).length; \ - (gb).value = (r).base; \ + (gb).length = (r).length; \ + (gb).value = (r).base; \ } while (0) -typedef struct gssapi_ctx { - isc_buffer_t *buffer; - gss_ctx_id_t *context_id; -} gssapi_ctx_t; +struct dst_gssapi_signverifyctx { + isc_buffer_t *buffer; +}; +/*% + * Allocate a temporary "context" for use in gathering data for signing + * or verifying. + */ static isc_result_t -gssapi_createctx(dst_key_t *key, dst_context_t *dctx) { - gssapi_ctx_t *ctx; +gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) { + dst_gssapi_signverifyctx_t *ctx; isc_result_t result; UNUSED(key); - ctx = isc_mem_get(dctx->mctx, sizeof(gssapi_ctx_t)); + ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t)); if (ctx == NULL) return (ISC_R_NOMEMORY); ctx->buffer = NULL; result = isc_buffer_allocate(dctx->mctx, &ctx->buffer, INITIAL_BUFFER_SIZE); if (result != ISC_R_SUCCESS) { - isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t)); + isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t)); return (result); } - ctx->context_id = key->opaque; - dctx->opaque = ctx; + + dctx->ctxdata.gssctx = ctx; + return (ISC_R_SUCCESS); } +/*% + * Destroy the temporary sign/verify context. + */ static void -gssapi_destroyctx(dst_context_t *dctx) { - gssapi_ctx_t *ctx = dctx->opaque; +gssapi_destroy_signverify_ctx(dst_context_t *dctx) { + dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx; if (ctx != NULL) { if (ctx->buffer != NULL) isc_buffer_free(&ctx->buffer); - isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t)); - dctx->opaque = NULL; + isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t)); + dctx->ctxdata.gssctx = NULL; } } +/*% + * Add data to our running buffer of data we will be signing or verifying. + * This code will see if the new data will fit in our existing buffer, and + * copy it in if it will. If not, it will attempt to allocate a larger + * buffer and copy old+new into it, and free the old buffer. + */ static isc_result_t gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) { - gssapi_ctx_t *ctx = dctx->opaque; + dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx; isc_buffer_t *newbuffer = NULL; isc_region_t r; unsigned int length; @@ -103,8 +116,8 @@ gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) { return (result); isc_buffer_usedregion(ctx->buffer, &r); - (void) isc_buffer_copyregion(newbuffer, &r); - (void) isc_buffer_copyregion(newbuffer, data); + (void)isc_buffer_copyregion(newbuffer, &r); + (void)isc_buffer_copyregion(newbuffer, data); isc_buffer_free(&ctx->buffer); ctx->buffer = newbuffer; @@ -112,56 +125,129 @@ gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) { return (ISC_R_SUCCESS); } +/*% + * Sign. + */ static isc_result_t gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) { - gssapi_ctx_t *ctx = dctx->opaque; + dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx; isc_region_t message; gss_buffer_desc gmessage, gsig; OM_uint32 minor, gret; + gss_ctx_id_t gssctx = dctx->key->keydata.gssctx; + char buf[1024]; + /* + * Convert the data we wish to sign into a structure gssapi can + * understand. + */ isc_buffer_usedregion(ctx->buffer, &message); REGION_TO_GBUFFER(message, gmessage); - gret = gss_get_mic(&minor, ctx->context_id, - GSS_C_QOP_DEFAULT, &gmessage, &gsig); - if (gret != 0) + /* + * Generate the signature. + */ + gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage, + &gsig); + + /* + * If it did not complete, we log the result and return a generic + * failure code. + */ + if (gret != GSS_S_COMPLETE) { + gss_log(3, "GSS sign error: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); return (ISC_R_FAILURE); + } + /* + * If it will not fit in our allocated buffer, return that we need + * more space. + */ if (gsig.length > isc_buffer_availablelength(sig)) { gss_release_buffer(&minor, &gsig); return (ISC_R_NOSPACE); } + /* + * Copy the output into our buffer space, and release the gssapi + * allocated space. + */ isc_buffer_putmem(sig, gsig.value, gsig.length); - - gss_release_buffer(&minor, &gsig); + if (gsig.length != 0) + gss_release_buffer(&minor, &gsig); return (ISC_R_SUCCESS); } +/*% + * Verify. + */ static isc_result_t gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) { - gssapi_ctx_t *ctx = dctx->opaque; - isc_region_t message; + dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx; + isc_region_t message, r; gss_buffer_desc gmessage, gsig; OM_uint32 minor, gret; - + gss_ctx_id_t gssctx = dctx->key->keydata.gssctx; + unsigned char *buf; + char err[1024]; + + /* + * Convert the data we wish to sign into a structure gssapi can + * understand. + */ isc_buffer_usedregion(ctx->buffer, &message); REGION_TO_GBUFFER(message, gmessage); - REGION_TO_GBUFFER(*sig, gsig); - - gret = gss_verify_mic(&minor, ctx->context_id, &gmessage, &gsig, NULL); - if (gret != 0) + /* + * XXXMLG + * It seem that gss_verify_mic() modifies the signature buffer, + * at least on Heimdal's implementation. Copy it here to an allocated + * buffer. + */ + buf = isc_mem_allocate(dst__memory_pool, sig->length); + if (buf == NULL) return (ISC_R_FAILURE); + memcpy(buf, sig->base, sig->length); + r.base = buf; + r.length = sig->length; + REGION_TO_GBUFFER(r, gsig); + + /* + * Verify the data. + */ + gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL); + + isc_mem_free(dst__memory_pool, buf); + + /* + * Convert return codes into something useful to us. + */ + if (gret != GSS_S_COMPLETE) { + gss_log(3, "GSS verify error: %s", + gss_error_tostring(gret, minor, err, sizeof(err))); + if (gret == GSS_S_DEFECTIVE_TOKEN || + gret == GSS_S_BAD_SIG || + gret == GSS_S_DUPLICATE_TOKEN || + gret == GSS_S_OLD_TOKEN || + gret == GSS_S_UNSEQ_TOKEN || + gret == GSS_S_GAP_TOKEN || + gret == GSS_S_CONTEXT_EXPIRED || + gret == GSS_S_NO_CONTEXT || + gret == GSS_S_FAILURE) + return(DST_R_VERIFYFAILURE); + else + return (ISC_R_FAILURE); + } return (ISC_R_SUCCESS); } static isc_boolean_t gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) { - gss_ctx_id_t gsskey1 = key1->opaque; - gss_ctx_id_t gsskey2 = key2->opaque; + gss_ctx_id_t gsskey1 = key1->keydata.gssctx; + gss_ctx_id_t gsskey2 = key2->keydata.gssctx; /* No idea */ return (ISC_TF(gsskey1 == gsskey2)); @@ -179,18 +265,19 @@ gssapi_generate(dst_key_t *key, int unused) { static isc_boolean_t gssapi_isprivate(const dst_key_t *key) { UNUSED(key); - return (ISC_TRUE); + return (ISC_TRUE); } static void gssapi_destroy(dst_key_t *key) { - UNUSED(key); - /* No idea */ + REQUIRE(key != NULL); + dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx); + key->keydata.gssctx = NULL; } static dst_func_t gssapi_functions = { - gssapi_createctx, - gssapi_destroyctx, + gssapi_create_signverify_ctx, + gssapi_destroy_signverify_ctx, gssapi_adddata, gssapi_sign, gssapi_verify, @@ -205,6 +292,7 @@ static dst_func_t gssapi_functions = { NULL, /*%< tofile */ NULL, /*%< parse */ NULL, /*%< cleanup */ + NULL /*%< fromlabel */ }; isc_result_t diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c index ce5d6fa..11eadb9 100644 --- a/lib/dns/gssapictx.c +++ b/lib/dns/gssapictx.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,11 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gssapictx.c,v 1.1.6.3 2005/04/29 00:15:54 marka Exp $ */ +/* $Id: gssapictx.c,v 1.12 2008/04/03 06:09:04 tbox Exp $ */ #include <config.h> #include <stdlib.h> +#include <string.h> #include <isc/buffer.h> #include <isc/dir.h> @@ -27,6 +28,7 @@ #include <isc/lex.h> #include <isc/mem.h> #include <isc/once.h> +#include <isc/print.h> #include <isc/random.h> #include <isc/string.h> #include <isc/time.h> @@ -39,34 +41,76 @@ #include <dns/result.h> #include <dns/types.h> #include <dns/keyvalues.h> +#include <dns/log.h> #include <dst/gssapi.h> #include <dst/result.h> #include "dst_internal.h" -#ifdef GSSAPI +/* + * If we're using our own SPNEGO implementation (see configure.in), + * pull it in now. Otherwise, we just use whatever GSSAPI supplies. + */ +#if defined(GSSAPI) && defined(USE_ISC_SPNEGO) +#include "spnego.h" +#define gss_accept_sec_context gss_accept_sec_context_spnego +#define gss_init_sec_context gss_init_sec_context_spnego +#endif -#include <gssapi/gssapi.h> +/* + * Solaris8 apparently needs an explicit OID set, and Solaris10 needs + * one for anything but Kerberos. Supplying an explicit OID set + * doesn't appear to hurt anything in other implementations, so we + * always use one. If we're not using our own SPNEGO implementation, + * we include SPNEGO's OID. + */ +#if defined(GSSAPI) -#define RETERR(x) do { \ - result = (x); \ - if (result != ISC_R_SUCCESS) \ - goto out; \ +static unsigned char krb5_mech_oid_bytes[] = { + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 +}; + +#ifndef USE_ISC_SPNEGO +static unsigned char spnego_mech_oid_bytes[] = { + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 +}; +#endif + +static gss_OID_desc mech_oid_set_array[] = { + { sizeof(krb5_mech_oid_bytes), krb5_mech_oid_bytes }, +#ifndef USE_ISC_SPNEGO + { sizeof(spnego_mech_oid_bytes), spnego_mech_oid_bytes }, +#endif +}; + +static gss_OID_set_desc mech_oid_set = { + sizeof(mech_oid_set_array) / sizeof(*mech_oid_set_array), + mech_oid_set_array +}; + +#endif + +#define REGION_TO_GBUFFER(r, gb) \ + do { \ + (gb).length = (r).length; \ + (gb).value = (r).base; \ } while (0) -#define REGION_TO_GBUFFER(r, gb) \ - do { \ - (gb).length = (r).length; \ - (gb).value = (r).base; \ +#define GBUFFER_TO_REGION(gb, r) \ + do { \ + (r).length = (gb).length; \ + (r).base = (gb).value; \ } while (0) -#define GBUFFER_TO_REGION(gb, r) \ - do { \ - (r).length = (gb).length; \ - (r).base = (gb).value; \ + +#define RETERR(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto out; \ } while (0) +#ifdef GSSAPI static inline void name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer, gss_buffer_desc *gbuffer) @@ -77,22 +121,81 @@ name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer, if (!dns_name_isabsolute(name)) namep = name; - else { + else + { unsigned int labels; dns_name_init(&tname, NULL); labels = dns_name_countlabels(name); dns_name_getlabelsequence(name, 0, labels - 1, &tname); namep = &tname; } - + result = dns_name_totext(namep, ISC_FALSE, buffer); isc_buffer_putuint8(buffer, 0); isc_buffer_usedregion(buffer, &r); REGION_TO_GBUFFER(r, *gbuffer); } +static void +log_cred(const gss_cred_id_t cred) { + OM_uint32 gret, minor, lifetime; + gss_name_t gname; + gss_buffer_desc gbuffer; + gss_cred_usage_t usage; + const char *usage_text; + char buf[1024]; + + gret = gss_inquire_cred(&minor, cred, &gname, &lifetime, &usage, NULL); + if (gret != GSS_S_COMPLETE) { + gss_log(3, "failed gss_inquire_cred: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); + return; + } + + gret = gss_display_name(&minor, gname, &gbuffer, NULL); + if (gret != GSS_S_COMPLETE) + gss_log(3, "failed gss_display_name: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); + else { + switch (usage) { + case GSS_C_BOTH: + usage_text = "GSS_C_BOTH"; + break; + case GSS_C_INITIATE: + usage_text = "GSS_C_INITIATE"; + break; + case GSS_C_ACCEPT: + usage_text = "GSS_C_ACCEPT"; + break; + default: + usage_text = "???"; + } + gss_log(3, "gss cred: \"%s\", %s, %lu", (char *)gbuffer.value, + usage_text, (unsigned long)lifetime); + } + + if (gret == GSS_S_COMPLETE) { + if (gbuffer.length != 0) { + gret = gss_release_buffer(&minor, &gbuffer); + if (gret != GSS_S_COMPLETE) + gss_log(3, "failed gss_release_buffer: %s", + gss_error_tostring(gret, minor, buf, + sizeof(buf))); + } + } + + gret = gss_release_name(&minor, &gname); + if (gret != GSS_S_COMPLETE) + gss_log(3, "failed gss_release_name: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); +} +#endif + isc_result_t -dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) { +dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, + gss_cred_id_t *cred) +{ +#ifdef GSSAPI isc_buffer_t namebuf; gss_name_t gname; gss_buffer_desc gnamebuf; @@ -101,164 +204,535 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) { gss_OID_set mechs; OM_uint32 lifetime; gss_cred_usage_t usage; + char buf[1024]; REQUIRE(cred != NULL && *cred == NULL); + /* + * XXXSRA In theory we could use GSS_C_NT_HOSTBASED_SERVICE + * here when we're in the acceptor role, which would let us + * default the hostname and use a compiled in default service + * name of "DNS", giving one less thing to configure in + * named.conf. Unfortunately, this creates a circular + * dependency due to DNS-based realm lookup in at least one + * GSSAPI implementation (Heimdal). Oh well. + */ if (name != NULL) { isc_buffer_init(&namebuf, array, sizeof(array)); name_to_gbuffer(name, &namebuf, &gnamebuf); - gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, - &gname); - if (gret != GSS_S_COMPLETE) + gret = gss_import_name(&minor, &gnamebuf, + GSS_C_NO_OID, &gname); + if (gret != GSS_S_COMPLETE) { + gss_log(3, "failed gss_import_name: %s", + gss_error_tostring(gret, minor, buf, + sizeof(buf))); return (ISC_R_FAILURE); + } } else gname = NULL; + /* Get the credentials. */ + if (gname != NULL) + gss_log(3, "acquiring credentials for %s", + (char *)gnamebuf.value); + else { + /* XXXDCL does this even make any sense? */ + gss_log(3, "acquiring credentials for ?"); + } + if (initiate) usage = GSS_C_INITIATE; else usage = GSS_C_ACCEPT; gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE, - GSS_C_NO_OID_SET, usage, - cred, &mechs, &lifetime); - if (gret != GSS_S_COMPLETE) + &mech_oid_set, + usage, cred, &mechs, &lifetime); + + if (gret != GSS_S_COMPLETE) { + gss_log(3, "failed to acquire %s credentials for %s: %s", + initiate ? "initiate" : "accept", + (char *)gnamebuf.value, + gss_error_tostring(gret, minor, buf, sizeof(buf))); return (ISC_R_FAILURE); + } + + gss_log(4, "acquired %s credentials for %s", + initiate ? "initiate" : "accept", + (char *)gnamebuf.value); + + log_cred(*cred); + return (ISC_R_SUCCESS); +#else + UNUSED(name); + UNUSED(initiate); + UNUSED(cred); + + return (ISC_R_NOTIMPLEMENTED); +#endif +} + +isc_boolean_t +dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name, + dns_name_t *realm) +{ +#ifdef GSSAPI + char sbuf[DNS_NAME_FORMATSIZE]; + char nbuf[DNS_NAME_FORMATSIZE]; + char rbuf[DNS_NAME_FORMATSIZE]; + char *sname; + char *rname; + + /* + * It is far, far easier to write the names we are looking at into + * a string, and do string operations on them. + */ + dns_name_format(signer, sbuf, sizeof(sbuf)); + if (name != NULL) + dns_name_format(name, nbuf, sizeof(nbuf)); + dns_name_format(realm, rbuf, sizeof(rbuf)); + + /* + * Find the realm portion. This is the part after the @. If it + * does not exist, we don't have something we like, so we fail our + * compare. + */ + rname = strstr(sbuf, "\\@"); + if (rname == NULL) + return (isc_boolean_false); + *rname = '\0'; + rname += 2; + + /* + * Find the host portion of the signer's name. We do this by + * searching for the first / character. We then check to make + * certain the instance name is "host" + * + * This will work for + * host/example.com@EXAMPLE.COM + */ + sname = strchr(sbuf, '/'); + if (sname == NULL) + return (isc_boolean_false); + *sname = '\0'; + sname++; + if (strcmp(sbuf, "host") != 0) + return (isc_boolean_false); + + /* + * Now, we do a simple comparison between the name and the realm. + */ + if (name != NULL) { + if ((strcasecmp(sname, nbuf) == 0) + && (strcmp(rname, rbuf) == 0)) + return (isc_boolean_true); + } else { + if (strcmp(rname, rbuf) == 0) + return (isc_boolean_true); + } + + return (isc_boolean_false); +#else + UNUSED(signer); + UNUSED(name); + UNUSED(realm); + return (isc_boolean_false); +#endif +} + +isc_boolean_t +dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, + dns_name_t *realm) +{ +#ifdef GSSAPI + char sbuf[DNS_NAME_FORMATSIZE]; + char nbuf[DNS_NAME_FORMATSIZE]; + char rbuf[DNS_NAME_FORMATSIZE]; + char *sname; + char *nname; + char *rname; + + /* + * It is far, far easier to write the names we are looking at into + * a string, and do string operations on them. + */ + dns_name_format(signer, sbuf, sizeof(sbuf)); + if (name != NULL) + dns_name_format(name, nbuf, sizeof(nbuf)); + dns_name_format(realm, rbuf, sizeof(rbuf)); + + /* + * Find the realm portion. This is the part after the @. If it + * does not exist, we don't have something we like, so we fail our + * compare. + */ + rname = strstr(sbuf, "\\@"); + if (rname == NULL) + return (isc_boolean_false); + sname = strstr(sbuf, "\\$"); + if (sname == NULL) + return (isc_boolean_false); + + /* + * Verify that the $ and @ follow one another. + */ + if (rname - sname != 2) + return (isc_boolean_false); + + /* + * Find the host portion of the signer's name. Zero out the $ so + * it terminates the signer's name, and skip past the @ for + * the realm. + * + * All service principals in Microsoft format seem to be in + * machinename$@EXAMPLE.COM + * format. + */ + *rname = '\0'; + rname += 2; + *sname = '\0'; + sname = sbuf; + + /* + * Find the first . in the target name, and make it the end of + * the string. The rest of the name has to match the realm. + */ + if (name != NULL) { + nname = strchr(nbuf, '.'); + if (nname == NULL) + return (isc_boolean_false); + *nname++ = '\0'; + } + + /* + * Now, we do a simple comparison between the name and the realm. + */ + if (name != NULL) { + if ((strcasecmp(sname, nbuf) == 0) + && (strcmp(rname, rbuf) == 0) + && (strcasecmp(nname, rbuf) == 0)) + return (isc_boolean_true); + } else { + if (strcmp(rname, rbuf) == 0) + return (isc_boolean_true); + } + + + return (isc_boolean_false); +#else + UNUSED(signer); + UNUSED(name); + UNUSED(realm); + return (isc_boolean_false); +#endif } isc_result_t -dst_gssapi_initctx(dns_name_t *name, void *cred, - isc_region_t *intoken, isc_buffer_t *outtoken, - void **context) +dst_gssapi_releasecred(gss_cred_id_t *cred) { +#ifdef GSSAPI + OM_uint32 gret, minor; + char buf[1024]; + + REQUIRE(cred != NULL && *cred != NULL); + + gret = gss_release_cred(&minor, cred); + if (gret != GSS_S_COMPLETE) { + /* Log the error, but still free the credential's memory */ + gss_log(3, "failed releasing credential: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); + } + *cred = NULL; + + return(ISC_R_SUCCESS); +#else + UNUSED(cred); + + return (ISC_R_NOTIMPLEMENTED); +#endif +} + +isc_result_t +dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, + isc_buffer_t *outtoken, gss_ctx_id_t *gssctx) { +#ifdef GSSAPI isc_region_t r; isc_buffer_t namebuf; - gss_buffer_desc gnamebuf, gintoken, *gintokenp, gouttoken; - OM_uint32 gret, minor, flags, ret_flags; - gss_OID mech_type, ret_mech_type; - OM_uint32 lifetime; gss_name_t gname; + OM_uint32 gret, minor, ret_flags, flags; + gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER; isc_result_t result; + gss_buffer_desc gnamebuf; unsigned char array[DNS_NAME_MAXTEXT + 1]; + char buf[1024]; + + /* Client must pass us a valid gss_ctx_id_t here */ + REQUIRE(gssctx != NULL); isc_buffer_init(&namebuf, array, sizeof(array)); name_to_gbuffer(name, &namebuf, &gnamebuf); + + /* Get the name as a GSS name */ gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); - if (gret != GSS_S_COMPLETE) - return (ISC_R_FAILURE); + if (gret != GSS_S_COMPLETE) { + result = ISC_R_FAILURE; + goto out; + } if (intoken != NULL) { + /* Don't call gss_release_buffer for gintoken! */ REGION_TO_GBUFFER(*intoken, gintoken); gintokenp = &gintoken; - } else + } else { gintokenp = NULL; + } - if (*context == NULL) - *context = GSS_C_NO_CONTEXT; flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | - GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG; - mech_type = GSS_C_NO_OID; - - gret = gss_init_sec_context(&minor, cred, context, gname, - mech_type, flags, 0, - GSS_C_NO_CHANNEL_BINDINGS, gintokenp, - &ret_mech_type, &gouttoken, &ret_flags, - &lifetime); - if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) - return (ISC_R_FAILURE); + GSS_C_SEQUENCE_FLAG | GSS_C_INTEG_FLAG; + + gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx, + gname, GSS_SPNEGO_MECHANISM, flags, + 0, NULL, gintokenp, + NULL, &gouttoken, &ret_flags, NULL); + + if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) { + gss_log(3, "Failure initiating security context"); + gss_log(3, "%s", gss_error_tostring(gret, minor, + buf, sizeof(buf))); + result = ISC_R_FAILURE; + goto out; + } - GBUFFER_TO_REGION(gouttoken, r); - RETERR(isc_buffer_copyregion(outtoken, &r)); + /* + * XXXSRA Not handled yet: RFC 3645 3.1.1: check ret_flags + * MUTUAL and INTEG flags, fail if either not set. + */ + + /* + * RFC 2744 states the a valid output token has a non-zero length. + */ + if (gouttoken.length != 0) { + GBUFFER_TO_REGION(gouttoken, r); + RETERR(isc_buffer_copyregion(outtoken, &r)); + (void)gss_release_buffer(&minor, &gouttoken); + } + (void)gss_release_name(&minor, &gname); if (gret == GSS_S_COMPLETE) - return (ISC_R_SUCCESS); + result = ISC_R_SUCCESS; else - return (DNS_R_CONTINUE); + result = DNS_R_CONTINUE; out: - return (result); + return (result); +#else + UNUSED(name); + UNUSED(intoken); + UNUSED(outtoken); + UNUSED(gssctx); + + return (ISC_R_NOTIMPLEMENTED); +#endif } isc_result_t -dst_gssapi_acceptctx(dns_name_t *name, void *cred, - isc_region_t *intoken, isc_buffer_t *outtoken, - void **context) +dst_gssapi_acceptctx(gss_cred_id_t cred, + isc_region_t *intoken, isc_buffer_t **outtoken, + gss_ctx_id_t *ctxout, dns_name_t *principal, + isc_mem_t *mctx) { +#ifdef GSSAPI isc_region_t r; isc_buffer_t namebuf; - gss_buffer_desc gnamebuf, gintoken, gouttoken; - OM_uint32 gret, minor, flags; - gss_OID mech_type; - OM_uint32 lifetime; - gss_cred_id_t delegated_cred; - gss_name_t gname; + gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken, + gouttoken = GSS_C_EMPTY_BUFFER; + OM_uint32 gret, minor; + gss_ctx_id_t context = GSS_C_NO_CONTEXT; + gss_name_t gname = NULL; isc_result_t result; - unsigned char array[DNS_NAME_MAXTEXT + 1]; + char buf[1024]; - isc_buffer_init(&namebuf, array, sizeof(array)); - name_to_gbuffer(name, &namebuf, &gnamebuf); - gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); - if (gret != GSS_S_COMPLETE) - return (ISC_R_FAILURE); + REQUIRE(outtoken != NULL && *outtoken == NULL); + + log_cred(cred); REGION_TO_GBUFFER(*intoken, gintoken); - if (*context == NULL) - *context = GSS_C_NO_CONTEXT; + if (*ctxout == NULL) + context = GSS_C_NO_CONTEXT; + else + context = *ctxout; + + gret = gss_accept_sec_context(&minor, &context, cred, &gintoken, + GSS_C_NO_CHANNEL_BINDINGS, &gname, + NULL, &gouttoken, NULL, NULL, NULL); + + result = ISC_R_FAILURE; + + switch (gret) { + case GSS_S_COMPLETE: + result = ISC_R_SUCCESS; + break; + case GSS_S_CONTINUE_NEEDED: + result = DNS_R_CONTINUE; + break; + case GSS_S_DEFECTIVE_TOKEN: + case GSS_S_DEFECTIVE_CREDENTIAL: + case GSS_S_BAD_SIG: + case GSS_S_DUPLICATE_TOKEN: + case GSS_S_OLD_TOKEN: + case GSS_S_NO_CRED: + case GSS_S_CREDENTIALS_EXPIRED: + case GSS_S_BAD_BINDINGS: + case GSS_S_NO_CONTEXT: + case GSS_S_BAD_MECH: + case GSS_S_FAILURE: + result = DNS_R_INVALIDTKEY; + /* fall through */ + default: + gss_log(3, "failed gss_accept_sec_context: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); + return (result); + } - gret = gss_accept_sec_context(&minor, context, cred, &gintoken, - GSS_C_NO_CHANNEL_BINDINGS, gname, - &mech_type, &gouttoken, &flags, - &lifetime, &delegated_cred); - if (gret != GSS_S_COMPLETE) - return (ISC_R_FAILURE); + if (gouttoken.length > 0) { + RETERR(isc_buffer_allocate(mctx, outtoken, gouttoken.length)); + GBUFFER_TO_REGION(gouttoken, r); + RETERR(isc_buffer_copyregion(*outtoken, &r)); + (void)gss_release_buffer(&minor, &gouttoken); + } - GBUFFER_TO_REGION(gouttoken, r); - RETERR(isc_buffer_copyregion(outtoken, &r)); + if (gret == GSS_S_COMPLETE) { + gret = gss_display_name(&minor, gname, &gnamebuf, NULL); + if (gret != GSS_S_COMPLETE) { + gss_log(3, "failed gss_display_name: %s", + gss_error_tostring(gret, minor, + buf, sizeof(buf))); + RETERR(ISC_R_FAILURE); + } + + /* + * Compensate for a bug in Solaris8's implementation + * of gss_display_name(). Should be harmless in any + * case, since principal names really should not + * contain null characters. + */ + if (gnamebuf.length > 0 && + ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0') + gnamebuf.length--; + + gss_log(3, "gss-api source name (accept) is %.*s", + (int)gnamebuf.length, (char *)gnamebuf.value); + + GBUFFER_TO_REGION(gnamebuf, r); + isc_buffer_init(&namebuf, r.base, r.length); + isc_buffer_add(&namebuf, r.length); + + RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname, + ISC_FALSE, NULL)); + + if (gnamebuf.length != 0) { + gret = gss_release_buffer(&minor, &gnamebuf); + if (gret != GSS_S_COMPLETE) + gss_log(3, "failed gss_release_buffer: %s", + gss_error_tostring(gret, minor, buf, + sizeof(buf))); + } + } - return (ISC_R_SUCCESS); + *ctxout = context; out: - return (result); -} + if (gname != NULL) { + gret = gss_release_name(&minor, &gname); + if (gret != GSS_S_COMPLETE) + gss_log(3, "failed gss_release_name: %s", + gss_error_tostring(gret, minor, buf, + sizeof(buf))); + } + return (result); #else - -isc_result_t -dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) { - UNUSED(name); - UNUSED(initiate); - UNUSED(cred); - return (ISC_R_NOTIMPLEMENTED); -} - -isc_result_t -dst_gssapi_initctx(dns_name_t *name, void *cred, - isc_region_t *intoken, isc_buffer_t *outtoken, - void **context) -{ - UNUSED(name); UNUSED(cred); UNUSED(intoken); UNUSED(outtoken); - UNUSED(context); + UNUSED(ctxout); + UNUSED(principal); + UNUSED(mctx); + return (ISC_R_NOTIMPLEMENTED); +#endif } isc_result_t -dst_gssapi_acceptctx(dns_name_t *name, void *cred, - isc_region_t *intoken, isc_buffer_t *outtoken, - void **context) +dst_gssapi_deletectx(isc_mem_t *mctx, gss_ctx_id_t *gssctx) { - UNUSED(name); - UNUSED(cred); - UNUSED(intoken); - UNUSED(outtoken); - UNUSED(context); +#ifdef GSSAPI + OM_uint32 gret, minor; + char buf[1024]; + + UNUSED(mctx); + + REQUIRE(gssctx != NULL && *gssctx != NULL); + + /* Delete the context from the GSS provider */ + gret = gss_delete_sec_context(&minor, gssctx, GSS_C_NO_BUFFER); + if (gret != GSS_S_COMPLETE) { + /* Log the error, but still free the context's memory */ + gss_log(3, "Failure deleting security context %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); + } + return(ISC_R_SUCCESS); +#else + UNUSED(mctx); + UNUSED(gssctx); return (ISC_R_NOTIMPLEMENTED); +#endif } +char * +gss_error_tostring(isc_uint32_t major, isc_uint32_t minor, + char *buf, size_t buflen) { +#ifdef GSSAPI + gss_buffer_desc msg_minor = GSS_C_EMPTY_BUFFER, + msg_major = GSS_C_EMPTY_BUFFER; + OM_uint32 msg_ctx, minor_stat; + + /* Handle major status */ + msg_ctx = 0; + (void)gss_display_status(&minor_stat, major, GSS_C_GSS_CODE, + GSS_C_NULL_OID, &msg_ctx, &msg_major); + + /* Handle minor status */ + msg_ctx = 0; + (void)gss_display_status(&minor_stat, minor, GSS_C_MECH_CODE, + GSS_C_NULL_OID, &msg_ctx, &msg_minor); + + snprintf(buf, buflen, "GSSAPI error: Major = %s, Minor = %s.", + (char *)msg_major.value, (char *)msg_minor.value); + + if (msg_major.length != 0) + (void)gss_release_buffer(&minor_stat, &msg_major); + if (msg_minor.length != 0) + (void)gss_release_buffer(&minor_stat, &msg_minor); + return(buf); +#else + snprintf(buf, buflen, "GSSAPI error: Major = %u, Minor = %u.", + major, minor); + + return (buf); #endif +} + +void +gss_log(int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_TKEY, ISC_LOG_DEBUG(level), fmt, ap); + va_end(ap); +} /*! \file */ diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 9655c89..fce98d7 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -1,9 +1,22 @@ /* - * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: hmac_link.c,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ + * $Id: hmac_link.c,v 1.11 2008/04/01 23:47:10 tbox Exp $ */ #include <config.h> @@ -43,9 +56,9 @@ static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data); -typedef struct hmackey { +struct dst_hmacmd5_key { unsigned char key[HMAC_LEN]; -} HMAC_Key; +}; static isc_result_t getkeybits(dst_key_t *key, struct dst_private_element *element) { @@ -61,30 +74,30 @@ getkeybits(dst_key_t *key, struct dst_private_element *element) { static isc_result_t hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacmd5_t *hmacmd5ctx; - HMAC_Key *hkey = key->opaque; + dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5; hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t)); if (hmacmd5ctx == NULL) return (ISC_R_NOMEMORY); isc_hmacmd5_init(hmacmd5ctx, hkey->key, HMAC_LEN); - dctx->opaque = hmacmd5ctx; + dctx->ctxdata.hmacmd5ctx = hmacmd5ctx; return (ISC_R_SUCCESS); } static void hmacmd5_destroyctx(dst_context_t *dctx) { - isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx; if (hmacmd5ctx != NULL) { isc_hmacmd5_invalidate(hmacmd5ctx); isc_mem_put(dctx->mctx, hmacmd5ctx, sizeof(isc_hmacmd5_t)); - dctx->opaque = NULL; + dctx->ctxdata.hmacmd5ctx = NULL; } } static isc_result_t hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx; isc_hmacmd5_update(hmacmd5ctx, data->base, data->length); return (ISC_R_SUCCESS); @@ -92,7 +105,7 @@ hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx; unsigned char *digest; if (isc_buffer_availablelength(sig) < ISC_MD5_DIGESTLENGTH) @@ -106,7 +119,7 @@ hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_hmacmd5_t *hmacmd5ctx = dctx->opaque; + isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx; if (sig->length > ISC_MD5_DIGESTLENGTH) return (DST_R_VERIFYFAILURE); @@ -119,10 +132,10 @@ hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) { - HMAC_Key *hkey1, *hkey2; + dst_hmacmd5_key_t *hkey1, *hkey2; - hkey1 = (HMAC_Key *)key1->opaque; - hkey2 = (HMAC_Key *)key2->opaque; + hkey1 = key1->keydata.hmacmd5; + hkey2 = key2->keydata.hmacmd5; if (hkey1 == NULL && hkey2 == NULL) return (ISC_TRUE); @@ -170,20 +183,20 @@ hmacmd5_isprivate(const dst_key_t *key) { static void hmacmd5_destroy(dst_key_t *key) { - HMAC_Key *hkey = key->opaque; - memset(hkey, 0, sizeof(HMAC_Key)); - isc_mem_put(key->mctx, hkey, sizeof(HMAC_Key)); - key->opaque = NULL; + dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5; + memset(hkey, 0, sizeof(dst_hmacmd5_key_t)); + isc_mem_put(key->mctx, hkey, sizeof(dst_hmacmd5_key_t)); + key->keydata.hmacmd5 = NULL; } static isc_result_t hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) { - HMAC_Key *hkey; + dst_hmacmd5_key_t *hkey; unsigned int bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.hmacmd5 != NULL); - hkey = (HMAC_Key *) key->opaque; + hkey = key->keydata.hmacmd5; bytes = (key->key_size + 7) / 8; if (isc_buffer_availablelength(data) < bytes) @@ -195,7 +208,7 @@ hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { - HMAC_Key *hkey; + dst_hmacmd5_key_t *hkey; int keylen; isc_region_t r; isc_md5_t md5ctx; @@ -204,7 +217,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length == 0) return (ISC_R_SUCCESS); - hkey = (HMAC_Key *) isc_mem_get(key->mctx, sizeof(HMAC_Key)); + hkey = isc_mem_get(key->mctx, sizeof(dst_hmacmd5_key_t)); if (hkey == NULL) return (ISC_R_NOMEMORY); @@ -222,7 +235,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { } key->key_size = keylen * 8; - key->opaque = hkey; + key->keydata.hmacmd5 = hkey; return (ISC_R_SUCCESS); } @@ -230,15 +243,15 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacmd5_tofile(const dst_key_t *key, const char *directory) { int cnt = 0; - HMAC_Key *hkey; + dst_hmacmd5_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; unsigned char buf[2]; - if (key->opaque == NULL) + if (key->keydata.hmacmd5 == NULL) return (DST_R_NULLKEY); - hkey = (HMAC_Key *) key->opaque; + hkey = key->keydata.hmacmd5; priv.elements[cnt].tag = TAG_HMACMD5_KEY; priv.elements[cnt].length = bytes; @@ -272,7 +285,7 @@ hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer) { switch (priv.elements[i].tag) { case TAG_HMACMD5_KEY: isc_buffer_init(&b, priv.elements[i].data, - priv.elements[i].length); + priv.elements[i].length); isc_buffer_add(&b, priv.elements[i].length); tresult = hmacmd5_fromdns(key, &b); if (tresult != ISC_R_SUCCESS) @@ -310,6 +323,7 @@ static dst_func_t hmacmd5_functions = { hmacmd5_tofile, hmacmd5_parse, NULL, /*%< cleanup */ + NULL, /*%< fromlabel */ }; isc_result_t @@ -322,37 +336,37 @@ dst__hmacmd5_init(dst_func_t **funcp) { static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data); -typedef struct { +struct dst_hmacsha1_key { unsigned char key[ISC_SHA1_DIGESTLENGTH]; -} HMACSHA1_Key; +}; static isc_result_t hmacsha1_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacsha1_t *hmacsha1ctx; - HMACSHA1_Key *hkey = key->opaque; + dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1; hmacsha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha1_t)); if (hmacsha1ctx == NULL) return (ISC_R_NOMEMORY); isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_DIGESTLENGTH); - dctx->opaque = hmacsha1ctx; + dctx->ctxdata.hmacsha1ctx = hmacsha1ctx; return (ISC_R_SUCCESS); } static void hmacsha1_destroyctx(dst_context_t *dctx) { - isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx; if (hmacsha1ctx != NULL) { isc_hmacsha1_invalidate(hmacsha1ctx); isc_mem_put(dctx->mctx, hmacsha1ctx, sizeof(isc_hmacsha1_t)); - dctx->opaque = NULL; + dctx->ctxdata.hmacsha1ctx = NULL; } } static isc_result_t hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx; isc_hmacsha1_update(hmacsha1ctx, data->base, data->length); return (ISC_R_SUCCESS); @@ -360,7 +374,7 @@ hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx; unsigned char *digest; if (isc_buffer_availablelength(sig) < ISC_SHA1_DIGESTLENGTH) @@ -374,7 +388,7 @@ hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_hmacsha1_t *hmacsha1ctx = dctx->opaque; + isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx; if (sig->length > ISC_SHA1_DIGESTLENGTH || sig->length == 0) return (DST_R_VERIFYFAILURE); @@ -387,10 +401,10 @@ hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) { - HMACSHA1_Key *hkey1, *hkey2; + dst_hmacsha1_key_t *hkey1, *hkey2; - hkey1 = (HMACSHA1_Key *)key1->opaque; - hkey2 = (HMACSHA1_Key *)key2->opaque; + hkey1 = key1->keydata.hmacsha1; + hkey2 = key2->keydata.hmacsha1; if (hkey1 == NULL && hkey2 == NULL) return (ISC_TRUE); @@ -438,20 +452,20 @@ hmacsha1_isprivate(const dst_key_t *key) { static void hmacsha1_destroy(dst_key_t *key) { - HMACSHA1_Key *hkey = key->opaque; - memset(hkey, 0, sizeof(HMACSHA1_Key)); - isc_mem_put(key->mctx, hkey, sizeof(HMACSHA1_Key)); - key->opaque = NULL; + dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1; + memset(hkey, 0, sizeof(dst_hmacsha1_key_t)); + isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha1_key_t)); + key->keydata.hmacsha1 = NULL; } static isc_result_t hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) { - HMACSHA1_Key *hkey; + dst_hmacsha1_key_t *hkey; unsigned int bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.hmacsha1 != NULL); - hkey = (HMACSHA1_Key *) key->opaque; + hkey = key->keydata.hmacsha1; bytes = (key->key_size + 7) / 8; if (isc_buffer_availablelength(data) < bytes) @@ -463,7 +477,7 @@ hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { - HMACSHA1_Key *hkey; + dst_hmacsha1_key_t *hkey; int keylen; isc_region_t r; isc_sha1_t sha1ctx; @@ -472,7 +486,7 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length == 0) return (ISC_R_SUCCESS); - hkey = (HMACSHA1_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA1_Key)); + hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha1_key_t)); if (hkey == NULL) return (ISC_R_NOMEMORY); @@ -490,7 +504,7 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { } key->key_size = keylen * 8; - key->opaque = hkey; + key->keydata.hmacsha1 = hkey; return (ISC_R_SUCCESS); } @@ -498,15 +512,15 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha1_tofile(const dst_key_t *key, const char *directory) { int cnt = 0; - HMACSHA1_Key *hkey; + dst_hmacsha1_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; unsigned char buf[2]; - if (key->opaque == NULL) + if (key->keydata.hmacsha1 == NULL) return (DST_R_NULLKEY); - hkey = (HMACSHA1_Key *) key->opaque; + hkey = key->keydata.hmacsha1; priv.elements[cnt].tag = TAG_HMACSHA1_KEY; priv.elements[cnt].length = bytes; @@ -541,7 +555,7 @@ hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer) { switch (priv.elements[i].tag) { case TAG_HMACSHA1_KEY: isc_buffer_init(&b, priv.elements[i].data, - priv.elements[i].length); + priv.elements[i].length); isc_buffer_add(&b, priv.elements[i].length); tresult = hmacsha1_fromdns(key, &b); if (tresult != ISC_R_SUCCESS) @@ -579,6 +593,7 @@ static dst_func_t hmacsha1_functions = { hmacsha1_tofile, hmacsha1_parse, NULL, /* cleanup */ + NULL, /* fromlabel */ }; isc_result_t @@ -591,37 +606,37 @@ dst__hmacsha1_init(dst_func_t **funcp) { static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data); -typedef struct { +struct dst_hmacsha224_key { unsigned char key[ISC_SHA224_DIGESTLENGTH]; -} HMACSHA224_Key; +}; static isc_result_t hmacsha224_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacsha224_t *hmacsha224ctx; - HMACSHA224_Key *hkey = key->opaque; + dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224; hmacsha224ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha224_t)); if (hmacsha224ctx == NULL) return (ISC_R_NOMEMORY); isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_DIGESTLENGTH); - dctx->opaque = hmacsha224ctx; + dctx->ctxdata.hmacsha224ctx = hmacsha224ctx; return (ISC_R_SUCCESS); } static void hmacsha224_destroyctx(dst_context_t *dctx) { - isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx; if (hmacsha224ctx != NULL) { isc_hmacsha224_invalidate(hmacsha224ctx); isc_mem_put(dctx->mctx, hmacsha224ctx, sizeof(isc_hmacsha224_t)); - dctx->opaque = NULL; + dctx->ctxdata.hmacsha224ctx = NULL; } } static isc_result_t hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx; isc_hmacsha224_update(hmacsha224ctx, data->base, data->length); return (ISC_R_SUCCESS); @@ -629,7 +644,7 @@ hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx; unsigned char *digest; if (isc_buffer_availablelength(sig) < ISC_SHA224_DIGESTLENGTH) @@ -643,7 +658,7 @@ hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_hmacsha224_t *hmacsha224ctx = dctx->opaque; + isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx; if (sig->length > ISC_SHA224_DIGESTLENGTH || sig->length == 0) return (DST_R_VERIFYFAILURE); @@ -656,10 +671,10 @@ hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) { - HMACSHA224_Key *hkey1, *hkey2; + dst_hmacsha224_key_t *hkey1, *hkey2; - hkey1 = (HMACSHA224_Key *)key1->opaque; - hkey2 = (HMACSHA224_Key *)key2->opaque; + hkey1 = key1->keydata.hmacsha224; + hkey2 = key2->keydata.hmacsha224; if (hkey1 == NULL && hkey2 == NULL) return (ISC_TRUE); @@ -707,20 +722,20 @@ hmacsha224_isprivate(const dst_key_t *key) { static void hmacsha224_destroy(dst_key_t *key) { - HMACSHA224_Key *hkey = key->opaque; - memset(hkey, 0, sizeof(HMACSHA224_Key)); - isc_mem_put(key->mctx, hkey, sizeof(HMACSHA224_Key)); - key->opaque = NULL; + dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224; + memset(hkey, 0, sizeof(dst_hmacsha224_key_t)); + isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha224_key_t)); + key->keydata.hmacsha224 = NULL; } static isc_result_t hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) { - HMACSHA224_Key *hkey; + dst_hmacsha224_key_t *hkey; unsigned int bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.hmacsha224 != NULL); - hkey = (HMACSHA224_Key *) key->opaque; + hkey = key->keydata.hmacsha224; bytes = (key->key_size + 7) / 8; if (isc_buffer_availablelength(data) < bytes) @@ -732,7 +747,7 @@ hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { - HMACSHA224_Key *hkey; + dst_hmacsha224_key_t *hkey; int keylen; isc_region_t r; isc_sha224_t sha224ctx; @@ -741,7 +756,7 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length == 0) return (ISC_R_SUCCESS); - hkey = (HMACSHA224_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA224_Key)); + hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha224_key_t)); if (hkey == NULL) return (ISC_R_NOMEMORY); @@ -759,7 +774,7 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { } key->key_size = keylen * 8; - key->opaque = hkey; + key->keydata.hmacsha224 = hkey; return (ISC_R_SUCCESS); } @@ -767,15 +782,15 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha224_tofile(const dst_key_t *key, const char *directory) { int cnt = 0; - HMACSHA224_Key *hkey; + dst_hmacsha224_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; unsigned char buf[2]; - if (key->opaque == NULL) + if (key->keydata.hmacsha224 == NULL) return (DST_R_NULLKEY); - hkey = (HMACSHA224_Key *) key->opaque; + hkey = key->keydata.hmacsha224; priv.elements[cnt].tag = TAG_HMACSHA224_KEY; priv.elements[cnt].length = bytes; @@ -810,7 +825,7 @@ hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer) { switch (priv.elements[i].tag) { case TAG_HMACSHA224_KEY: isc_buffer_init(&b, priv.elements[i].data, - priv.elements[i].length); + priv.elements[i].length); isc_buffer_add(&b, priv.elements[i].length); tresult = hmacsha224_fromdns(key, &b); if (tresult != ISC_R_SUCCESS) @@ -848,6 +863,7 @@ static dst_func_t hmacsha224_functions = { hmacsha224_tofile, hmacsha224_parse, NULL, /* cleanup */ + NULL, /* fromlabel */ }; isc_result_t @@ -860,37 +876,37 @@ dst__hmacsha224_init(dst_func_t **funcp) { static isc_result_t hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data); -typedef struct { +struct dst_hmacsha256_key { unsigned char key[ISC_SHA256_DIGESTLENGTH]; -} HMACSHA256_Key; +}; static isc_result_t hmacsha256_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacsha256_t *hmacsha256ctx; - HMACSHA256_Key *hkey = key->opaque; + dst_hmacsha256_key_t *hkey = key->keydata.hmacsha256; hmacsha256ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha256_t)); if (hmacsha256ctx == NULL) return (ISC_R_NOMEMORY); isc_hmacsha256_init(hmacsha256ctx, hkey->key, ISC_SHA256_DIGESTLENGTH); - dctx->opaque = hmacsha256ctx; + dctx->ctxdata.hmacsha256ctx = hmacsha256ctx; return (ISC_R_SUCCESS); } static void hmacsha256_destroyctx(dst_context_t *dctx) { - isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx; if (hmacsha256ctx != NULL) { isc_hmacsha256_invalidate(hmacsha256ctx); isc_mem_put(dctx->mctx, hmacsha256ctx, sizeof(isc_hmacsha256_t)); - dctx->opaque = NULL; + dctx->ctxdata.hmacsha256ctx = NULL; } } static isc_result_t hmacsha256_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx; isc_hmacsha256_update(hmacsha256ctx, data->base, data->length); return (ISC_R_SUCCESS); @@ -898,7 +914,7 @@ hmacsha256_adddata(dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmacsha256_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx; unsigned char *digest; if (isc_buffer_availablelength(sig) < ISC_SHA256_DIGESTLENGTH) @@ -912,7 +928,7 @@ hmacsha256_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t hmacsha256_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_hmacsha256_t *hmacsha256ctx = dctx->opaque; + isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx; if (sig->length > ISC_SHA256_DIGESTLENGTH || sig->length == 0) return (DST_R_VERIFYFAILURE); @@ -925,10 +941,10 @@ hmacsha256_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t hmacsha256_compare(const dst_key_t *key1, const dst_key_t *key2) { - HMACSHA256_Key *hkey1, *hkey2; + dst_hmacsha256_key_t *hkey1, *hkey2; - hkey1 = (HMACSHA256_Key *)key1->opaque; - hkey2 = (HMACSHA256_Key *)key2->opaque; + hkey1 = key1->keydata.hmacsha256; + hkey2 = key2->keydata.hmacsha256; if (hkey1 == NULL && hkey2 == NULL) return (ISC_TRUE); @@ -976,20 +992,20 @@ hmacsha256_isprivate(const dst_key_t *key) { static void hmacsha256_destroy(dst_key_t *key) { - HMACSHA256_Key *hkey = key->opaque; - memset(hkey, 0, sizeof(HMACSHA256_Key)); - isc_mem_put(key->mctx, hkey, sizeof(HMACSHA256_Key)); - key->opaque = NULL; + dst_hmacsha256_key_t *hkey = key->keydata.hmacsha256; + memset(hkey, 0, sizeof(dst_hmacsha256_key_t)); + isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha256_key_t)); + key->keydata.hmacsha256 = NULL; } static isc_result_t hmacsha256_todns(const dst_key_t *key, isc_buffer_t *data) { - HMACSHA256_Key *hkey; + dst_hmacsha256_key_t *hkey; unsigned int bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.hmacsha256 != NULL); - hkey = (HMACSHA256_Key *) key->opaque; + hkey = key->keydata.hmacsha256; bytes = (key->key_size + 7) / 8; if (isc_buffer_availablelength(data) < bytes) @@ -1001,7 +1017,7 @@ hmacsha256_todns(const dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { - HMACSHA256_Key *hkey; + dst_hmacsha256_key_t *hkey; int keylen; isc_region_t r; isc_sha256_t sha256ctx; @@ -1010,7 +1026,7 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length == 0) return (ISC_R_SUCCESS); - hkey = (HMACSHA256_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA256_Key)); + hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha256_key_t)); if (hkey == NULL) return (ISC_R_NOMEMORY); @@ -1028,7 +1044,7 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { } key->key_size = keylen * 8; - key->opaque = hkey; + key->keydata.hmacsha256 = hkey; return (ISC_R_SUCCESS); } @@ -1036,15 +1052,15 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha256_tofile(const dst_key_t *key, const char *directory) { int cnt = 0; - HMACSHA256_Key *hkey; + dst_hmacsha256_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; unsigned char buf[2]; - if (key->opaque == NULL) + if (key->keydata.hmacsha256 == NULL) return (DST_R_NULLKEY); - hkey = (HMACSHA256_Key *) key->opaque; + hkey = key->keydata.hmacsha256; priv.elements[cnt].tag = TAG_HMACSHA256_KEY; priv.elements[cnt].length = bytes; @@ -1079,7 +1095,7 @@ hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer) { switch (priv.elements[i].tag) { case TAG_HMACSHA256_KEY: isc_buffer_init(&b, priv.elements[i].data, - priv.elements[i].length); + priv.elements[i].length); isc_buffer_add(&b, priv.elements[i].length); tresult = hmacsha256_fromdns(key, &b); if (tresult != ISC_R_SUCCESS) @@ -1117,6 +1133,7 @@ static dst_func_t hmacsha256_functions = { hmacsha256_tofile, hmacsha256_parse, NULL, /* cleanup */ + NULL, /* fromlabel */ }; isc_result_t @@ -1129,37 +1146,37 @@ dst__hmacsha256_init(dst_func_t **funcp) { static isc_result_t hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data); -typedef struct { +struct dst_hmacsha384_key { unsigned char key[ISC_SHA384_DIGESTLENGTH]; -} HMACSHA384_Key; +}; static isc_result_t hmacsha384_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacsha384_t *hmacsha384ctx; - HMACSHA384_Key *hkey = key->opaque; + dst_hmacsha384_key_t *hkey = key->keydata.hmacsha384; hmacsha384ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha384_t)); if (hmacsha384ctx == NULL) return (ISC_R_NOMEMORY); isc_hmacsha384_init(hmacsha384ctx, hkey->key, ISC_SHA384_DIGESTLENGTH); - dctx->opaque = hmacsha384ctx; + dctx->ctxdata.hmacsha384ctx = hmacsha384ctx; return (ISC_R_SUCCESS); } static void hmacsha384_destroyctx(dst_context_t *dctx) { - isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx; if (hmacsha384ctx != NULL) { isc_hmacsha384_invalidate(hmacsha384ctx); isc_mem_put(dctx->mctx, hmacsha384ctx, sizeof(isc_hmacsha384_t)); - dctx->opaque = NULL; + dctx->ctxdata.hmacsha384ctx = NULL; } } static isc_result_t hmacsha384_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx; isc_hmacsha384_update(hmacsha384ctx, data->base, data->length); return (ISC_R_SUCCESS); @@ -1167,7 +1184,7 @@ hmacsha384_adddata(dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmacsha384_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx; unsigned char *digest; if (isc_buffer_availablelength(sig) < ISC_SHA384_DIGESTLENGTH) @@ -1181,7 +1198,7 @@ hmacsha384_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t hmacsha384_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_hmacsha384_t *hmacsha384ctx = dctx->opaque; + isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx; if (sig->length > ISC_SHA384_DIGESTLENGTH || sig->length == 0) return (DST_R_VERIFYFAILURE); @@ -1194,10 +1211,10 @@ hmacsha384_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t hmacsha384_compare(const dst_key_t *key1, const dst_key_t *key2) { - HMACSHA384_Key *hkey1, *hkey2; + dst_hmacsha384_key_t *hkey1, *hkey2; - hkey1 = (HMACSHA384_Key *)key1->opaque; - hkey2 = (HMACSHA384_Key *)key2->opaque; + hkey1 = key1->keydata.hmacsha384; + hkey2 = key2->keydata.hmacsha384; if (hkey1 == NULL && hkey2 == NULL) return (ISC_TRUE); @@ -1245,20 +1262,20 @@ hmacsha384_isprivate(const dst_key_t *key) { static void hmacsha384_destroy(dst_key_t *key) { - HMACSHA384_Key *hkey = key->opaque; - memset(hkey, 0, sizeof(HMACSHA384_Key)); - isc_mem_put(key->mctx, hkey, sizeof(HMACSHA384_Key)); - key->opaque = NULL; + dst_hmacsha384_key_t *hkey = key->keydata.hmacsha384; + memset(hkey, 0, sizeof(dst_hmacsha384_key_t)); + isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha384_key_t)); + key->keydata.hmacsha384 = NULL; } static isc_result_t hmacsha384_todns(const dst_key_t *key, isc_buffer_t *data) { - HMACSHA384_Key *hkey; + dst_hmacsha384_key_t *hkey; unsigned int bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.hmacsha384 != NULL); - hkey = (HMACSHA384_Key *) key->opaque; + hkey = key->keydata.hmacsha384; bytes = (key->key_size + 7) / 8; if (isc_buffer_availablelength(data) < bytes) @@ -1270,7 +1287,7 @@ hmacsha384_todns(const dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { - HMACSHA384_Key *hkey; + dst_hmacsha384_key_t *hkey; int keylen; isc_region_t r; isc_sha384_t sha384ctx; @@ -1279,7 +1296,7 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length == 0) return (ISC_R_SUCCESS); - hkey = (HMACSHA384_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA384_Key)); + hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha384_key_t)); if (hkey == NULL) return (ISC_R_NOMEMORY); @@ -1297,7 +1314,7 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { } key->key_size = keylen * 8; - key->opaque = hkey; + key->keydata.hmacsha384 = hkey; return (ISC_R_SUCCESS); } @@ -1305,15 +1322,15 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha384_tofile(const dst_key_t *key, const char *directory) { int cnt = 0; - HMACSHA384_Key *hkey; + dst_hmacsha384_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; unsigned char buf[2]; - if (key->opaque == NULL) + if (key->keydata.hmacsha384 == NULL) return (DST_R_NULLKEY); - hkey = (HMACSHA384_Key *) key->opaque; + hkey = key->keydata.hmacsha384; priv.elements[cnt].tag = TAG_HMACSHA384_KEY; priv.elements[cnt].length = bytes; @@ -1348,7 +1365,7 @@ hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer) { switch (priv.elements[i].tag) { case TAG_HMACSHA384_KEY: isc_buffer_init(&b, priv.elements[i].data, - priv.elements[i].length); + priv.elements[i].length); isc_buffer_add(&b, priv.elements[i].length); tresult = hmacsha384_fromdns(key, &b); if (tresult != ISC_R_SUCCESS) @@ -1386,6 +1403,7 @@ static dst_func_t hmacsha384_functions = { hmacsha384_tofile, hmacsha384_parse, NULL, /* cleanup */ + NULL, /* fromlabel */ }; isc_result_t @@ -1398,37 +1416,37 @@ dst__hmacsha384_init(dst_func_t **funcp) { static isc_result_t hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data); -typedef struct { +struct dst_hmacsha512_key { unsigned char key[ISC_SHA512_DIGESTLENGTH]; -} HMACSHA512_Key; +}; static isc_result_t hmacsha512_createctx(dst_key_t *key, dst_context_t *dctx) { isc_hmacsha512_t *hmacsha512ctx; - HMACSHA512_Key *hkey = key->opaque; + dst_hmacsha512_key_t *hkey = key->keydata.hmacsha512; hmacsha512ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha512_t)); if (hmacsha512ctx == NULL) return (ISC_R_NOMEMORY); isc_hmacsha512_init(hmacsha512ctx, hkey->key, ISC_SHA512_DIGESTLENGTH); - dctx->opaque = hmacsha512ctx; + dctx->ctxdata.hmacsha512ctx = hmacsha512ctx; return (ISC_R_SUCCESS); } static void hmacsha512_destroyctx(dst_context_t *dctx) { - isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx; if (hmacsha512ctx != NULL) { isc_hmacsha512_invalidate(hmacsha512ctx); isc_mem_put(dctx->mctx, hmacsha512ctx, sizeof(isc_hmacsha512_t)); - dctx->opaque = NULL; + dctx->ctxdata.hmacsha512ctx = NULL; } } static isc_result_t hmacsha512_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx; isc_hmacsha512_update(hmacsha512ctx, data->base, data->length); return (ISC_R_SUCCESS); @@ -1436,7 +1454,7 @@ hmacsha512_adddata(dst_context_t *dctx, const isc_region_t *data) { static isc_result_t hmacsha512_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx; unsigned char *digest; if (isc_buffer_availablelength(sig) < ISC_SHA512_DIGESTLENGTH) @@ -1450,7 +1468,7 @@ hmacsha512_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t hmacsha512_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_hmacsha512_t *hmacsha512ctx = dctx->opaque; + isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx; if (sig->length > ISC_SHA512_DIGESTLENGTH || sig->length == 0) return (DST_R_VERIFYFAILURE); @@ -1463,10 +1481,10 @@ hmacsha512_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t hmacsha512_compare(const dst_key_t *key1, const dst_key_t *key2) { - HMACSHA512_Key *hkey1, *hkey2; + dst_hmacsha512_key_t *hkey1, *hkey2; - hkey1 = (HMACSHA512_Key *)key1->opaque; - hkey2 = (HMACSHA512_Key *)key2->opaque; + hkey1 = key1->keydata.hmacsha512; + hkey2 = key2->keydata.hmacsha512; if (hkey1 == NULL && hkey2 == NULL) return (ISC_TRUE); @@ -1514,20 +1532,20 @@ hmacsha512_isprivate(const dst_key_t *key) { static void hmacsha512_destroy(dst_key_t *key) { - HMACSHA512_Key *hkey = key->opaque; - memset(hkey, 0, sizeof(HMACSHA512_Key)); - isc_mem_put(key->mctx, hkey, sizeof(HMACSHA512_Key)); - key->opaque = NULL; + dst_hmacsha512_key_t *hkey = key->keydata.hmacsha512; + memset(hkey, 0, sizeof(dst_hmacsha512_key_t)); + isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha512_key_t)); + key->keydata.hmacsha512 = NULL; } static isc_result_t hmacsha512_todns(const dst_key_t *key, isc_buffer_t *data) { - HMACSHA512_Key *hkey; + dst_hmacsha512_key_t *hkey; unsigned int bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.hmacsha512 != NULL); - hkey = (HMACSHA512_Key *) key->opaque; + hkey = key->keydata.hmacsha512; bytes = (key->key_size + 7) / 8; if (isc_buffer_availablelength(data) < bytes) @@ -1539,7 +1557,7 @@ hmacsha512_todns(const dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { - HMACSHA512_Key *hkey; + dst_hmacsha512_key_t *hkey; int keylen; isc_region_t r; isc_sha512_t sha512ctx; @@ -1548,7 +1566,7 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { if (r.length == 0) return (ISC_R_SUCCESS); - hkey = (HMACSHA512_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA512_Key)); + hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha512_key_t)); if (hkey == NULL) return (ISC_R_NOMEMORY); @@ -1566,7 +1584,7 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { } key->key_size = keylen * 8; - key->opaque = hkey; + key->keydata.hmacsha512 = hkey; return (ISC_R_SUCCESS); } @@ -1574,15 +1592,15 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { static isc_result_t hmacsha512_tofile(const dst_key_t *key, const char *directory) { int cnt = 0; - HMACSHA512_Key *hkey; + dst_hmacsha512_key_t *hkey; dst_private_t priv; int bytes = (key->key_size + 7) / 8; unsigned char buf[2]; - if (key->opaque == NULL) + if (key->keydata.hmacsha512 == NULL) return (DST_R_NULLKEY); - hkey = (HMACSHA512_Key *) key->opaque; + hkey = key->keydata.hmacsha512; priv.elements[cnt].tag = TAG_HMACSHA512_KEY; priv.elements[cnt].length = bytes; @@ -1617,7 +1635,7 @@ hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer) { switch (priv.elements[i].tag) { case TAG_HMACSHA512_KEY: isc_buffer_init(&b, priv.elements[i].data, - priv.elements[i].length); + priv.elements[i].length); isc_buffer_add(&b, priv.elements[i].length); tresult = hmacsha512_fromdns(key, &b); if (tresult != ISC_R_SUCCESS) @@ -1655,6 +1673,7 @@ static dst_func_t hmacsha512_functions = { hmacsha512_tofile, hmacsha512_parse, NULL, /* cleanup */ + NULL, /* fromlabel */ }; isc_result_t diff --git a/lib/dns/include/Makefile.in b/lib/dns/include/Makefile.in index 593ad5a..b52cb98 100644 --- a/lib/dns/include/Makefile.in +++ b/lib/dns/include/Makefile.in @@ -1,7 +1,7 @@ -# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2001 Internet Software Consortium. # -# Permission to use, copy, modify, and distribute this software for any +# 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. # @@ -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.12.18.1 2004/12/09 04:41:46 marka Exp $ +# $Id: Makefile.in,v 1.15 2007/06/19 23:47:16 tbox Exp $ srcdir = @srcdir@ VPATH = @srcdir@ diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in index 3f367bc..e9e049e 100644 --- a/lib/dns/include/dns/Makefile.in +++ b/lib/dns/include/dns/Makefile.in @@ -1,7 +1,7 @@ -# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2003 Internet Software Consortium. # -# Permission to use, copy, modify, and distribute this software for any +# 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. # @@ -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.50 2004/03/05 05:09:40 marka Exp $ +# $Id: Makefile.in,v 1.55 2008/11/14 23:47:33 tbox Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -23,14 +23,14 @@ top_srcdir = @top_srcdir@ HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h \ cert.h compress.h \ - db.h dbiterator.h dbtable.h diff.h dispatch.h \ - dnssec.h ds.h events.h fixedname.h journal.h keyflags.h \ + db.h dbiterator.h dbtable.h diff.h dispatch.h dlz.h \ + dnssec.h ds.h events.h fixedname.h iptable.h journal.h keyflags.h \ keytable.h keyvalues.h lib.h log.h master.h masterdump.h \ message.h name.h ncache.h \ nsec.h peer.h portlist.h rbt.h rcode.h \ rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ rdataslab.h rdatatype.h request.h resolver.h result.h \ - rootns.h sdb.h secalg.h secproto.h soa.h ssu.h \ + rootns.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \ tcpmsg.h time.h tkey.h \ tsig.h ttl.h types.h validator.h version.h view.h xfrin.h \ zone.h zonekey.h zt.h diff --git a/lib/dns/include/dns/acache.h b/lib/dns/include/dns/acache.h index 50d7fc1..28990c2 100644 --- a/lib/dns/include/dns/acache.h +++ b/lib/dns/include/dns/acache.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acache.h,v 1.3.2.4 2006/05/03 00:07:49 marka Exp $ */ +/* $Id: acache.h,v 1.8 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_ACACHE_H #define DNS_ACACHE_H 1 diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h index 34e394f..721fe51 100644 --- a/lib/dns/include/dns/acl.h +++ b/lib/dns/include/dns/acl.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acl.h,v 1.22.18.4 2006/03/02 00:37:21 marka Exp $ */ +/* $Id: acl.h,v 1.31.206.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_ACL_H #define DNS_ACL_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/acl.h * \brief * Address match list handling. */ @@ -40,6 +40,7 @@ #include <dns/name.h> #include <dns/types.h> +#include <dns/iptable.h> /*** *** Types @@ -62,20 +63,21 @@ struct dns_aclipprefix { }; struct dns_aclelement { - dns_aclelemettype_t type; - isc_boolean_t negative; - union { - dns_aclipprefix_t ip_prefix; - dns_name_t keyname; - dns_acl_t *nestedacl; - } u; + dns_aclelemettype_t type; + isc_boolean_t negative; + dns_name_t keyname; + dns_acl_t *nestedacl; + int node_num; }; struct dns_acl { unsigned int magic; isc_mem_t *mctx; isc_refcount_t refcount; + dns_iptable_t *iptable; +#define node_count iptable->radix->num_added_node dns_aclelement_t *elements; + isc_boolean_t has_negatives; unsigned int alloc; /*%< Elements allocated */ unsigned int length; /*%< Elements initialized */ char *name; /*%< Temporary use only */ @@ -100,14 +102,9 @@ ISC_LANG_BEGINDECLS isc_result_t dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target); /*%< - * Create a new ACL with room for 'n' elements. - * The elements are uninitialized and the length is 0. - */ - -isc_result_t -dns_acl_appendelement(dns_acl_t *acl, const dns_aclelement_t *elt); -/*%< - * Append an element to an existing ACL. + * Create a new ACL, including an IP table and an array with room + * for 'n' ACL elements. The elements are uninitialized and the + * length is 0. */ isc_result_t @@ -122,6 +119,30 @@ dns_acl_none(isc_mem_t *mctx, dns_acl_t **target); * Create a new ACL that matches nothing. */ +isc_boolean_t +dns_acl_isany(dns_acl_t *acl); +/*%< + * Test whether ACL is set to "{ any; }" + */ + +isc_boolean_t +dns_acl_isnone(dns_acl_t *acl); +/*%< + * Test whether ACL is set to "{ none; }" + */ + +isc_result_t +dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos); +/*%< + * Merge the contents of one ACL into another. Call dns_iptable_merge() + * for the IP tables, then concatenate the element arrays. + * + * If pos is set to false, then the nested ACL is to be negated. This + * means reverse the sense of each *positive* element or IP table node, + * but leave negatives alone, so as to prevent a double-negative causing + * an unexpected positive match in the parent ACL. + */ + void dns_acl_attach(dns_acl_t *source, dns_acl_t **target); @@ -129,17 +150,11 @@ void dns_acl_detach(dns_acl_t **aclp); isc_boolean_t -dns_aclelement_equal(const dns_aclelement_t *ea, const dns_aclelement_t *eb); - -isc_boolean_t -dns_acl_equal(const dns_acl_t *a, const dns_acl_t *b); - -isc_boolean_t dns_acl_isinsecure(const dns_acl_t *a); /*%< * Return #ISC_TRUE iff the acl 'a' is considered insecure, that is, * if it contains IP addresses other than those of the local host. - * This is intended for applications such as printing warning + * This is intended for applications such as printing warning * messages for suspect ACLs; it is not intended for making access * control decisions. We make no guarantee that an ACL for which * this function returns #ISC_FALSE is safe. @@ -147,6 +162,9 @@ dns_acl_isinsecure(const dns_acl_t *a); isc_result_t dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env); +/*%< + * Initialize ACL environment, setting up localhost and localnets ACLs + */ void dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s); @@ -168,19 +186,17 @@ dns_acl_match(const isc_netaddr_t *reqaddr, * Match the address 'reqaddr', and optionally the key name 'reqsigner', * against 'acl'. 'reqsigner' may be NULL. * - * If there is a positive match, '*match' will be set to a positive value - * indicating the distance from the beginning of the list. - * - * If there is a negative match, '*match' will be set to a negative value - * whose absolute value indicates the distance from the beginning of - * the list. - * - * If there is a match (either positive or negative) and 'matchelt' is - * non-NULL, *matchelt will be attached to the primitive - * (non-indirect) address match list element that matched. + * If there is a match, '*match' will be set to an integer whose absolute + * value corresponds to the order in which the matching value was inserted + * into the ACL. For a positive match, this value will be positive; for a + * negative match, it will be negative. * * If there is no match, *match will be set to zero. * + * If there is a match in the element list (either positive or negative) + * and 'matchelt' is non-NULL, *matchelt will be pointed to the matching + * element. + * * Returns: *\li #ISC_R_SUCCESS Always succeeds. */ @@ -189,34 +205,18 @@ isc_boolean_t dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, const dns_aclelement_t *e, - const dns_aclenv_t *env, + const dns_aclenv_t *env, const dns_aclelement_t **matchelt); /*%< * Like dns_acl_match, but matches against the single ACL element 'e' - * rather than a complete list and returns ISC_TRUE iff it matched. - * To determine whether the match was prositive or negative, the + * rather than a complete ACL, and returns ISC_TRUE iff it matched. + * + * To determine whether the match was positive or negative, the * caller should examine e->negative. Since the element 'e' may be - * a reference to a named ACL or a nested ACL, the matching element + * a reference to a named ACL or a nested ACL, a matching element * returned through 'matchelt' is not necessarily 'e' itself. */ -isc_result_t -dns_acl_elementmatch(const dns_acl_t *acl, - const dns_aclelement_t *elt, - const dns_aclelement_t **matchelt); -/*%< - * Search for an ACL element in 'acl' which is exactly the same as 'elt'. - * If there is one, and 'matchelt' is non NULL, then '*matchelt' will point - * to the entry. - * - * This function is intended to be used for avoiding duplicated ACL entries - * before adding an entry. - * - * Returns: - *\li #ISC_R_SUCCESS Match succeeds. - *\li #ISC_R_NOTFOUND Match fails. - */ - ISC_LANG_ENDDECLS #endif /* DNS_ACL_H */ diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 1e3cd61..d4ac40c 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.h,v 1.76.18.3 2005/06/23 04:23:16 marka Exp $ */ +/* $Id: adb.h,v 1.85 2008/04/03 06:09:04 tbox Exp $ */ #ifndef DNS_ADB_H #define DNS_ADB_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/adb.h *\brief * DNS Address Database * @@ -99,7 +99,7 @@ ISC_LANG_BEGINDECLS typedef struct dns_adbname dns_adbname_t; -/*! +/*! *\brief * Represents a lookup for a single name. * @@ -220,7 +220,7 @@ struct dns_adbaddrinfo { ISC_LINK(dns_adbaddrinfo_t) publink; }; -/*!< +/*!< * The event sent to the caller task is just a plain old isc_event_t. It * contains no data other than a simple status, passed in the "type" field * to indicate that another address resolved, or all partially resolved @@ -345,7 +345,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, * * If no events will be generated, the *find->result_v4 and/or result_v6 * members may be examined for address lookup status. The usual #ISC_R_SUCCESS, - * #ISC_R_FAILURE, and #DNS_R_NX{DOMAIN,RRSET} are returned, along with + * #ISC_R_FAILURE, #DNS_R_NXDOMAIN, and #DNS_R_NXRRSET are returned, along with * #ISC_R_NOTFOUND meaning the ADB has not _yet_ found the values. In this * latter case, retrying may produce more addresses. * @@ -520,7 +520,7 @@ void dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int rtt, unsigned int factor); /*%< - * Mix the round trip time into the existing smoothed rtt. + * Mix the round trip time into the existing smoothed rtt. * The formula used * (where srtt is the existing rtt value, and rtt and factor are arguments to @@ -623,13 +623,12 @@ void dns_adb_flushname(dns_adb_t *adb, dns_name_t *name); /*%< * Flush 'name' from the adb cache. - * + * * Requires: *\li 'adb' is valid. *\li 'name' is valid. */ - ISC_LANG_ENDDECLS #endif /* DNS_ADB_H */ diff --git a/lib/dns/include/dns/bit.h b/lib/dns/include/dns/bit.h index 770f294..28c733d 100644 --- a/lib/dns/include/dns/bit.h +++ b/lib/dns/include/dns/bit.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: bit.h,v 1.8.18.2 2005/04/29 00:16:09 marka Exp $ */ +/* $Id: bit.h,v 1.14 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_BIT_H #define DNS_BIT_H 1 -/*! \file */ +/*! \file dns/bit.h */ #include <isc/int.h> #include <isc/boolean.h> diff --git a/lib/dns/include/dns/byaddr.h b/lib/dns/include/dns/byaddr.h index 1f1e88c..edf8430 100644 --- a/lib/dns/include/dns/byaddr.h +++ b/lib/dns/include/dns/byaddr.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: byaddr.h,v 1.16.18.2 2005/04/29 00:16:09 marka Exp $ */ +/* $Id: byaddr.h,v 1.22 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_BYADDR_H #define DNS_BYADDR_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/byaddr.h * \brief * The byaddr module provides reverse lookup services for IPv4 and IPv6 * addresses. @@ -121,8 +121,8 @@ dns_byaddr_cancel(dns_byaddr_t *byaddr); * * Notes: * - *\li If 'byaddr' has not completed, post its #BYADDRDONE event with a - * result code of #ISC_R_CANCELED. + *\li If 'byaddr' has not completed, post its #DNS_EVENT_BYADDRDONE + * event with a result code of #ISC_R_CANCELED. * * Requires: * @@ -138,8 +138,8 @@ dns_byaddr_destroy(dns_byaddr_t **byaddrp); * *\li '*byaddrp' is a valid byaddr. * - *\li The caller has received the BYADDRDONE event (either because the - * byaddr completed or because dns_byaddr_cancel() was called). + *\li The caller has received the #DNS_EVENT_BYADDRDONE event (either because + * the byaddr completed or because dns_byaddr_cancel() was called). * * Ensures: * diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h index fc4f78e..7b37235 100644 --- a/lib/dns/include/dns/cache.h +++ b/lib/dns/include/dns/cache.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cache.h,v 1.19.18.3 2005/08/23 02:31:38 marka Exp $ */ +/* $Id: cache.h,v 1.26 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_CACHE_H #define DNS_CACHE_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/cache.h * \brief * Defines dns_cache_t, the cache object. * diff --git a/lib/dns/include/dns/callbacks.h b/lib/dns/include/dns/callbacks.h index 6aee70b..8a8385a 100644 --- a/lib/dns/include/dns/callbacks.h +++ b/lib/dns/include/dns/callbacks.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: callbacks.h,v 1.18.18.2 2005/04/29 00:16:10 marka Exp $ */ +/* $Id: callbacks.h,v 1.24 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_CALLBACKS_H #define DNS_CALLBACKS_H 1 -/*! \file */ +/*! \file dns/callbacks.h */ /*** *** Imports diff --git a/lib/dns/include/dns/cert.h b/lib/dns/include/dns/cert.h index 4de1aec..1cda848 100644 --- a/lib/dns/include/dns/cert.h +++ b/lib/dns/include/dns/cert.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cert.h,v 1.13.18.2 2005/04/29 00:16:10 marka Exp $ */ +/* $Id: cert.h,v 1.19 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_CERT_H #define DNS_CERT_H 1 -/*! \file */ +/*! \file dns/cert.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/compress.h b/lib/dns/include/dns/compress.h index 4d9c011..4632aff 100644 --- a/lib/dns/include/dns/compress.h +++ b/lib/dns/include/dns/compress.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: compress.h,v 1.32.18.6 2006/03/02 00:37:21 marka Exp $ */ +/* $Id: compress.h,v 1.40.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_COMPRESS_H #define DNS_COMPRESS_H 1 @@ -32,7 +32,7 @@ ISC_LANG_BEGINDECLS #define DNS_COMPRESS_ALL 0x01 /*%< all compression. */ #define DNS_COMPRESS_CASESENSITIVE 0x02 /*%< case sensitive compression. */ -/*! \file +/*! \file dns/compress.h * Direct manipulation of the structures is strongly discouraged. */ @@ -77,7 +77,7 @@ struct dns_decompress { isc_result_t dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx); /*%< - * Inialise the compression context structure pointed to by 'cctx'. + * Initialise the compression context structure pointed to by 'cctx'. * * Requires: * \li 'cctx' is a valid dns_compress_t structure. @@ -136,7 +136,7 @@ dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive); isc_boolean_t dns_compress_getsensitive(dns_compress_t *cctx); /* - * Return whether case is to be preservered when compressing + * Return whether case is to be preserved when compressing * domain names. * * Requires: diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index b03ae57..3b78208 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.h,v 1.76.18.10 2007/08/28 07:20:05 tbox Exp $ */ +/* $Id: db.h,v 1.93.50.3 2009/01/18 23:25:17 marka Exp $ */ #ifndef DNS_DB_H #define DNS_DB_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/db.h * \brief * The DNS DB interface allows named rdatasets to be stored and retrieved. * @@ -111,8 +111,7 @@ typedef struct dns_dbmethods { isc_stdtime_t now); void (*printnode)(dns_db_t *db, dns_dbnode_t *node, FILE *out); - isc_result_t (*createiterator)(dns_db_t *db, - isc_boolean_t relative_names, + isc_result_t (*createiterator)(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp); isc_result_t (*findrdataset)(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, @@ -146,6 +145,28 @@ typedef struct dns_dbmethods { void (*overmem)(dns_db_t *db, isc_boolean_t overmem); void (*settask)(dns_db_t *db, isc_task_t *); isc_result_t (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep); + void (*transfernode)(dns_db_t *db, dns_dbnode_t **sourcep, + dns_dbnode_t **targetp); + isc_result_t (*getnsec3parameters)(dns_db_t *db, + dns_dbversion_t *version, + dns_hash_t *hash, + isc_uint8_t *flags, + isc_uint16_t *iterations, + unsigned char *salt, + size_t *salt_len); + isc_result_t (*findnsec3node)(dns_db_t *db, dns_name_t *name, + isc_boolean_t create, + dns_dbnode_t **nodep); + isc_result_t (*setsigningtime)(dns_db_t *db, + dns_rdataset_t *rdataset, + isc_stdtime_t resign); + isc_result_t (*getsigningtime)(dns_db_t *db, + dns_rdataset_t *rdataset, + dns_name_t *name); + void (*resigned)(dns_db_t *db, dns_rdataset_t *rdataset, + dns_dbversion_t *version); + isc_boolean_t (*isdnssec)(dns_db_t *db); + dns_stats_t *(*getrrsetstats)(dns_db_t *db); } dns_dbmethods_t; typedef isc_result_t @@ -153,7 +174,7 @@ typedef isc_result_t dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc, char *argv[], void *driverarg, dns_db_t **dbp); - + #define DNS_DB_MAGIC ISC_MAGIC('D','N','S','D') #define DNS_DB_VALID(db) ISC_MAGIC_VALID(db, DNS_DB_MAGIC) @@ -191,6 +212,7 @@ struct dns_db { #define DNS_DBFIND_NOEXACT 0x10 #define DNS_DBFIND_FORCENSEC 0x20 #define DNS_DBFIND_COVERINGNSEC 0x40 +#define DNS_DBFIND_FORCENSEC3 0x80 /*@}*/ /*@{*/ @@ -208,6 +230,15 @@ struct dns_db { */ #define DNS_DBSUB_EXACT 0x01 +/*@{*/ +/*% + * Iterator options + */ +#define DNS_DB_RELATIVENAMES 0x1 +#define DNS_DB_NSEC3ONLY 0x2 +#define DNS_DB_NONSEC3 0x4 +/*@}*/ + /***** ***** Methods *****/ @@ -355,6 +386,20 @@ dns_db_issecure(dns_db_t *db); * \li #ISC_FALSE 'db' is not secure. */ +isc_boolean_t +dns_db_isdnssec(dns_db_t *db); +/*%< + * Is 'db' secure or partially secure? + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * Returns: + * \li #ISC_TRUE 'db' is secure or is partially. + * \li #ISC_FALSE 'db' is not secure. + */ + dns_name_t * dns_db_origin(dns_db_t *db); /*%< @@ -626,7 +671,7 @@ dns_db_findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, * * \li #ISC_R_SUCCESS * \li #ISC_R_NOTFOUND If !create and name not found. - * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE. + * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE. * * \li Other results are possible, depending upon the database * implementation used. @@ -785,8 +830,8 @@ dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * name, and 'rdataset' contains * the negative caching proof. * - * \li #DNS_R_EMPTYNAME The name exists but there is - * no data at the name. + * \li #DNS_R_EMPTYNAME The name exists but there is + * no data at the name. * * \li #DNS_R_COVERINGNSEC The returned data is a NSEC * that potentially covers 'name'. @@ -883,6 +928,27 @@ dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep); * \li *nodep is NULL. */ +void +dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep, + dns_dbnode_t **targetp); +/*%< + * Transfer a node between pointer. + * + * This is equivalent to calling dns_db_attachnode() then dns_db_detachnode(). + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li '*sourcep' is a valid node. + * + * \li 'targetp' points to a NULL dns_dbnode_t *. + * + * Ensures: + * + * \li '*sourcep' is NULL. + */ + isc_result_t dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now); /*%< @@ -917,16 +983,17 @@ dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out); ***/ isc_result_t -dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names, +dns_db_createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp); /*%< * Create an iterator for version 'version' of 'db'. * * Notes: * - * \li If 'relative_names' is ISC_TRUE, then node names returned by the - * iterator will be relative to the iterator's current origin. If - * #ISC_FALSE, then the node names will be absolute. + * \li One or more of the following options can be set. + * #DNS_DB_RELATIVENAMES + * #DNS_DB_NSEC3ONLY + * #DNS_DB_NONSEC3 * * Requires: * @@ -1005,7 +1072,7 @@ isc_result_t dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdatasetiter_t **iteratorp); /*%< - * Make '*iteratorp' an rdataset iteratator for all rdatasets at 'node' in + * Make '*iteratorp' an rdataset iterator for all rdatasets at 'node' in * version 'version' of 'db'. * * Notes: @@ -1192,7 +1259,7 @@ dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp); void dns_db_overmem(dns_db_t *db, isc_boolean_t overmem); /*%< - * Enable / disable agressive cache cleaning. + * Enable / disable aggressive cache cleaning. */ unsigned int @@ -1262,7 +1329,7 @@ dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg, void dns_db_unregister(dns_dbimplementation_t **dbimp); /*%< - * Remove a database implementation from the the list of supported + * Remove a database implementation from the list of supported * implementations. No databases of this type can be active when this * is called. * @@ -1294,6 +1361,117 @@ dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep); * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature. */ +isc_result_t +dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, + dns_hash_t *hash, isc_uint8_t *flags, + isc_uint16_t *interations, + unsigned char *salt, size_t *salt_length); +/*%< + * Get the NSEC3 parameters that are associated with this zone. + * + * Requires: + * \li 'db' is a valid zone database. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature + * or this zone does not have NSEC3 records. + */ + +isc_result_t +dns_db_findnsec3node(dns_db_t *db, dns_name_t *name, + isc_boolean_t create, dns_dbnode_t **nodep); +/*%< + * Find the NSEC3 node with name 'name'. + * + * Notes: + * \li If 'create' is ISC_TRUE and no node with name 'name' exists, then + * such a node will be created. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'name' is a valid, non-empty, absolute name. + * + * \li nodep != NULL && *nodep == NULL + * + * Ensures: + * + * \li On success, *nodep is attached to the node with name 'name'. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND If !create and name not found. + * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE. + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, + isc_stdtime_t resign); +/*%< + * Sets the re-signing time associated with 'rdataset' to 'resign'. + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'rdataset' to be associated with 'db'. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation. + */ + +isc_result_t +dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name); +/*%< + * Return the rdataset with the earliest signing time in the zone. + * Note: the rdataset is version agnostic. + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'rdataset' to be initialized but not associated. + * \li 'name' to be NULL or have a buffer associated with it. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND - No dataset exists. + */ + +void +dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, + dns_dbversion_t *version); +/*%< + * Mark 'rdataset' as not being available to be returned by + * dns_db_getsigningtime(). If the changes associated with 'version' + * are committed this will be permanent. If the version is not committed + * this change will be rolled back when the version is closed. + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'rdataset' to be associated with 'db'. + * \li 'version' to be open for writing. + */ + +dns_stats_t * +dns_db_getrrsetstats(dns_db_t *db); +/*%< + * Get statistics information counting RRsets stored in the DB, when available. + * The statistics may not be available depending on the DB implementation. + * + * Requires: + * + * \li 'db' is a valid database (zone or cache). + * + * Returns: + * \li when available, a pointer to a statistics object created by + * dns_rdatasetstats_create(); otherwise NULL. + */ + ISC_LANG_ENDDECLS #endif /* DNS_DB_H */ diff --git a/lib/dns/include/dns/dbiterator.h b/lib/dns/include/dns/dbiterator.h index 47ce082..366d676 100644 --- a/lib/dns/include/dns/dbiterator.h +++ b/lib/dns/include/dns/dbiterator.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dbiterator.h,v 1.19.18.2 2005/04/29 00:16:11 marka Exp $ */ +/* $Id: dbiterator.h,v 1.25 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_DBITERATOR_H #define DNS_DBITERATOR_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/dbiterator.h * \brief * The DNS DB Iterator interface allows iteration of all of the nodes in a * database. diff --git a/lib/dns/include/dns/dbtable.h b/lib/dns/include/dns/dbtable.h index 18d3e50..503de95 100644 --- a/lib/dns/include/dns/dbtable.h +++ b/lib/dns/include/dns/dbtable.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dbtable.h,v 1.17.18.2 2005/04/29 00:16:11 marka Exp $ */ +/* $Id: dbtable.h,v 1.23 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_DBTABLE_H #define DNS_DBTABLE_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/dbtable.h * \brief * DNS DB Tables * diff --git a/lib/dns/include/dns/diff.h b/lib/dns/include/dns/diff.h index cd96a0b..a13b678 100644 --- a/lib/dns/include/dns/diff.h +++ b/lib/dns/include/dns/diff.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: diff.h,v 1.6.18.2 2005/04/29 00:16:12 marka Exp $ */ +/* $Id: diff.h,v 1.15.120.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_DIFF_H #define DNS_DIFF_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/diff.h * \brief * A diff is a convenience type representing a list of changes to be * made to a database. @@ -59,12 +59,18 @@ * individual RRs of a "RRset exists (value dependent)" * prerequisite set. In this case, op==DNS_DIFFOP_EXISTS, * and the TTL is ignored. + * + * DNS_DIFFOP_*RESIGN will cause the 'resign' attribute of the resulting + * RRset to be recomputed to be 'resign' seconds before the earliest RRSIG + * timeexpire. */ typedef enum { - DNS_DIFFOP_ADD, /*%< Add an RR. */ - DNS_DIFFOP_DEL, /*%< Delete an RR. */ - DNS_DIFFOP_EXISTS /*%< Assert RR existence. */ + DNS_DIFFOP_ADD = 0, /*%< Add an RR. */ + DNS_DIFFOP_DEL = 1, /*%< Delete an RR. */ + DNS_DIFFOP_EXISTS = 2, /*%< Assert RR existence. */ + DNS_DIFFOP_ADDRESIGN = 4, /*%< ADD + RESIGN. */ + DNS_DIFFOP_DELRESIGN = 5, /*%< DEL + RESIGN. */ } dns_diffop_t; typedef struct dns_difftuple dns_difftuple_t; @@ -73,7 +79,7 @@ typedef struct dns_difftuple dns_difftuple_t; #define DNS_DIFFTUPLE_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFFTUPLE_MAGIC) struct dns_difftuple { - unsigned int magic; + unsigned int magic; isc_mem_t *mctx; dns_diffop_t op; dns_name_t name; @@ -96,10 +102,15 @@ typedef struct dns_diff dns_diff_t; struct dns_diff { unsigned int magic; isc_mem_t * mctx; + /* + * Set the 'resign' attribute to this many second before the + * earliest RRSIG timeexpire. + */ + isc_uint32_t resign; ISC_LIST(dns_difftuple_t) tuples; }; -/* Type of comparision function for sorting diffs. */ +/* Type of comparison function for sorting diffs. */ typedef int dns_diff_compare_func(const void *, const void *); /*** @@ -110,7 +121,7 @@ ISC_LANG_BEGINDECLS /**************************************************************************/ /* - * Maniuplation of diffs and tuples. + * Manipulation of diffs and tuples. */ isc_result_t diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 8c14320..96a44fe 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.h,v 1.48.18.9 2008/06/24 23:45:55 tbox Exp $ */ +/* $Id: dispatch.h,v 1.60.82.2 2009/01/29 23:47:44 tbox Exp $ */ #ifndef DNS_DISPATCH_H #define DNS_DISPATCH_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/dispatch.h * \brief * DNS Dispatch Management * Shared UDP and single-use TCP dispatches for queries and responses. @@ -55,7 +55,7 @@ #include <isc/buffer.h> #include <isc/lang.h> #include <isc/socket.h> -#include <dns/types.h> +#include <isc/types.h> #include <dns/types.h> @@ -222,6 +222,21 @@ dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, *\li v6portset is NULL or a valid port set */ +void +dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); +/*%< + * Sets statistics counter for the dispatchmgr. This function is expected to + * be called only on zone creation (when necessary). + * Once installed, it cannot be removed or replaced. Also, there is no + * interface to get the installed stats from the zone; the caller must keep the + * stats to reference (e.g. dump) it later. + * + * Requires: + *\li mgr is a valid dispatchmgr with no managed dispatch. + *\li stats is a valid statistics supporting resolver statistics counters + * (see dns/stats.h). + */ + isc_result_t dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr, diff --git a/lib/dns/include/dns/dlz.h b/lib/dns/include/dns/dlz.h index 4c61c91..75ba99f 100644 --- a/lib/dns/include/dns/dlz.h +++ b/lib/dns/include/dns/dlz.h @@ -1,8 +1,8 @@ /* - * Portions Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -50,9 +50,9 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlz.h,v 1.2.2.2 2005/09/06 03:47:18 marka Exp $ */ +/* $Id: dlz.h,v 1.7.332.2 2009/01/18 23:47:41 tbox Exp $ */ -/*! \file */ +/*! \file dns/dlz.h */ #ifndef DLZ_H #define DLZ_H 1 @@ -133,7 +133,7 @@ typedef void /*%< * Method prototype. Drivers implementing the DLZ interface MUST * supply a destroy method. This method is called when the DNS server - * is shuting down and no longer needs the driver. + * is shutting down and no longer needs the driver. */ typedef isc_result_t @@ -157,7 +157,7 @@ typedef isc_result_t * \li 3) we run out of domain name labels. I.E. we have tried the * shortest domain name * \li 4) the number of labels in the domain name is less than - * min_lables for dns_dlzfindzone + * min_labels for dns_dlzfindzone * * The driver's find zone method should return ISC_R_SUCCESS and a * database pointer to the name server if the zone is supported by the @@ -202,7 +202,7 @@ dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name, /*%< * This method is called when the DNS server is performing a zone - * transfer query. It will call the DLZ driver's allow zone tranfer + * transfer query. It will call the DLZ driver's allow zone transfer * method. */ @@ -223,7 +223,7 @@ void dns_dlzdestroy(dns_dlzdb_t **dbp); /*%< - * This method is called when the DNS server is shuting down and no + * This method is called when the DNS server is shutting down and no * longer needs the driver. If the DLZ driver supplies a destroy * methods, this function will call it. */ diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h index 2804e03..f8a59d0 100644 --- a/lib/dns/include/dns/dnssec.h +++ b/lib/dns/include/dns/dnssec.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec.h,v 1.26.18.2 2005/04/29 00:16:12 marka Exp $ */ +/* $Id: dnssec.h,v 1.32 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_DNSSEC_H #define DNS_DNSSEC_H 1 -/*! \file */ +/*! \file dns/dnssec.h */ #include <isc/lang.h> #include <isc/stdtime.h> diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h index 5e4cc40..b59fb83 100644 --- a/lib/dns/include/dns/ds.h +++ b/lib/dns/include/dns/ds.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds.h,v 1.3.20.5 2006/02/22 23:50:09 marka Exp $ */ +/* $Id: ds.h,v 1.10 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_DS_H #define DNS_DS_H 1 diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index d1ebef3..bb61b9d 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,14 +15,14 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: events.h,v 1.42.18.3 2005/04/29 00:16:13 marka Exp $ */ +/* $Id: events.h,v 1.49.332.2 2009/05/07 23:47:12 tbox Exp $ */ #ifndef DNS_EVENTS_H #define DNS_EVENTS_H 1 #include <isc/eventclass.h> -/*! \file +/*! \file dns/events.h * \brief * Registry of DNS event numbers. */ @@ -68,6 +68,7 @@ #define DNS_EVENT_ACACHECONTROL (ISC_EVENTCLASS_DNS + 38) #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_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) #define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) diff --git a/lib/dns/include/dns/fixedname.h b/lib/dns/include/dns/fixedname.h index 8380de6..5a2aaf3 100644 --- a/lib/dns/include/dns/fixedname.h +++ b/lib/dns/include/dns/fixedname.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: fixedname.h,v 1.13.18.2 2005/04/29 00:16:13 marka Exp $ */ +/* $Id: fixedname.h,v 1.19 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_FIXEDNAME_H #define DNS_FIXEDNAME_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/fixedname.h * \brief * Fixed-size Names * diff --git a/lib/dns/include/dns/forward.h b/lib/dns/include/dns/forward.h index ddf6d7f..512c5e3 100644 --- a/lib/dns/include/dns/forward.h +++ b/lib/dns/include/dns/forward.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: forward.h,v 1.3.18.3 2005/04/27 05:01:33 sra Exp $ */ +/* $Id: forward.h,v 1.11 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_FORWARD_H #define DNS_FORWARD_H 1 -/*! \file */ +/*! \file dns/forward.h */ #include <isc/lang.h> #include <isc/result.h> diff --git a/lib/dns/include/dns/iptable.h b/lib/dns/include/dns/iptable.h new file mode 100644 index 0000000..d7eb140 --- /dev/null +++ b/lib/dns/include/dns/iptable.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007 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: iptable.h,v 1.4 2007/09/14 01:46:05 marka Exp $ */ + +#ifndef DNS_IPTABLE_H +#define DNS_IPTABLE_H 1 + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/radix.h> + +struct dns_iptable { + unsigned int magic; + isc_mem_t *mctx; + isc_refcount_t refcount; + isc_radix_tree_t *radix; + ISC_LINK(dns_iptable_t) nextincache; +}; + +#define DNS_IPTABLE_MAGIC ISC_MAGIC('T','a','b','l') +#define DNS_IPTABLE_VALID(a) ISC_MAGIC_VALID(a, DNS_IPTABLE_MAGIC) + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target); +/* + * Create a new IP table and the underlying radix structure + */ + +isc_result_t +dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr, + isc_uint16_t bitlen, isc_boolean_t pos); +/* + * Add an IP prefix to an existing IP table + */ + +isc_result_t +dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos); +/* + * Merge one IP table into another one. + */ + +void +dns_iptable_attach(dns_iptable_t *source, dns_iptable_t **target); + +void +dns_iptable_detach(dns_iptable_t **tabp); + +ISC_LANG_ENDDECLS + +#endif /* DNS_IPTABLE_H */ diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h index b776a30..3917d8d 100644 --- a/lib/dns/include/dns/journal.h +++ b/lib/dns/include/dns/journal.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.h,v 1.25.18.2 2005/04/29 00:16:13 marka Exp $ */ +/* $Id: journal.h,v 1.33.120.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_JOURNAL_H #define DNS_JOURNAL_H 1 @@ -24,9 +24,9 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/journal.h * \brief - * Database journalling. + * Database journaling. */ /*** @@ -42,6 +42,11 @@ #include <dns/types.h> /*** + *** Defines. + ***/ +#define DNS_JOURNALOPT_RESIGN 0x00000001 + +/*** *** Types ***/ @@ -188,7 +193,7 @@ dns_journal_iter_init(dns_journal_t *j, * Returns: *\li ISC_R_SUCCESS *\li ISC_R_RANGE begin_serial is outside the addressable range. - *\li ISC_R_NOTFOUND begin_serial is within the range of adressable + *\li ISC_R_NOTFOUND begin_serial is within the range of addressable * serial numbers covered by the journal, but * this particular serial number does not exist. */ @@ -225,17 +230,18 @@ dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, isc_uint32_t *ttl, */ isc_result_t -dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename); +dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, unsigned int options, + const char *filename); /*%< * Roll forward (play back) the journal file "filename" into the * database "db". This should be called when the server starts * after a shutdown or crash. * * Requires: - *\li 'mctx' is a valid memory context. + *\li 'mctx' is a valid memory context. *\li 'db' is a valid database which does not have a version * open for writing. - * \li 'filename' is the name of the journal file belonging to 'db'. + *\li 'filename' is the name of the journal file belonging to 'db'. * * Returns: *\li DNS_R_NOJOURNAL when journal does not exist. @@ -264,7 +270,7 @@ dns_db_diff(isc_mem_t *mctx, isc_result_t dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, - isc_uint32_t target_size); + isc_uint32_t target_size); /*%< * Attempt to compact the journal if it is greater that 'target_size'. * Changes from 'serial' onwards will be preserved. If the journal diff --git a/lib/dns/include/dns/keyflags.h b/lib/dns/include/dns/keyflags.h index 665b517..74a1740 100644 --- a/lib/dns/include/dns/keyflags.h +++ b/lib/dns/include/dns/keyflags.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keyflags.h,v 1.10.18.2 2005/04/29 00:16:13 marka Exp $ */ +/* $Id: keyflags.h,v 1.16 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_KEYFLAGS_H #define DNS_KEYFLAGS_H 1 -/*! \file */ +/*! \file dns/keyflags.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/keytable.h b/lib/dns/include/dns/keytable.h index b8bfcc1..553aa99 100644 --- a/lib/dns/include/dns/keytable.h +++ b/lib/dns/include/dns/keytable.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keytable.h,v 1.11.18.3 2005/12/05 00:00:03 marka Exp $ */ +/* $Id: keytable.h,v 1.16 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_KEYTABLE_H #define DNS_KEYTABLE_H 1 diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h index df17ace..7040389 100644 --- a/lib/dns/include/dns/keyvalues.h +++ b/lib/dns/include/dns/keyvalues.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keyvalues.h,v 1.15.18.2 2005/04/29 00:16:14 marka Exp $ */ +/* $Id: keyvalues.h,v 1.23 2008/09/25 04:02:39 tbox Exp $ */ #ifndef DNS_KEYVALUES_H #define DNS_KEYVALUES_H 1 -/*! \file */ +/*! \file dns/keyvalues.h */ /* * Flags field of the KEY RR rdata @@ -64,9 +64,11 @@ #define DNS_KEYALG_RSA DNS_KEYALG_RSAMD5 #define DNS_KEYALG_DH 2 /*%< Diffie Hellman KEY */ #define DNS_KEYALG_DSA 3 /*%< DSA KEY */ -#define DNS_KEYALG_DSS NS_ALG_DSA +#define DNS_KEYALG_NSEC3DSA 6 +#define DNS_KEYALG_DSS DNS_ALG_DSA #define DNS_KEYALG_ECC 4 #define DNS_KEYALG_RSASHA1 5 +#define DNS_KEYALG_NSEC3RSASHA1 7 #define DNS_KEYALG_INDIRECT 252 #define DNS_KEYALG_PRIVATEDNS 253 #define DNS_KEYALG_PRIVATEOID 254 /*%< Key begins with OID giving alg */ diff --git a/lib/dns/include/dns/lib.h b/lib/dns/include/dns/lib.h index d59dde3..fd3325b 100644 --- a/lib/dns/include/dns/lib.h +++ b/lib/dns/include/dns/lib.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.h,v 1.8.18.4 2005/09/20 04:33:48 marka Exp $ */ +/* $Id: lib.h,v 1.16 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_LIB_H #define DNS_LIB_H 1 -/*! \file */ +/*! \file dns/lib.h */ #include <isc/types.h> #include <isc/lang.h> diff --git a/lib/dns/include/dns/log.h b/lib/dns/include/dns/log.h index 7bee174..b7aed42 100644 --- a/lib/dns/include/dns/log.h +++ b/lib/dns/include/dns/log.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,9 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.h,v 1.33.18.4 2005/09/05 00:18:27 marka Exp $ */ +/* $Id: log.h,v 1.42.332.2 2009/01/18 23:47:41 tbox Exp $ */ -/*! \file +/*! \file dns/log.h * \author Principal Authors: DCL */ #ifndef DNS_LOG_H @@ -41,6 +41,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[]; #define DNS_LOGCATEGORY_DISPATCH (&dns_categories[8]) #define DNS_LOGCATEGORY_LAME_SERVERS (&dns_categories[9]) #define DNS_LOGCATEGORY_DELEGATION_ONLY (&dns_categories[10]) +#define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11]) /* Backwards compatibility. */ #define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL @@ -87,7 +88,7 @@ dns_log_init(isc_log_t *lctx); *\li dns_log_init() is called only once. * * Ensures: - * \li The catgories and modules defined above are available for + * \li The categories and modules defined above are available for * use by isc_log_usechannnel() and isc_log_write(). */ diff --git a/lib/dns/include/dns/lookup.h b/lib/dns/include/dns/lookup.h index aea6f84..0e9a327 100644 --- a/lib/dns/include/dns/lookup.h +++ b/lib/dns/include/dns/lookup.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lookup.h,v 1.6.18.2 2005/04/29 00:16:15 marka Exp $ */ +/* $Id: lookup.h,v 1.12.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_LOOKUP_H #define DNS_LOOKUP_H 1 @@ -24,11 +24,11 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/lookup.h * \brief * The lookup module performs simple DNS lookups. It implements - * the full resolver algorithm, both looking for local data and - * resoving external names as necessary. + * the full resolver algorithm, both looking for local data and + * resolving external names as necessary. * * MP: *\li The module ensures appropriate synchronization of data structures it diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h index 1f94c8c..93a782d 100644 --- a/lib/dns/include/dns/master.h +++ b/lib/dns/include/dns/master.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.h,v 1.38.18.6 2005/06/20 01:19:43 marka Exp $ */ +/* $Id: master.h,v 1.51 2008/04/02 02:37:42 marka Exp $ */ #ifndef DNS_MASTER_H #define DNS_MASTER_H 1 -/*! \file */ +/*! \file dns/master.h */ /*** *** Imports @@ -42,7 +42,7 @@ #define DNS_MASTER_HINT 0x00000010 /*%< Loading a hint master file. */ #define DNS_MASTER_SLAVE 0x00000020 /*%< Loading a slave master file. */ #define DNS_MASTER_CHECKNS 0x00000040 /*%< - * Check NS records to see + * Check NS records to see * if they are an address */ #define DNS_MASTER_FATALNS 0x00000080 /*%< @@ -55,6 +55,8 @@ #define DNS_MASTER_CHECKMX 0x00000800 #define DNS_MASTER_CHECKMXFAIL 0x00001000 +#define DNS_MASTER_RESIGN 0x00002000 + ISC_LANG_BEGINDECLS /* @@ -113,6 +115,17 @@ dns_master_loadfile2(const char *master_file, dns_masterformat_t format); isc_result_t +dns_master_loadfile3(const char *master_file, + dns_name_t *top, + dns_name_t *origin, + dns_rdataclass_t zclass, + unsigned int options, + isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, + isc_mem_t *mctx, + dns_masterformat_t format); + +isc_result_t dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin, @@ -163,6 +176,19 @@ dns_master_loadfileinc2(const char *master_file, dns_masterformat_t format); isc_result_t +dns_master_loadfileinc3(const char *master_file, + dns_name_t *top, + dns_name_t *origin, + dns_rdataclass_t zclass, + unsigned int options, + isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, + isc_task_t *task, + dns_loaddonefunc_t done, void *done_arg, + dns_loadctx_t **ctxp, isc_mem_t *mctx, + dns_masterformat_t format); + +isc_result_t dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin, @@ -212,6 +238,9 @@ dns_master_loadlexerinc(isc_lex_t *lex, * is completed or has failed. If the initial setup fails 'done' is * not called. * + * 'resign' the number of seconds before a RRSIG expires that it should + * be re-signed. 0 is used if not provided. + * * Requires: *\li 'master_file' points to a valid string. *\li 'lexer' points to a valid lexer. diff --git a/lib/dns/include/dns/masterdump.h b/lib/dns/include/dns/masterdump.h index 8cf5c13..42521b3 100644 --- a/lib/dns/include/dns/masterdump.h +++ b/lib/dns/include/dns/masterdump.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.h,v 1.31.14.4 2005/09/01 03:04:28 marka Exp $ */ +/* $Id: masterdump.h,v 1.42 2008/09/24 02:46:23 marka Exp $ */ #ifndef DNS_MASTERDUMP_H #define DNS_MASTERDUMP_H 1 -/*! \file */ +/*! \file dns/masterdump.h */ /*** *** Imports @@ -91,11 +91,14 @@ typedef struct dns_master_style dns_master_style_t; /*% Print negative caching entries. */ #define DNS_STYLEFLAG_NCACHE 0x00800000U -/*% Never print the TTL */ +/*% Never print the TTL. */ #define DNS_STYLEFLAG_NO_TTL 0x01000000U - -/*% Never print the CLASS */ -#define DNS_STYLEFLAG_NO_CLASS 0x02000000U + +/*% Never print the CLASS. */ +#define DNS_STYLEFLAG_NO_CLASS 0x02000000U + +/*% Report re-signing time. */ +#define DNS_STYLEFLAG_RESIGN 0x04000000U ISC_LANG_BEGINDECLS @@ -119,8 +122,8 @@ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_default; LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_full; /*% - * A master file style that prints explicit TTL values on each - * record line, never using $TTL statements. The TTL has a tab + * A master file style that prints explicit TTL values on each + * record line, never using $TTL statements. The TTL has a tab * stop of its own, but the class and type share one. */ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t @@ -133,9 +136,9 @@ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_cache; /*% - * A master style that prints name, ttl, class, type, and value on - * every line. Similar to explicitttl above, but more verbose. - * Intended for generating master files which can be easily parsed + * A master style that prints name, ttl, class, type, and value on + * every line. Similar to explicitttl above, but more verbose. + * Intended for generating master files which can be easily parsed * by perl scripts and similar applications. */ LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_simple; @@ -231,7 +234,7 @@ dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db, *\li 'task' to be valid. *\li 'done' to be non NULL. *\li 'dctxp' to be non NULL && '*dctxp' to be NULL. - * + * * Returns: *\li ISC_R_SUCCESS *\li ISC_R_CONTINUE dns_master_dumptostreaminc() only. @@ -329,6 +332,9 @@ dns_master_stylecreate(dns_master_style_t **style, unsigned int flags, void dns_master_styledestroy(dns_master_style_t **style, isc_mem_t *mctx); +const char * +dns_trust_totext(dns_trust_t trust); + ISC_LANG_ENDDECLS #endif /* DNS_MASTERDUMP_H */ diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 9002b83..f880095 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.h,v 1.114.18.6 2006/03/02 23:19:20 marka Exp $ */ +/* $Id: message.h,v 1.125.118.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_MESSAGE_H #define DNS_MESSAGE_H 1 @@ -33,7 +33,7 @@ #include <dst/dst.h> -/*! \file +/*! \file dns/message.h * \brief Message Handling Module * * How this beast works: @@ -101,8 +101,12 @@ #define DNS_MESSAGEFLAG_AD 0x0020U #define DNS_MESSAGEFLAG_CD 0x0010U +/*%< EDNS0 extended message flags */ #define DNS_MESSAGEEXTFLAG_DO 0x8000U +/*%< EDNS0 extended OPT codes */ +#define DNS_OPT_NSID 0x0003 /*%< NSID opt code */ + #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD) #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) @@ -157,7 +161,7 @@ typedef int dns_messagetextflag_t; occurs */ #define DNS_MESSAGEPARSE_CLONEBUFFER 0x0004 /*%< save a copy of the source buffer */ -#define DNS_MESSAGEPARSE_IGNORETRUNCATION 0x0008 /*%< trucation errors are +#define DNS_MESSAGEPARSE_IGNORETRUNCATION 0x0008 /*%< truncation errors are * not fatal. */ /* @@ -771,7 +775,7 @@ dns_message_addname(dns_message_t *msg, dns_name_t *name, void dns_message_removename(dns_message_t *msg, dns_name_t *name, - dns_section_t section); + dns_section_t section); /*%< * Remove a existing name from a given section. * @@ -1031,7 +1035,7 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt); *\li The OPT record has either been freed or ownership of it has * been transferred to the message. * - *\li If ISC_R_SUCCESS was returned, the OPT record will be rendered + *\li If ISC_R_SUCCESS was returned, the OPT record will be rendered * when dns_message_renderend() is called. * * Returns: @@ -1195,7 +1199,7 @@ dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer); *\li msg be a valid message. * *\li buffer != NULL && *buffer is a valid isc_buffer_t, which was - * dynamincally allocated via isc_buffer_allocate(). + * dynamically allocated via isc_buffer_allocate(). */ isc_result_t @@ -1315,7 +1319,7 @@ dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, *\li order_arg is NULL if and only if order is NULL. */ -void +void dns_message_settimeadjust(dns_message_t *msg, int timeadjust); /*%< * Adjust the time used to sign/verify a message by timeadjust. @@ -1325,7 +1329,7 @@ dns_message_settimeadjust(dns_message_t *msg, int timeadjust); *\li msg be a valid message. */ -int +int dns_message_gettimeadjust(dns_message_t *msg); /*%< * Return the current time adjustment. diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index 038ae05..0149301 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.h,v 1.107.18.15 2006/03/02 00:37:21 marka Exp $ */ +/* $Id: name.h,v 1.126.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_NAME_H #define DNS_NAME_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/name.h * \brief * Provides facilities for manipulating DNS names and labels, including * conversions to and from wire format and text format. @@ -131,6 +131,7 @@ struct dns_name { #define DNS_NAMEATTR_READONLY 0x0002 #define DNS_NAMEATTR_DYNAMIC 0x0004 #define DNS_NAMEATTR_DYNOFFSETS 0x0008 +#define DNS_NAMEATTR_NOCOMPRESS 0x0010 /* * Attributes below 0x0100 reserved for name.c usage. */ @@ -242,7 +243,7 @@ dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer); * * Notes: * \li Specification of a target buffer in dns_name_fromwire(), - * dns_name_fromtext(), and dns_name_concatentate() is optional if + * dns_name_fromtext(), and dns_name_concatenate() is optional if * 'name' has a dedicated buffer. * * \li The caller must not write to buffer until the name has been @@ -721,7 +722,7 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source, isc_result_t dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, - isc_buffer_t *target); + isc_buffer_t *target); /*%< * Convert 'name' into wire format, compressing it as specified by the * compression context 'cctx', and storing the result in 'target'. @@ -840,7 +841,7 @@ dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot, * name as generated by dns_name_totext(). This does not * include space for a terminating NULL. * - * This definition is conservative - the actual maximum + * This definition is conservative - the actual maximum * is 1004, derived as follows: * * A backslash-decimal escaped character takes 4 bytes. @@ -952,7 +953,7 @@ dns_name_split(dns_name_t *name, unsigned int suffixlabels, * * Notes: * \li 'name' is split such that 'suffix' holds the most significant - * 'suffixlabels' labels. All other labels are stored in 'prefix'. + * 'suffixlabels' labels. All other labels are stored in 'prefix'. * *\li Copying name data is avoided as much as possible, so 'prefix' * and 'suffix' will end up pointing at the data for 'name'. @@ -1082,7 +1083,7 @@ dns_name_dynamic(dns_name_t *name); * * Returns: * - *\li 'ISC_TRUE' if the name is dynamic othewise 'ISC_FALSE'. + *\li 'ISC_TRUE' if the name is dynamic otherwise 'ISC_FALSE'. */ isc_result_t @@ -1185,7 +1186,7 @@ dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard); * Requires: * 'name' to be valid. */ - + isc_boolean_t dns_name_ismailbox(const dns_name_t *name); @@ -1220,7 +1221,7 @@ dns_name_destroy(void); ISC_LANG_ENDDECLS /* - *** High Peformance Macros + *** High Performance Macros ***/ /* diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h index 459effb..a818fe6 100644 --- a/lib/dns/include/dns/ncache.h +++ b/lib/dns/include/dns/ncache.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ncache.h,v 1.17.18.2 2005/04/29 00:16:16 marka Exp $ */ +/* $Id: ncache.h,v 1.25 2008/09/25 04:02:39 tbox Exp $ */ #ifndef DNS_NCACHE_H #define DNS_NCACHE_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/ncache.h *\brief * DNS Ncache * @@ -63,6 +63,11 @@ isc_result_t dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, dns_rdataset_t *addedrdataset); +isc_result_t +dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, + dns_dbnode_t *node, dns_rdatatype_t covers, + isc_stdtime_t now, dns_ttl_t maxttl, + isc_boolean_t optout, dns_rdataset_t *addedrdataset); /*%< * Convert the authority data from 'message' into a negative cache * rdataset, and store it in 'cache' at 'node' with a TTL limited to @@ -71,6 +76,8 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, * The 'covers' argument is the RR type whose nonexistence we are caching, * or dns_rdatatype_any when caching a NXDOMAIN response. * + * 'optout' indicates a DNS_RATASETATTR_OPTOUT should be set. + * * Note: *\li If 'addedrdataset' is not NULL, then it will be attached to the added * rdataset. See dns_db_addrdataset() for more details. @@ -154,6 +161,19 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, * */ +void +dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, + dns_rdataset_t *rdataset); + +/*%< + * Extract the current rdataset and name from a ncache entry. + * + * Requires: + * \li 'ncacherdataset' to be valid and to be a negative cache entry + * \li 'found' to be valid. + * \li 'rdataset' to be unassociated. + */ + ISC_LANG_ENDDECLS #endif /* DNS_NCACHE_H */ diff --git a/lib/dns/include/dns/nsec.h b/lib/dns/include/dns/nsec.h index 46b75fa..335a463 100644 --- a/lib/dns/include/dns/nsec.h +++ b/lib/dns/include/dns/nsec.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec.h,v 1.4.20.2 2005/04/29 00:16:16 marka Exp $ */ +/* $Id: nsec.h,v 1.12 2008/09/25 04:02:39 tbox Exp $ */ #ifndef DNS_NSEC_H #define DNS_NSEC_H 1 -/*! \file */ +/*! \file dns/nsec.h */ #include <isc/lang.h> @@ -64,6 +64,17 @@ dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type); *\li 'nsec' points to a valid rdataset of type NSEC */ +isc_result_t +dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t *answer); +/* + * Report whether the DNSKEY RRset has a NSEC only algorithm. Unknown + * algorithms are assumed to support NSEC3. + * + * Requires: + * 'answer' to be non NULL. + */ + ISC_LANG_ENDDECLS #endif /* DNS_NSEC_H */ diff --git a/lib/dns/include/dns/nsec3.h b/lib/dns/include/dns/nsec3.h new file mode 100644 index 0000000..2d6a8dd --- /dev/null +++ b/lib/dns/include/dns/nsec3.h @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008, 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: nsec3.h,v 1.5.48.2 2009/01/18 23:47:41 tbox Exp $ */ + +#ifndef DNS_NSEC3_H +#define DNS_NSEC3_H 1 + +#include <isc/lang.h> +#include <isc/iterated_hash.h> + +#include <dns/db.h> +#include <dns/diff.h> +#include <dns/name.h> +#include <dns/rdatastruct.h> +#include <dns/types.h> + +/* + * hash = 1, flags =1, iterations = 2, salt length = 1, salt = 255 (max) + * hash length = 1, hash = 255 (max), bitmap = 8192 + 512 (max) + */ +#define DNS_NSEC3_BUFFERSIZE (6 + 255 + 255 + 8192 + 512) +/* + * hash = 1, flags = 1, iterations = 2, salt length = 1, salt = 255 (max) + */ +#define DNS_NSEC3PARAM_BUFFERSIZE (5 + 255) + +/* + * Test "unknown" algorithm. Is mapped to dns_hash_sha1. + */ +#define DNS_NSEC3_UNKNOWNALG 245U + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, + dns_dbnode_t *node, unsigned int hashalg, + unsigned int optin, unsigned int iterations, + const unsigned char *salt, size_t salt_length, + const unsigned char *nexthash, size_t hash_length, + unsigned char *buffer, dns_rdata_t *rdata); +/*%< + * Build the rdata of a NSEC3 record for the data at 'node'. + * Note: 'node' is not the node where the NSEC3 record will be stored. + * + * Requires: + * buffer Points to a temporary buffer of at least + * DNS_NSEC_BUFFERSIZE bytes. + * rdata Points to an initialized dns_rdata_t. + * + * Ensures: + * *rdata Contains a valid NSEC3 rdata. The 'data' member refers + * to 'buffer'. + */ + +isc_boolean_t +dns_nsec3_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type); +/*%< + * Determine if a type is marked as present in an NSEC3 record. + * + * Requires: + * 'nsec' points to a valid rdataset of type NSEC3 + */ + +isc_result_t +dns_nsec3_hashname(dns_fixedname_t *result, + unsigned char rethash[NSEC3_MAX_HASH_LENGTH], + size_t *hash_length, dns_name_t *name, dns_name_t *origin, + dns_hash_t hashalg, unsigned int iterations, + const unsigned char *salt, size_t saltlength); +/*%< + * Make a hashed domain name from an unhashed one. If rethash is not NULL + * the raw hash is stored there. + */ + +unsigned int +dns_nsec3_hashlength(dns_hash_t hash); +/*%< + * Return the length of the hash produced by the specified algorithm + * or zero when unknown. + */ + +isc_boolean_t +dns_nsec3_supportedhash(dns_hash_t hash); +/*%< + * Return whether we support this hash algorithm or not. + */ + +isc_result_t +dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, const dns_rdata_nsec3param_t *nsec3param, + dns_ttl_t nsecttl, isc_boolean_t unsecure, dns_diff_t *diff); + +isc_result_t +dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, dns_ttl_t nsecttl, + isc_boolean_t unsecure, dns_diff_t *diff); +/*%< + * Add NSEC3 records for 'name', recording the change in 'diff'. + * Adjust previous NSEC3 records, if any, to reflect the addition. + * The existing NSEC3 records are removed. + * + * dns_nsec3_addnsec3() will only add records to the chain identified by + * 'nsec3param'. + * + * 'unsecure' should be set to reflect if this is a potentially + * unsecure delegation (no DS record). + * + * dns_nsec3_addnsec3s() will examine the NSEC3PARAM RRset to determine which + * chains to be updated. NSEC3PARAM records with the DNS_NSEC3FLAG_CREATE + * will be preferentially chosen over NSEC3PARAM records without + * DNS_NSEC3FLAG_CREATE set. NSEC3PARAM records with DNS_NSEC3FLAG_REMOVE + * set will be ignored by dns_nsec3_addnsec3s(). If DNS_NSEC3FLAG_CREATE + * is set then the new NSEC3 will have OPTOUT set to match the that in the + * NSEC3PARAM record otherwise OPTOUT will be inherited from the previous + * record in the chain. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'name' to be valid. + * 'nsec3param' to be valid. + * 'diff' to be valid. + */ + +isc_result_t +dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff); + +isc_result_t +dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_diff_t *diff); +/*%< + * Remove NSEC3 records for 'name', recording the change in 'diff'. + * Adjust previous NSEC3 records, if any, to reflect the removal. + * + * dns_nsec3_delnsec3() performs the above for the chain identified by + * 'nsec3param'. + * + * dns_nsec3_delnsec3s() examines the NSEC3PARAM RRset in a similar manner + * to dns_nsec3_addnsec3s(). Unlike dns_nsec3_addnsec3s() updated NSEC3 + * records have the OPTOUT flag preserved. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'name' to be valid. + * 'nsec3param' to be valid. + * 'diff' to be valid. + */ + +isc_result_t +dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t complete, isc_boolean_t *answer); +/*%< + * Check if there are any complete/to be built NSEC3 chains. + * If 'complete' is ISC_TRUE only complete chains will be recognized. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'answer' to be non NULL. + */ + +isc_result_t +dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version, + isc_mem_t *mctx, unsigned int *iterationsp); +/*%< + * Find the maximum permissible number of iterations allowed based on + * the key strength. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'mctx' to be valid. + * 'iterationsp' to be non NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_NSEC3_H */ diff --git a/lib/dns/include/dns/opcode.h b/lib/dns/include/dns/opcode.h index 4796dba..368b2b2 100644 --- a/lib/dns/include/dns/opcode.h +++ b/lib/dns/include/dns/opcode.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: opcode.h,v 1.2.18.2 2005/04/29 00:16:16 marka Exp $ */ +/* $Id: opcode.h,v 1.8 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_OPCODE_H #define DNS_OPCODE_H 1 -/*! \file */ +/*! \file dns/opcode.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/order.h b/lib/dns/include/dns/order.h index 6458db0..85663c3 100644 --- a/lib/dns/include/dns/order.h +++ b/lib/dns/include/dns/order.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: order.h,v 1.3.18.2 2005/04/29 00:16:17 marka Exp $ */ +/* $Id: order.h,v 1.9 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_ORDER_H #define DNS_ORDER_H 1 -/*! \file */ +/*! \file dns/order.h */ #include <isc/lang.h> #include <isc/types.h> diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h index be5a8c3..9e7a188 100644 --- a/lib/dns/include/dns/peer.h +++ b/lib/dns/include/dns/peer.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: peer.h,v 1.20.18.8 2006/02/28 03:10:48 marka Exp $ */ +/* $Id: peer.h,v 1.33.118.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_PEER_H #define DNS_PEER_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/peer.h * \brief * Data structures for peers (e.g. a 'server' config file statement) */ @@ -73,11 +73,12 @@ struct dns_peer { isc_boolean_t provide_ixfr; isc_boolean_t request_ixfr; isc_boolean_t support_edns; + isc_boolean_t request_nsid; dns_name_t *key; isc_sockaddr_t *transfer_source; - isc_sockaddr_t *notify_source; - isc_sockaddr_t *query_source; - isc_uint16_t udpsize; /* recieve size */ + isc_sockaddr_t *notify_source; + isc_sockaddr_t *query_source; + isc_uint16_t udpsize; /* receive size */ isc_uint16_t maxudp; /* transmit size */ isc_uint32_t bitflags; @@ -150,6 +151,12 @@ isc_result_t dns_peer_getprovideixfr(dns_peer_t *peer, isc_boolean_t *retval); isc_result_t +dns_peer_setrequestnsid(dns_peer_t *peer, isc_boolean_t newval); + +isc_result_t +dns_peer_getrequestnsid(dns_peer_t *peer, isc_boolean_t *retval); + +isc_result_t dns_peer_setsupportedns(dns_peer_t *peer, isc_boolean_t newval); isc_result_t diff --git a/lib/dns/include/dns/portlist.h b/lib/dns/include/dns/portlist.h index 2d400d4..f76731a 100644 --- a/lib/dns/include/dns/portlist.h +++ b/lib/dns/include/dns/portlist.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,9 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: portlist.h,v 1.3.18.2 2005/04/29 00:16:17 marka Exp $ */ +/* $Id: portlist.h,v 1.9 2007/06/19 23:47:17 tbox Exp $ */ -/*! \file */ +/*! \file dns/portlist.h */ #include <isc/lang.h> #include <isc/net.h> diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h index a1edf0c..6eea787 100644 --- a/lib/dns/include/dns/rbt.h +++ b/lib/dns/include/dns/rbt.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbt.h,v 1.59.18.5 2005/10/13 01:26:07 marka Exp $ */ +/* $Id: rbt.h,v 1.71.48.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_RBT_H #define DNS_RBT_H 1 -/*! \file */ +/*! \file dns/rbt.h */ #include <isc/lang.h> #include <isc/magic.h> @@ -37,10 +37,10 @@ ISC_LANG_BEGINDECLS * Option values for dns_rbt_findnode() and dns_rbt_findname(). * These are used to form a bitmask. */ -#define DNS_RBTFIND_NOOPTIONS 0x00 -#define DNS_RBTFIND_EMPTYDATA 0x01 -#define DNS_RBTFIND_NOEXACT 0x02 -#define DNS_RBTFIND_NOPREDECESSOR 0x04 +#define DNS_RBTFIND_NOOPTIONS 0x00 +#define DNS_RBTFIND_EMPTYDATA 0x01 +#define DNS_RBTFIND_NOEXACT 0x02 +#define DNS_RBTFIND_NOPREDECESSOR 0x04 /*@}*/ #ifndef DNS_RBT_USEISCREFCOUNT @@ -52,14 +52,14 @@ ISC_LANG_BEGINDECLS /* * These should add up to 30. */ -#define DNS_RBT_LOCKLENGTH 10 -#define DNS_RBT_REFLENGTH 20 +#define DNS_RBT_LOCKLENGTH 10 +#define DNS_RBT_REFLENGTH 20 -#define DNS_RBTNODE_MAGIC ISC_MAGIC('R','B','N','O') +#define DNS_RBTNODE_MAGIC ISC_MAGIC('R','B','N','O') #if DNS_RBT_USEMAGIC -#define DNS_RBTNODE_VALID(n) ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC) +#define DNS_RBTNODE_VALID(n) ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC) #else -#define DNS_RBTNODE_VALID(n) ISC_TRUE +#define DNS_RBTNODE_VALID(n) ISC_TRUE #endif /*% @@ -69,22 +69,31 @@ ISC_LANG_BEGINDECLS * appended to this structure. Allocating a contiguous block of memory for * multiple dns_rbtnode structures will not work. */ -typedef struct dns_rbtnode { +typedef struct dns_rbtnode dns_rbtnode_t; +struct dns_rbtnode { #if DNS_RBT_USEMAGIC unsigned int magic; #endif - struct dns_rbtnode *parent; - struct dns_rbtnode *left; - struct dns_rbtnode *right; - struct dns_rbtnode *down; + dns_rbtnode_t *parent; + dns_rbtnode_t *left; + dns_rbtnode_t *right; + dns_rbtnode_t *down; #ifdef DNS_RBT_USEHASH - struct dns_rbtnode *hashnext; + dns_rbtnode_t *hashnext; #endif + + /*% + * Used for LRU cache. This linked list is used to mark nodes which + * have no data any longer, but we cannot unlink at that exact moment + * because we did not or could not obtain a write lock on the tree. + */ + ISC_LINK(dns_rbtnode_t) deadlink; + /*@{*/ /*! * The following bitfields add up to a total bitwidth of 32. * The range of values necessary for each item is indicated, - * but in the case of "attributes" the field is wider to accomodate + * but in the case of "attributes" the field is wider to accommodate * possible future expansion. "offsetlen" could be one bit * narrower by always adjusting its value by 1 to find the real * offsetlen, but doing so does not gain anything (except perhaps @@ -93,13 +102,14 @@ typedef struct dns_rbtnode { * In each case below the "range" indicated is what's _necessary_ for * the bitfield to hold, not what it actually _can_ hold. */ - unsigned int is_root : 1; /*%< range is 0..1 */ - unsigned int color : 1; /*%< range is 0..1 */ - unsigned int find_callback : 1; /*%< range is 0..1 */ - unsigned int attributes : 4; /*%< range is 0..2 */ - unsigned int namelen : 8; /*%< range is 1..255 */ - unsigned int offsetlen : 8; /*%< range is 1..128 */ - unsigned int padbytes : 9; /*%< range is 0..380 */ + unsigned int is_root : 1; /*%< range is 0..1 */ + unsigned int color : 1; /*%< range is 0..1 */ + unsigned int find_callback : 1; /*%< range is 0..1 */ + unsigned int attributes : 3; /*%< range is 0..2 */ + unsigned int nsec3 : 1; /*%< range is 0..1 */ + unsigned int namelen : 8; /*%< range is 1..255 */ + unsigned int offsetlen : 8; /*%< range is 1..128 */ + unsigned int padbytes : 9; /*%< range is 0..380 */ /*@}*/ #ifdef DNS_RBT_USEHASH @@ -121,14 +131,14 @@ typedef struct dns_rbtnode { isc_refcount_t references; /* note that this is not in the bitfield */ #endif /*@}*/ -} dns_rbtnode_t; +}; typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node, dns_name_t *name, void *callback_arg); /***** - ***** Chain Info + ***** Chain Info *****/ /*! @@ -145,7 +155,7 @@ typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node, * tree when a node is added). The obvious implication of this is that for a * chain to remain valid, the tree has to be locked down against writes for the * duration of the useful life of the chain, because additions or removals can - * change the path from the root to the node the chain has targetted. + * change the path from the root to the node the chain has targeted. * * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take * dns_name_t parameters for the name and the origin, which can be NULL. If @@ -182,15 +192,15 @@ typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node, #define DNS_RBT_LEVELBLOCK 254 typedef struct dns_rbtnodechain { - unsigned int magic; - isc_mem_t * mctx; + unsigned int magic; + isc_mem_t * mctx; /*% * The terminal node of the chain. It is not in levels[]. * This is ostensibly private ... but in a pinch it could be * used tell that the chain points nowhere without needing to * call dns_rbtnodechain_current(). */ - dns_rbtnode_t * end; + dns_rbtnode_t * end; /*% * The maximum number of labels in a name is 128; bitstrings mean * a conceptually very large number (which I have not bothered to @@ -199,7 +209,7 @@ typedef struct dns_rbtnodechain { * labels in a name to 255, meaning only 254 pointers are needed * in the worst case. */ - dns_rbtnode_t * levels[DNS_RBT_LEVELBLOCK]; + dns_rbtnode_t * levels[DNS_RBT_LEVELBLOCK]; /*% * level_count indicates how deep the chain points into the * tree of trees, and is the index into the levels[] array. @@ -208,7 +218,7 @@ typedef struct dns_rbtnodechain { * a level_count of 0, the first level has a level_count of 1, and * so on. */ - unsigned int level_count; + unsigned int level_count; /*% * level_matches tells how many levels matched above the node * returned by dns_rbt_findnode(). A match (partial or exact) found @@ -216,7 +226,7 @@ typedef struct dns_rbtnodechain { * This is used by the rbtdb to set the start point for a recursive * search of superdomains until the RR it is looking for is found. */ - unsigned int level_matches; + unsigned int level_matches; } dns_rbtnodechain_t; /***** @@ -229,27 +239,27 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *), * Initialize a red-black tree of trees. * * Notes: - *\li The deleter argument, if non-null, points to a function that is - * responsible for cleaning up any memory associated with the data - * pointer of a node when the node is deleted. It is passed the - * deleted node's data pointer as its first argument and deleter_arg - * as its second argument. + *\li The deleter argument, if non-null, points to a function that is + * responsible for cleaning up any memory associated with the data + * pointer of a node when the node is deleted. It is passed the + * deleted node's data pointer as its first argument and deleter_arg + * as its second argument. * * Requires: - * \li mctx is a pointer to a valid memory context. - *\li rbtp != NULL && *rbtp == NULL - *\li arg == NULL iff deleter == NULL + * \li mctx is a pointer to a valid memory context. + *\li rbtp != NULL && *rbtp == NULL + *\li arg == NULL iff deleter == NULL * * Ensures: - *\li If result is ISC_R_SUCCESS: - * *rbtp points to a valid red-black tree manager + *\li If result is ISC_R_SUCCESS: + * *rbtp points to a valid red-black tree manager * - *\li If result is failure: - * *rbtp does not point to a valid red-black tree manager. + *\li If result is failure: + * *rbtp does not point to a valid red-black tree manager. * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #ISC_R_NOMEMORY Resource limit: Out of Memory + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of Memory */ isc_result_t @@ -258,38 +268,38 @@ dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data); * Add 'name' to the tree of trees, associated with 'data'. * * Notes: - *\li 'data' is never required to be non-NULL, but specifying it - * when the name is added is faster than searching for 'name' - * again and then setting the data pointer. The lack of a data pointer - * for a node also has other ramifications regarding whether - * dns_rbt_findname considers a node to exist, or dns_rbt_deletename - * joins nodes. + *\li 'data' is never required to be non-NULL, but specifying it + * when the name is added is faster than searching for 'name' + * again and then setting the data pointer. The lack of a data pointer + * for a node also has other ramifications regarding whether + * dns_rbt_findname considers a node to exist, or dns_rbt_deletename + * joins nodes. * * Requires: - *\li rbt is a valid rbt manager. - *\li dns_name_isabsolute(name) == TRUE + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE * * Ensures: - *\li 'name' is not altered in any way. + *\li 'name' is not altered in any way. * - *\li Any external references to nodes in the tree are unaffected by - * node splits that are necessary to insert the new name. + *\li Any external references to nodes in the tree are unaffected by + * node splits that are necessary to insert the new name. * - *\li If result is #ISC_R_SUCCESS: - * 'name' is findable in the red/black tree of trees in O(log N). - * The data pointer of the node for 'name' is set to 'data'. + *\li If result is #ISC_R_SUCCESS: + * 'name' is findable in the red/black tree of trees in O(log N). + * The data pointer of the node for 'name' is set to 'data'. * - *\li If result is #ISC_R_EXISTS or #ISC_R_NOSPACE: - * The tree of trees is unaltered. + *\li If result is #ISC_R_EXISTS or #ISC_R_NOSPACE: + * The tree of trees is unaltered. * - *\li If result is #ISC_R_NOMEMORY: - * No guarantees. + *\li If result is #ISC_R_NOMEMORY: + * No guarantees. * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #ISC_R_EXISTS The name already exists with associated data. - *\li #ISC_R_NOSPACE The name had more logical labels than are allowed. - *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_EXISTS The name already exists with associated data. + *\li #ISC_R_NOSPACE The name had more logical labels than are allowed. + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory */ isc_result_t @@ -299,31 +309,31 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep); * Just like dns_rbt_addname, but returns the address of the node. * * Requires: - *\li rbt is a valid rbt structure. - *\li dns_name_isabsolute(name) == TRUE - *\li nodep != NULL && *nodep == NULL + *\li rbt is a valid rbt structure. + *\li dns_name_isabsolute(name) == TRUE + *\li nodep != NULL && *nodep == NULL * * Ensures: - *\li 'name' is not altered in any way. + *\li 'name' is not altered in any way. * - *\li Any external references to nodes in the tree are unaffected by - * node splits that are necessary to insert the new name. + *\li Any external references to nodes in the tree are unaffected by + * node splits that are necessary to insert the new name. * - *\li If result is ISC_R_SUCCESS: - * 'name' is findable in the red/black tree of trees in O(log N). - * *nodep is the node that was added for 'name'. + *\li If result is ISC_R_SUCCESS: + * 'name' is findable in the red/black tree of trees in O(log N). + * *nodep is the node that was added for 'name'. * - *\li If result is ISC_R_EXISTS: - * The tree of trees is unaltered. - * *nodep is the existing node for 'name'. + *\li If result is ISC_R_EXISTS: + * The tree of trees is unaltered. + * *nodep is the existing node for 'name'. * - *\li If result is ISC_R_NOMEMORY: - * No guarantees. + *\li If result is ISC_R_NOMEMORY: + * No guarantees. * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #ISC_R_EXISTS The name already exists, possibly without data. - *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_EXISTS The name already exists, possibly without data. + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory */ isc_result_t @@ -333,36 +343,36 @@ dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options, * Get the data pointer associated with 'name'. * * Notes: - *\li When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is + *\li When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is * returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is - * an exact match in the tree. + * an exact match in the tree. * *\li A node that has no data is considered not to exist for this function, * unless the #DNS_RBTFIND_EMPTYDATA option is set. * * Requires: - *\li rbt is a valid rbt manager. - *\li dns_name_isabsolute(name) == TRUE - *\li data != NULL && *data == NULL + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE + *\li data != NULL && *data == NULL * * Ensures: - *\li 'name' and the tree are not altered in any way. + *\li 'name' and the tree are not altered in any way. * - *\li If result is ISC_R_SUCCESS: - * *data is the data associated with 'name'. + *\li If result is ISC_R_SUCCESS: + * *data is the data associated with 'name'. * - *\li If result is DNS_R_PARTIALMATCH: - * *data is the data associated with the deepest superdomain - * of 'name' which has data. + *\li If result is DNS_R_PARTIALMATCH: + * *data is the data associated with the deepest superdomain + * of 'name' which has data. * - *\li If result is ISC_R_NOTFOUND: - * Neither the name nor a superdomain was found with data. + *\li If result is ISC_R_NOTFOUND: + * Neither the name nor a superdomain was found with data. * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #DNS_R_PARTIALMATCH Superdomain found with data - *\li #ISC_R_NOTFOUND No match - *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed + *\li #ISC_R_SUCCESS Success + *\li #DNS_R_PARTIALMATCH Superdomain found with data + *\li #ISC_R_NOTFOUND No match + *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed */ isc_result_t @@ -374,100 +384,100 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname, * Find the node for 'name'. * * Notes: - *\li A node that has no data is considered not to exist for this function, - * unless the DNS_RBTFIND_EMPTYDATA option is set. This applies to both - * exact matches and partial matches. - * - *\li If the chain parameter is non-NULL, then the path through the tree - * to the DNSSEC predecessor of the searched for name is maintained, - * unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option - * is used. (For more details on those options, see below.) - * - *\li If there is no predecessor, then the chain will point to nowhere, as - * indicated by chain->end being NULL or dns_rbtnodechain_current - * returning ISC_R_NOTFOUND. Note that in a normal Internet DNS RBT - * there will always be a predecessor for all names except the root - * name, because '.' will exist and '.' is the predecessor of - * everything. But you can certainly construct a trivial tree and a - * search for it that has no predecessor. - * - *\li Within the chain structure, the 'levels' member of the structure holds - * the root node of each level except the first. - * - *\li The 'level_count' of the chain indicates how deep the chain to the - * predecessor name is, as an index into the 'levels[]' array. It does - * not count name elements, per se, but only levels of the tree of trees, - * the distinction arrising because multiple labels from a name can be - * stored on only one level. It is also does not include the level - * that has the node, since that level is not stored in levels[]. - * - *\li The chain's 'level_matches' is not directly related to the predecessor. - * It is the number of levels above the level of the found 'node', - * regardless of whether it was a partial match or exact match. When - * the node is found in the top level tree, or no node is found at all, - * level_matches is 0. - * - *\li When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is + *\li A node that has no data is considered not to exist for this function, + * unless the DNS_RBTFIND_EMPTYDATA option is set. This applies to both + * exact matches and partial matches. + * + *\li If the chain parameter is non-NULL, then the path through the tree + * to the DNSSEC predecessor of the searched for name is maintained, + * unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option + * is used. (For more details on those options, see below.) + * + *\li If there is no predecessor, then the chain will point to nowhere, as + * indicated by chain->end being NULL or dns_rbtnodechain_current + * returning ISC_R_NOTFOUND. Note that in a normal Internet DNS RBT + * there will always be a predecessor for all names except the root + * name, because '.' will exist and '.' is the predecessor of + * everything. But you can certainly construct a trivial tree and a + * search for it that has no predecessor. + * + *\li Within the chain structure, the 'levels' member of the structure holds + * the root node of each level except the first. + * + *\li The 'level_count' of the chain indicates how deep the chain to the + * predecessor name is, as an index into the 'levels[]' array. It does + * not count name elements, per se, but only levels of the tree of trees, + * the distinction arising because multiple labels from a name can be + * stored on only one level. It is also does not include the level + * that has the node, since that level is not stored in levels[]. + * + *\li The chain's 'level_matches' is not directly related to the predecessor. + * It is the number of levels above the level of the found 'node', + * regardless of whether it was a partial match or exact match. When + * the node is found in the top level tree, or no node is found at all, + * level_matches is 0. + * + *\li When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is * returned (also subject to DNS_RBTFIND_EMPTYDATA), even when * there is an exact match in the tree. In this case, the chain - * will not point to the DNSSEC predecessor, but will instead point - * to the exact match, if there was any. Thus the preceding paragraphs - * should have "exact match" substituted for "predecessor" to describe - * how the various elements of the chain are set. This was done to - * ensure that the chain's state was sane, and to prevent problems that - * occurred when running the predecessor location code under conditions - * it was not designed for. It is not clear *where* the chain should - * point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain - * with this option because you want a particular node, let us know - * where you want the chain pointed, so this can be made more firm. + * will not point to the DNSSEC predecessor, but will instead point + * to the exact match, if there was any. Thus the preceding paragraphs + * should have "exact match" substituted for "predecessor" to describe + * how the various elements of the chain are set. This was done to + * ensure that the chain's state was sane, and to prevent problems that + * occurred when running the predecessor location code under conditions + * it was not designed for. It is not clear *where* the chain should + * point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain + * with this option because you want a particular node, let us know + * where you want the chain pointed, so this can be made more firm. * * Requires: - *\li rbt is a valid rbt manager. - *\li dns_name_isabsolute(name) == TRUE. - *\li node != NULL && *node == NULL. - *\li #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutally - * exclusive. + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE. + *\li node != NULL && *node == NULL. + *\li #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutually + * exclusive. * * Ensures: - *\li 'name' and the tree are not altered in any way. + *\li 'name' and the tree are not altered in any way. * - *\li If result is ISC_R_SUCCESS: + *\li If result is ISC_R_SUCCESS: *\verbatim - * *node is the terminal node for 'name'. + * *node is the terminal node for 'name'. - * 'foundname' and 'name' represent the same name (though not - * the same memory). + * 'foundname' and 'name' represent the same name (though not + * the same memory). - * 'chain' points to the DNSSEC predecessor, if any, of 'name'. + * 'chain' points to the DNSSEC predecessor, if any, of 'name'. * - * chain->level_matches and chain->level_count are equal. + * chain->level_matches and chain->level_count are equal. *\endverbatim * - * If result is DNS_R_PARTIALMATCH: + * If result is DNS_R_PARTIALMATCH: *\verbatim - * *node is the data associated with the deepest superdomain - * of 'name' which has data. + * *node is the data associated with the deepest superdomain + * of 'name' which has data. * - * 'foundname' is the name of deepest superdomain (which has - * data, unless the DNS_RBTFIND_EMPTYDATA option is set). + * 'foundname' is the name of deepest superdomain (which has + * data, unless the DNS_RBTFIND_EMPTYDATA option is set). * - * 'chain' points to the DNSSEC predecessor, if any, of 'name'. + * 'chain' points to the DNSSEC predecessor, if any, of 'name'. *\endverbatim * - *\li If result is ISC_R_NOTFOUND: + *\li If result is ISC_R_NOTFOUND: *\verbatim - * Neither the name nor a superdomain was found. *node is NULL. + * Neither the name nor a superdomain was found. *node is NULL. * - * 'chain' points to the DNSSEC predecessor, if any, of 'name'. + * 'chain' points to the DNSSEC predecessor, if any, of 'name'. * - * chain->level_matches is 0. + * chain->level_matches is 0. *\endverbatim * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #DNS_R_PARTIALMATCH Superdomain found with data - *\li #ISC_R_NOTFOUND No match, or superdomain with no data - *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed + *\li #ISC_R_SUCCESS Success + *\li #DNS_R_PARTIALMATCH Superdomain found with data + *\li #ISC_R_NOTFOUND No match, or superdomain with no data + *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed */ isc_result_t @@ -476,41 +486,41 @@ dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse); * Delete 'name' from the tree of trees. * * Notes: - *\li When 'name' is removed, if recurse is ISC_TRUE then all of its + *\li When 'name' is removed, if recurse is ISC_TRUE then all of its * subnames are removed too. * * Requires: - *\li rbt is a valid rbt manager. - *\li dns_name_isabsolute(name) == TRUE + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE * * Ensures: - *\li 'name' is not altered in any way. + *\li 'name' is not altered in any way. * - *\li Does NOT ensure that any external references to nodes in the tree - * are unaffected by node joins. + *\li Does NOT ensure that any external references to nodes in the tree + * are unaffected by node joins. * - *\li If result is ISC_R_SUCCESS: - * 'name' does not appear in the tree with data; however, - * the node for the name might still exist which can be - * found with dns_rbt_findnode (but not dns_rbt_findname). + *\li If result is ISC_R_SUCCESS: + * 'name' does not appear in the tree with data; however, + * the node for the name might still exist which can be + * found with dns_rbt_findnode (but not dns_rbt_findname). * - *\li If result is ISC_R_NOTFOUND: - * 'name' does not appear in the tree with data, because - * it did not appear in the tree before the function was called. + *\li If result is ISC_R_NOTFOUND: + * 'name' does not appear in the tree with data, because + * it did not appear in the tree before the function was called. * - *\li If result is something else: - * See result codes for dns_rbt_findnode (if it fails, the - * node is not deleted) or dns_rbt_deletenode (if it fails, - * the node is deleted, but the tree is not optimized when - * it could have been). + *\li If result is something else: + * See result codes for dns_rbt_findnode (if it fails, the + * node is not deleted) or dns_rbt_deletenode (if it fails, + * the node is deleted, but the tree is not optimized when + * it could have been). * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #ISC_R_NOTFOUND No match - *\li something_else Any return code from dns_rbt_findnode except - * DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND - * to be returned instead), and any code from - * dns_rbt_deletenode. + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOTFOUND No match + *\li something_else Any return code from dns_rbt_findnode except + * DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND + * to be returned instead), and any code from + * dns_rbt_deletenode. */ isc_result_t @@ -519,32 +529,32 @@ dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse); * Delete 'node' from the tree of trees. * * Notes: - *\li When 'node' is removed, if recurse is ISC_TRUE then all nodes - * in levels down from it are removed too. + *\li When 'node' is removed, if recurse is ISC_TRUE then all nodes + * in levels down from it are removed too. * * Requires: - *\li rbt is a valid rbt manager. - *\li node != NULL. + *\li rbt is a valid rbt manager. + *\li node != NULL. * * Ensures: - *\li Does NOT ensure that any external references to nodes in the tree - * are unaffected by node joins. + *\li Does NOT ensure that any external references to nodes in the tree + * are unaffected by node joins. * - *\li If result is ISC_R_SUCCESS: - * 'node' does not appear in the tree with data; however, - * the node might still exist if it serves as a pointer to - * a lower tree level as long as 'recurse' was false, hence - * the node could can be found with dns_rbt_findnode whem - * that function's empty_data_ok parameter is true. + *\li If result is ISC_R_SUCCESS: + * 'node' does not appear in the tree with data; however, + * the node might still exist if it serves as a pointer to + * a lower tree level as long as 'recurse' was false, hence + * the node could can be found with dns_rbt_findnode when + * that function's empty_data_ok parameter is true. * - *\li If result is ISC_R_NOMEMORY or ISC_R_NOSPACE: - * The node was deleted, but the tree structure was not - * optimized. + *\li If result is ISC_R_NOMEMORY or ISC_R_NOSPACE: + * The node was deleted, but the tree structure was not + * optimized. * * Returns: - *\li #ISC_R_SUCCESS Success - *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes. - *\li #ISC_R_NOSPACE dns_name_concatenate failed when joining nodes. + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes. + *\li #ISC_R_NOSPACE dns_name_concatenate failed when joining nodes. */ void @@ -553,24 +563,24 @@ dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name); * Convert the sequence of labels stored at 'node' into a 'name'. * * Notes: - *\li This function does not return the full name, from the root, but - * just the labels at the indicated node. + *\li This function does not return the full name, from the root, but + * just the labels at the indicated node. * - *\li The name data pointed to by 'name' is the information stored - * in the node, not a copy. Altering the data at this pointer - * will likely cause grief. + *\li The name data pointed to by 'name' is the information stored + * in the node, not a copy. Altering the data at this pointer + * will likely cause grief. * * Requires: - * \li name->offsets == NULL + * \li name->offsets == NULL * * Ensures: - * \li 'name' is DNS_NAMEATTR_READONLY. + * \li 'name' is DNS_NAMEATTR_READONLY. * - * \li 'name' will point directly to the labels stored after the - * dns_rbtnode_t struct. + * \li 'name' will point directly to the labels stored after the + * dns_rbtnode_t struct. * - * \li 'name' will have offsets that also point to the information stored - * as part of the node. + * \li 'name' will have offsets that also point to the information stored + * as part of the node. */ isc_result_t @@ -579,18 +589,18 @@ dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name); * Like dns_rbt_namefromnode, but returns the full name from the root. * * Notes: - * \li Unlike dns_rbt_namefromnode, the name will not point directly - * to node data. Rather, dns_name_concatenate will be used to copy - * the name data from each node into the 'name' argument. + * \li Unlike dns_rbt_namefromnode, the name will not point directly + * to node data. Rather, dns_name_concatenate will be used to copy + * the name data from each node into the 'name' argument. * * Requires: - * \li name != NULL - * \li name has a dedicated buffer. + * \li name != NULL + * \li name has a dedicated buffer. * * Returns: - * \li ISC_R_SUCCESS - * \li ISC_R_NOSPACE (possible via dns_name_concatenate) - * \li DNS_R_NAMETOOLONG (possible via dns_name_concatenate) + * \li ISC_R_SUCCESS + * \li ISC_R_NOSPACE (possible via dns_name_concatenate) + * \li DNS_R_NAMETOOLONG (possible via dns_name_concatenate) */ char * @@ -600,14 +610,14 @@ dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, * Format the full name of a node for printing, using dns_name_format(). * * Notes: - * \li 'size' is the length of the printname buffer. This should be - * DNS_NAME_FORMATSIZE or larger. + * \li 'size' is the length of the printname buffer. This should be + * DNS_NAME_FORMATSIZE or larger. * * Requires: - * \li node and printname are not NULL. + * \li node and printname are not NULL. * * Returns: - * \li The 'printname' pointer. + * \li The 'printname' pointer. */ unsigned int @@ -616,7 +626,7 @@ dns_rbt_nodecount(dns_rbt_t *rbt); * Obtain the number of nodes in the tree of trees. * * Requires: - * \li rbt is a valid rbt manager. + * \li rbt is a valid rbt manager. */ void @@ -624,25 +634,25 @@ dns_rbt_destroy(dns_rbt_t **rbtp); isc_result_t dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum); /*%< - * Stop working with a red-black tree of trees. + * Stop working with a red-black tree of trees. * If 'quantum' is zero then the entire tree will be destroyed. * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed * allowing the rbt to be incrementally destroyed by repeated calls to * dns_rbt_destroy2(). Once dns_rbt_destroy2() has been called no other * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be * performed on the tree of trees. - * + * * Requires: - * \li *rbt is a valid rbt manager. + * \li *rbt is a valid rbt manager. * * Ensures on ISC_R_SUCCESS: - * \li All space allocated by the RBT library has been returned. + * \li All space allocated by the RBT library has been returned. * - * \li *rbt is invalidated as an rbt manager. + * \li *rbt is invalidated as an rbt manager. * * Returns: - * \li ISC_R_SUCCESS - * \li ISC_R_QUOTA if 'quantum' nodes have been destroyed. + * \li ISC_R_SUCCESS + * \li ISC_R_QUOTA if 'quantum' nodes have been destroyed. */ void @@ -652,10 +662,10 @@ dns_rbt_printall(dns_rbt_t *rbt); * tree of trees. * * Notes: - * \li The name stored at each node, along with the node's color, is printed. - * Then the down pointer, left and right pointers are displayed - * recursively in turn. NULL down pointers are silently omitted; - * NULL left and right pointers are printed. + * \li The name stored at each node, along with the node's color, is printed. + * Then the down pointer, left and right pointers are displayed + * recursively in turn. NULL down pointers are silently omitted; + * NULL left and right pointers are printed. */ /***** @@ -668,12 +678,12 @@ dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx); * Initialize 'chain'. * * Requires: - *\li 'chain' is a valid pointer. + *\li 'chain' is a valid pointer. * - *\li 'mctx' is a valid memory context. + *\li 'mctx' is a valid memory context. * * Ensures: - *\li 'chain' is suitable for use. + *\li 'chain' is suitable for use. */ void @@ -683,10 +693,10 @@ dns_rbtnodechain_reset(dns_rbtnodechain_t *chain); * 'chain'. * * Requires: - *\li 'chain' is a valid pointer. + *\li 'chain' is a valid pointer. * * Ensures: - *\li 'chain' is suitable for use, and uses no dynamic storage. + *\li 'chain' is suitable for use, and uses no dynamic storage. */ void @@ -695,15 +705,15 @@ dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain); * Free any dynamic storage associated with 'chain', and then invalidates it. * * Notes: - *\li Future calls to any dns_rbtnodechain_ function will need to call - * dns_rbtnodechain_init on the chain first (except, of course, - * dns_rbtnodechain_init itself). + *\li Future calls to any dns_rbtnodechain_ function will need to call + * dns_rbtnodechain_init on the chain first (except, of course, + * dns_rbtnodechain_init itself). * * Requires: - *\li 'chain' is a valid chain. + *\li 'chain' is a valid chain. * * Ensures: - *\li 'chain' is no longer suitable for use, and uses no dynamic storage. + *\li 'chain' is no longer suitable for use, and uses no dynamic storage. */ isc_result_t @@ -713,37 +723,37 @@ dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name, * Provide the name, origin and node to which the chain is currently pointed. * * Notes: - *\li The tree need not have be locked against additions for the chain - * to remain valid, however there are no guarantees if any deletion - * has been made since the chain was established. + *\li The tree need not have be locked against additions for the chain + * to remain valid, however there are no guarantees if any deletion + * has been made since the chain was established. * * Requires: - *\li 'chain' is a valid chain. + *\li 'chain' is a valid chain. * * Ensures: - *\li 'node', if non-NULL, is the node to which the chain was pointed - * by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last. - * If none were called for the chain since it was initialized or reset, - * or if the was no predecessor to the name searched for with - * dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned. + *\li 'node', if non-NULL, is the node to which the chain was pointed + * by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last. + * If none were called for the chain since it was initialized or reset, + * or if the was no predecessor to the name searched for with + * dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned. * - *\li 'name', if non-NULL, is the name stored at the terminal level of - * the chain. This is typically a single label, like the "www" of - * "www.isc.org", but need not be so. At the root of the tree of trees, - * if the node is "." then 'name' is ".", otherwise it is relative to ".". - * (Minimalist and atypical case: if the tree has just the name - * "isc.org." then the root node's stored name is "isc.org." but 'name' - * will be "isc.org".) + *\li 'name', if non-NULL, is the name stored at the terminal level of + * the chain. This is typically a single label, like the "www" of + * "www.isc.org", but need not be so. At the root of the tree of trees, + * if the node is "." then 'name' is ".", otherwise it is relative to ".". + * (Minimalist and atypical case: if the tree has just the name + * "isc.org." then the root node's stored name is "isc.org." but 'name' + * will be "isc.org".) * - *\li 'origin', if non-NULL, is the sequence of labels in the levels - * above the terminal level, such as "isc.org." in the above example. - * 'origin' is always "." for the root node. + *\li 'origin', if non-NULL, is the sequence of labels in the levels + * above the terminal level, such as "isc.org." in the above example. + * 'origin' is always "." for the root node. * * * Returns: - *\li #ISC_R_SUCCESS name, origin & node were successfully set. - *\li #ISC_R_NOTFOUND The chain does not point to any node. - *\li <something_else> Any error return from dns_name_concatenate. + *\li #ISC_R_SUCCESS name, origin & node were successfully set. + *\li #ISC_R_NOTFOUND The chain does not point to any node. + *\li <something_else> Any error return from dns_name_concatenate. */ isc_result_t @@ -753,23 +763,23 @@ dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, * Set the chain to the lexically first node in the tree of trees. * * Notes: - *\li By the definition of ordering for DNS names, the root of the tree of - * trees is the very first node, since everything else in the megatree - * uses it as a common suffix. + *\li By the definition of ordering for DNS names, the root of the tree of + * trees is the very first node, since everything else in the megatree + * uses it as a common suffix. * * Requires: - *\li 'chain' is a valid chain. - *\li 'rbt' is a valid rbt manager. + *\li 'chain' is a valid chain. + *\li 'rbt' is a valid rbt manager. * * Ensures: - *\li The chain points to the very first node of the tree. + *\li The chain points to the very first node of the tree. * - *\li 'name' and 'origin', if non-NULL, are set as described for - * dns_rbtnodechain_current. Thus 'origin' will always be ".". + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. Thus 'origin' will always be ".". * * Returns: - *\li #DNS_R_NEWORIGIN The name & origin were successfully set. - *\li <something_else> Any error result from dns_rbtnodechain_current. + *\li #DNS_R_NEWORIGIN The name & origin were successfully set. + *\li <something_else> Any error result from dns_rbtnodechain_current. */ isc_result_t @@ -779,19 +789,19 @@ dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, * Set the chain to the lexically last node in the tree of trees. * * Requires: - *\li 'chain' is a valid chain. - *\li 'rbt' is a valid rbt manager. + *\li 'chain' is a valid chain. + *\li 'rbt' is a valid rbt manager. * * Ensures: - *\li The chain points to the very last node of the tree. + *\li The chain points to the very last node of the tree. * - *\li 'name' and 'origin', if non-NULL, are set as described for - * dns_rbtnodechain_current. + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. * * Returns: - *\li #DNS_R_NEWORIGIN The name & origin were successfully set. - *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory building chain. - *\li <something_else> Any error result from dns_name_concatenate. + *\li #DNS_R_NEWORIGIN The name & origin were successfully set. + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory building chain. + *\li <something_else> Any error result from dns_name_concatenate. */ isc_result_t @@ -802,26 +812,26 @@ dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name, * is currently pointed. * * Requires: - *\li 'chain' is a valid chain. - *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, - * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that - * dns_rbt_findnode is not guaranteed to point the chain somewhere, - * since there may have been no predecessor to the searched for name. + *\li 'chain' is a valid chain. + *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, + * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that + * dns_rbt_findnode is not guaranteed to point the chain somewhere, + * since there may have been no predecessor to the searched for name. * * Ensures: - *\li The chain is pointed to the predecessor of its current target. + *\li The chain is pointed to the predecessor of its current target. * - *\li 'name' and 'origin', if non-NULL, are set as described for - * dns_rbtnodechain_current. + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. * - *\li 'origin' is only if a new origin was found. + *\li 'origin' is only if a new origin was found. * * Returns: - *\li #ISC_R_SUCCESS The predecessor was found and 'name' was set. - *\li #DNS_R_NEWORIGIN The predecessor was found with a different - * origin and 'name' and 'origin' were set. - *\li #ISC_R_NOMORE There was no predecessor. - *\li <something_else> Any error result from dns_rbtnodechain_current. + *\li #ISC_R_SUCCESS The predecessor was found and 'name' was set. + *\li #DNS_R_NEWORIGIN The predecessor was found with a different + * origin and 'name' and 'origin' were set. + *\li #ISC_R_NOMORE There was no predecessor. + *\li <something_else> Any error result from dns_rbtnodechain_current. */ isc_result_t @@ -832,26 +842,39 @@ dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, * is currently pointed. * * Requires: - *\li 'chain' is a valid chain. - *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, - * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that - * dns_rbt_findnode is not guaranteed to point the chain somewhere, - * since there may have been no predecessor to the searched for name. + *\li 'chain' is a valid chain. + *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, + * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that + * dns_rbt_findnode is not guaranteed to point the chain somewhere, + * since there may have been no predecessor to the searched for name. * * Ensures: - *\li The chain is pointed to the successor of its current target. + *\li The chain is pointed to the successor of its current target. * - *\li 'name' and 'origin', if non-NULL, are set as described for - * dns_rbtnodechain_current. + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. * - *\li 'origin' is only if a new origin was found. + *\li 'origin' is only if a new origin was found. * * Returns: - *\li #ISC_R_SUCCESS The successor was found and 'name' was set. - *\li #DNS_R_NEWORIGIN The successor was found with a different - * origin and 'name' and 'origin' were set. - *\li #ISC_R_NOMORE There was no successor. - *\li <something_else> Any error result from dns_name_concatenate. + *\li #ISC_R_SUCCESS The successor was found and 'name' was set. + *\li #DNS_R_NEWORIGIN The successor was found with a different + * origin and 'name' and 'origin' were set. + *\li #ISC_R_NOMORE There was no successor. + *\li <something_else> Any error result from dns_name_concatenate. + */ + +isc_result_t +dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin); +/*%< + * Descend down if possible. + */ + +isc_result_t +dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name); +/*%< + * Find the next node at the current depth in DNSSEC order. */ /* @@ -862,53 +885,53 @@ dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, * hiding the back-end. The usage is the same as that of isc_refcount_xxx(). */ #ifdef DNS_RBT_USEISCREFCOUNT -#define dns_rbtnode_refinit(node, n) \ - do { \ - isc_refcount_init(&(node)->references, (n)); \ - } while (0) -#define dns_rbtnode_refdestroy(node) \ - do { \ - isc_refcount_destroy(&(node)->references); \ - } while (0) -#define dns_rbtnode_refcurrent(node) \ +#define dns_rbtnode_refinit(node, n) \ + do { \ + isc_refcount_init(&(node)->references, (n)); \ + } while (0) +#define dns_rbtnode_refdestroy(node) \ + do { \ + isc_refcount_destroy(&(node)->references); \ + } while (0) +#define dns_rbtnode_refcurrent(node) \ isc_refcount_current(&(node)->references) -#define dns_rbtnode_refincrement0(node, refs) \ - do { \ +#define dns_rbtnode_refincrement0(node, refs) \ + do { \ isc_refcount_increment0(&(node)->references, (refs)); \ - } while (0) -#define dns_rbtnode_refincrement(node, refs) \ - do { \ + } while (0) +#define dns_rbtnode_refincrement(node, refs) \ + do { \ isc_refcount_increment(&(node)->references, (refs)); \ - } while (0) -#define dns_rbtnode_refdecrement(node, refs) \ - do { \ + } while (0) +#define dns_rbtnode_refdecrement(node, refs) \ + do { \ isc_refcount_decrement(&(node)->references, (refs)); \ - } while (0) + } while (0) #else /* DNS_RBT_USEISCREFCOUNT */ -#define dns_rbtnode_refinit(node, n) ((node)->references = (n)) -#define dns_rbtnode_refdestroy(node) (REQUIRE((node)->references == 0)) -#define dns_rbtnode_refcurrent(node) ((node)->references) -#define dns_rbtnode_refincrement0(node, refs) \ - do { \ - unsigned int *_tmp = (unsigned int *)(refs); \ - (node)->references++; \ - if ((_tmp) != NULL) \ - (*_tmp) = (node)->references; \ - } while (0) -#define dns_rbtnode_refincrement(node, refs) \ - do { \ - REQUIRE((node)->references > 0); \ - (node)->references++; \ - if ((refs) != NULL) \ - (*refs) = (node)->references; \ - } while (0) -#define dns_rbtnode_refdecrement(node, refs) \ - do { \ - REQUIRE((node)->references > 0); \ - (node)->references--; \ - if ((refs) != NULL) \ - (*refs) = (node)->references; \ - } while (0) +#define dns_rbtnode_refinit(node, n) ((node)->references = (n)) +#define dns_rbtnode_refdestroy(node) (REQUIRE((node)->references == 0)) +#define dns_rbtnode_refcurrent(node) ((node)->references) +#define dns_rbtnode_refincrement0(node, refs) \ + do { \ + unsigned int *_tmp = (unsigned int *)(refs); \ + (node)->references++; \ + if ((_tmp) != NULL) \ + (*_tmp) = (node)->references; \ + } while (0) +#define dns_rbtnode_refincrement(node, refs) \ + do { \ + REQUIRE((node)->references > 0); \ + (node)->references++; \ + if ((refs) != NULL) \ + (*refs) = (node)->references; \ + } while (0) +#define dns_rbtnode_refdecrement(node, refs) \ + do { \ + REQUIRE((node)->references > 0); \ + (node)->references--; \ + if ((refs) != NULL) \ + (*refs) = (node)->references; \ + } while (0) #endif /* DNS_RBT_USEISCREFCOUNT */ ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/rcode.h b/lib/dns/include/dns/rcode.h index 03c145b..94e831b 100644 --- a/lib/dns/include/dns/rcode.h +++ b/lib/dns/include/dns/rcode.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rcode.h,v 1.13.18.2 2005/04/29 00:16:18 marka Exp $ */ +/* $Id: rcode.h,v 1.21 2008/09/25 04:02:39 tbox Exp $ */ #ifndef DNS_RCODE_H #define DNS_RCODE_H 1 -/*! \file */ +/*! \file dns/rcode.h */ #include <isc/lang.h> @@ -93,6 +93,21 @@ isc_result_t dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target); *\li #ISC_R_NOSPACE target buffer is too small */ +isc_result_t +dns_hashalg_fromtext(unsigned char *hashalg, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a has algorithm value. + * + * Requires: + *\li 'hashalg' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #DNS_R_UNKNOWN type is unknown + */ + ISC_LANG_ENDDECLS #endif /* DNS_RCODE_H */ diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h index a14bde7..126bc96 100644 --- a/lib/dns/include/dns/rdata.h +++ b/lib/dns/include/dns/rdata.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdata.h,v 1.60.18.3 2005/05/19 04:59:56 marka Exp $ */ +/* $Id: rdata.h,v 1.70.120.3 2009/02/16 00:29:27 marka Exp $ */ #ifndef DNS_RDATA_H #define DNS_RDATA_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/rdata.h * \brief * Provides facilities for manipulating DNS rdata, including conversions to * and from wire format and text format. @@ -49,7 +49,7 @@ * build process from a set of source files, one per rdata type. For * portability, it's probably best that the building be done by a C * program. Adding a new rdata type will be a simple matter of adding - * a file to a directory and rebuilding the server. *All* knowlege of + * a file to a directory and rebuilding the server. *All* knowledge of * the format of a particular rdata type is in this file. * * MP: @@ -124,7 +124,8 @@ struct dns_rdata { #define DNS_RDATA_INIT { NULL, 0, 0, 0, 0, {(void*)(-1), (void *)(-1)}} -#define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record */ +#define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record. */ +#define DNS_RDATA_OFFLINE 0x0002 /*%< RRSIG has a offline key. */ /* * Flags affecting rdata formatting style. Flags 0xFFFF0000 @@ -327,11 +328,11 @@ dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass, *\li 'target' is a valid region. * *\li 'origin' if non NULL it must be absolute. - * + * *\li 'callbacks' to be NULL or callbacks->warn and callbacks->error be * initialized. * - * Ensures, + * Ensures, * if result is success: *\li If 'rdata' is not NULL, it is attached to the target. @@ -384,7 +385,8 @@ dns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target); isc_result_t dns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin, unsigned int flags, - unsigned int width, char *linebreak, isc_buffer_t *target); + unsigned int width, const char *linebreak, + isc_buffer_t *target); /*%< * Like dns_rdata_totext, but do formatted output suitable for * database dumps. This is intended for use by dns_db_dump(); diff --git a/lib/dns/include/dns/rdataclass.h b/lib/dns/include/dns/rdataclass.h index fc622bf..786eb6a 100644 --- a/lib/dns/include/dns/rdataclass.h +++ b/lib/dns/include/dns/rdataclass.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataclass.h,v 1.18.18.2 2005/04/29 00:16:18 marka Exp $ */ +/* $Id: rdataclass.h,v 1.24 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_RDATACLASS_H #define DNS_RDATACLASS_H 1 -/*! \file */ +/*! \file dns/rdataclass.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/rdatalist.h b/lib/dns/include/dns/rdatalist.h index 697386f..57debc3 100644 --- a/lib/dns/include/dns/rdatalist.h +++ b/lib/dns/include/dns/rdatalist.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist.h,v 1.14.18.2 2005/04/29 00:16:19 marka Exp $ */ +/* $Id: rdatalist.h,v 1.22 2008/04/03 06:09:05 tbox Exp $ */ #ifndef DNS_RDATALIST_H #define DNS_RDATALIST_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/rdatalist.h * \brief * A DNS rdatalist is a list of rdata of a common type and class. * @@ -98,6 +98,27 @@ dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, *\li #ISC_R_SUCCESS */ +isc_result_t +dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset, + dns_rdatalist_t **rdatalist); +/*%< + * Point 'rdatalist' to the rdatalist in 'rdataset'. + * + * Requires: + * + *\li 'rdatalist' is a pointer to a NULL dns_rdatalist_t pointer. + * + *\li 'rdataset' is a valid rdataset associated with an rdatalist. + * + * Ensures, + * on success, + * + *\li 'rdatalist' is pointed to the rdatalist in rdataset. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + ISC_LANG_ENDDECLS #endif /* DNS_RDATALIST_H */ diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 5597591..baff146 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.h,v 1.51.18.7 2006/03/03 00:56:53 marka Exp $ */ +/* $Id: rdataset.h,v 1.65.50.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_RDATASET_H #define DNS_RDATASET_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/rdataset.h * \brief * A DNS rdataset is a handle that can be associated with a collection of * rdata all having a common owner name, class, and type. @@ -78,8 +78,14 @@ typedef struct dns_rdatasetmethods { dns_name_t *name); isc_result_t (*getnoqname)(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, - dns_rdataset_t *nsecsig); + dns_rdataset_t *neg, + dns_rdataset_t *negsig); + isc_result_t (*addclosest)(dns_rdataset_t *rdataset, + dns_name_t *name); + isc_result_t (*getclosest)(dns_rdataset_t *rdataset, + dns_name_t *name, + dns_rdataset_t *neg, + dns_rdataset_t *negsig); isc_result_t (*getadditional)(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype, @@ -140,6 +146,11 @@ struct dns_rdataset { * increment the counter. */ isc_uint32_t count; + /* + * This RRSIG RRset should be re-generated around this time. + * Only valid if DNS_RDATASETATTR_RESIGN is set in attributes. + */ + isc_stdtime_t resign; /*@{*/ /*% * These are for use by the rdataset implementation, and MUST NOT @@ -151,7 +162,9 @@ struct dns_rdataset { unsigned int privateuint4; void * private5; void * private6; + void * private7; /*@}*/ + }; /*! @@ -184,6 +197,9 @@ struct dns_rdataset { #define DNS_RDATASETATTR_CHECKNAMES 0x00008000 /*%< Used by resolver. */ #define DNS_RDATASETATTR_REQUIREDGLUE 0x00010000 #define DNS_RDATASETATTR_LOADORDER 0x00020000 +#define DNS_RDATASETATTR_RESIGN 0x00040000 +#define DNS_RDATASETATTR_CLOSEST 0x00080000 +#define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */ /*% * _OMITDNSSEC: @@ -348,8 +364,8 @@ dns_rdataset_totext(dns_rdataset_t *rdataset, * Notes: *\li The rdata cursor position will be changed. * - *\li The 'question' flag should normally be #ISC_FALSE. If it is - * #ISC_TRUE, the TTL and rdata fields are not printed. This is + *\li The 'question' flag should normally be #ISC_FALSE. If it is + * #ISC_TRUE, the TTL and rdata fields are not printed. This is * for use when printing an rdata representing a question section. * *\li This interface is deprecated; use dns_master_rdatasettottext() @@ -411,7 +427,7 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, unsigned int *countp); /*%< * Like dns_rdataset_towire(), but sorting the rdatasets according to - * the integer value returned by 'order' when called witih the rdataset + * the integer value returned by 'order' when called with the rdataset * and 'order_arg' as arguments. * * Requires: @@ -477,14 +493,14 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset, isc_result_t dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, dns_rdataset_t *nsecsig); + dns_rdataset_t *neg, dns_rdataset_t *negsig); /*%< * Return the noqname proof for this record. * * Requires: *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set. *\li 'name' to be valid. - *\li 'nsec' and 'nsecsig' to be valid and not associated. + *\li 'neg' and 'negsig' to be valid and not associated. */ isc_result_t @@ -493,11 +509,37 @@ dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name); * Associate a noqname proof with this record. * Sets #DNS_RDATASETATTR_NOQNAME if successful. * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and - * the 'nsec' and 'rrsig(nsec)' ttl. + * the 'nsec'/'nsec3' and 'rrsig(nsec)'/'rrsig(nsec3)' ttl. * * Requires: *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set. - *\li 'name' to be valid and have NSEC and RRSIG(NSEC) rdatasets. + *\li 'name' to be valid and have NSEC or NSEC3 and associated RRSIG + * rdatasets. + */ + +isc_result_t +dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *nsec, dns_rdataset_t *nsecsig); +/*%< + * Return the closest encloser for this record. + * + * Requires: + *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set. + *\li 'name' to be valid. + *\li 'nsec' and 'nsecsig' to be valid and not associated. + */ + +isc_result_t +dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name); +/*%< + * Associate a closest encloset proof with this record. + * Sets #DNS_RDATASETATTR_CLOSEST if successful. + * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and + * the 'nsec' and 'rrsig(nsec)' ttl. + * + * Requires: + *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set. + *\li 'name' to be valid and have NSEC3 and RRSIG(NSEC3) rdatasets. */ isc_result_t diff --git a/lib/dns/include/dns/rdatasetiter.h b/lib/dns/include/dns/rdatasetiter.h index b2e13f8..dcde367 100644 --- a/lib/dns/include/dns/rdatasetiter.h +++ b/lib/dns/include/dns/rdatasetiter.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatasetiter.h,v 1.15.18.2 2005/04/29 00:16:19 marka Exp $ */ +/* $Id: rdatasetiter.h,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_RDATASETITER_H #define DNS_RDATASETITER_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/rdatasetiter.h * \brief * The DNS Rdataset Iterator interface allows iteration of all of the * rdatasets at a node. diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index b693a71..3ac44b8 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataslab.h,v 1.25.18.2 2005/04/29 00:16:19 marka Exp $ */ +/* $Id: rdataslab.h,v 1.33 2008/04/01 23:47:10 tbox Exp $ */ #ifndef DNS_RDATASLAB_H #define DNS_RDATASLAB_H 1 -/*! \file +/*! \file dns/rdataslab.h * \brief * Implements storage of rdatasets into slabs of memory. * @@ -57,6 +57,13 @@ ISC_LANG_BEGINDECLS #define DNS_RDATASLAB_FORCE 0x1 #define DNS_RDATASLAB_EXACT 0x2 +#define DNS_RDATASLAB_OFFLINE 0x01 /* RRSIG is for offline DNSKEY */ +#define DNS_RDATASLAB_WARNMASK 0x0E /*%< RRSIG(DNSKEY) expired + * warnings number mask. */ +#define DNS_RDATASLAB_WARNSHIFT 1 /*%< How many bits to shift to find + * remaining expired warning number. */ + + /*** *** Functions ***/ @@ -146,10 +153,10 @@ dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2, */ isc_boolean_t dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2, - unsigned int reservelen, dns_rdataclass_t rdclass, + unsigned int reservelen, dns_rdataclass_t rdclass, dns_rdatatype_t type); /*%< - * Compare two rdataslabs for DNSSEC equality. + * Compare two rdataslabs for DNSSEC equality. * * Requires: *\li 'slab1' and 'slab2' point to slabs. diff --git a/lib/dns/include/dns/rdatatype.h b/lib/dns/include/dns/rdatatype.h index 40a884d..ba9a92c 100644 --- a/lib/dns/include/dns/rdatatype.h +++ b/lib/dns/include/dns/rdatatype.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatatype.h,v 1.18.18.2 2005/04/29 00:16:20 marka Exp $ */ +/* $Id: rdatatype.h,v 1.26 2008/09/25 04:02:39 tbox Exp $ */ #ifndef DNS_RDATATYPE_H #define DNS_RDATATYPE_H 1 -/*! \file */ +/*! \file dns/rdatatype.h */ #include <isc/lang.h> @@ -71,7 +71,8 @@ dns_rdatatype_format(dns_rdatatype_t rdtype, * The resulting string is guaranteed to be null-terminated. */ -#define DNS_RDATATYPE_FORMATSIZE sizeof("TYPE65535") +#define DNS_RDATATYPE_FORMATSIZE sizeof("NSEC3PARAM") + /*%< * Minimum size of array to pass to dns_rdatatype_format(). * May need to be adjusted if a new RR type with a very long diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index b858a9e..62a83ca 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: request.h,v 1.21.18.2 2005/04/29 00:16:20 marka Exp $ */ +/* $Id: request.h,v 1.27.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_REQUEST_H #define DNS_REQUEST_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/request.h * * \brief * The request module provides simple request/response services useful for @@ -49,7 +49,7 @@ #define DNS_REQUESTOPT_TCP 0x00000001U typedef struct dns_requestevent { - ISC_EVENT_COMMON(struct dns_requestevent); + ISC_EVENT_COMMON(struct dns_requestevent); isc_result_t result; dns_request_t *request; } dns_requestevent_t; @@ -217,7 +217,7 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, unsigned int udpretries, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); -/*%< +/*%< * Create and send a request. * * Notes: @@ -271,7 +271,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, unsigned int udptimeout, unsigned int udpretries, isc_task_t *task, isc_taskaction_t action, void *arg, dns_request_t **requestp); -/*!< +/*!< * \brief Create and send a request. * * Notes: @@ -280,7 +280,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, * #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request * will timeout after 'timeout' seconds. UDP requests will be resent * at 'udptimeout' intervals if non-zero or if 'udpretries' is not zero. - * + * *\li When the request completes, successfully, due to a timeout, or * because it was canceled, a completion event will be sent to 'task'. * @@ -344,7 +344,7 @@ dns_request_usedtcp(dns_request_t *request); /*%< * Return whether this query used TCP or not. Setting #DNS_REQUESTOPT_TCP * in the call to dns_request_create() will cause the function to return - * #ISC_TRUE, othewise the result is based on the query message size. + * #ISC_TRUE, otherwise the result is based on the query message size. * * Requires: *\li 'request' is a valid request. diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 4e0e6a0..fa837c1 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.h,v 1.40.18.11 2006/02/01 22:39:17 marka Exp $ */ +/* $Id: resolver.h,v 1.60.56.3 2009/01/29 22:40:35 jinmei Exp $ */ #ifndef DNS_RESOLVER_H #define DNS_RESOLVER_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/resolver.h * * \brief * This is the BIND 9 resolver, the module responsible for resolving DNS @@ -93,13 +93,29 @@ typedef struct dns_fetchevent { #define DNS_FETCHOPT_FORWARDONLY 0x10 /*%< Only use forwarders. */ #define DNS_FETCHOPT_NOVALIDATE 0x20 /*%< Disable validation. */ #define DNS_FETCHOPT_EDNS512 0x40 /*%< Advertise a 512 byte - UDP buffer. */ + UDP buffer. */ +#define DNS_FETCHOPT_WANTNSID 0x80 /*%< Request NSID */ #define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000 #define DNS_FETCHOPT_EDNSVERSIONMASK 0xff000000 #define DNS_FETCHOPT_EDNSVERSIONSHIFT 24 /* + * Upper bounds of class of query RTT (ms). Corresponds to + * dns_resstatscounter_queryrttX statistics counters. + */ +#define DNS_RESOLVER_QRYRTTCLASS0 10 +#define DNS_RESOLVER_QRYRTTCLASS0STR "10" +#define DNS_RESOLVER_QRYRTTCLASS1 100 +#define DNS_RESOLVER_QRYRTTCLASS1STR "100" +#define DNS_RESOLVER_QRYRTTCLASS2 500 +#define DNS_RESOLVER_QRYRTTCLASS2STR "500" +#define DNS_RESOLVER_QRYRTTCLASS3 800 +#define DNS_RESOLVER_QRYRTTCLASS3STR "800" +#define DNS_RESOLVER_QRYRTTCLASS4 1600 +#define DNS_RESOLVER_QRYRTTCLASS4STR "1600" + +/* * XXXRTH Should this API be made semi-private? (I.e. * _dns_resolver_create()). */ @@ -126,8 +142,6 @@ dns_resolver_create(dns_view_t *view, *\li Generally, applications should not create a resolver directly, but * should instead call dns_view_createresolver(). * - *\li No options are currently defined. - * * Requires: * *\li 'view' is a valid view. @@ -348,6 +362,23 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp); *\li *fetchp == NULL. */ +void +dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx, + isc_logcategory_t *category, isc_logmodule_t *module, + int level, isc_boolean_t duplicateok); +/*%< + * Dump a log message on internal state at the completion of given 'fetch'. + * 'lctx', 'category', 'module', and 'level' are used to write the log message. + * By default, only one log message is written even if the corresponding fetch + * context serves multiple clients; if 'duplicateok' is true the suppression + * is disabled and the message can be written every time this function is + * called. + * + * Requires: + * + *\li 'fetch' is a valid fetch, and has completed. + */ + dns_dispatchmgr_t * dns_resolver_dispatchmgr(dns_resolver_t *resolver); @@ -470,10 +501,13 @@ dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur, isc_boolean_t dns_resolver_getzeronosoattl(dns_resolver_t *resolver); - + void dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state); +unsigned int +dns_resolver_getoptions(dns_resolver_t *resolver); + ISC_LANG_ENDDECLS #endif /* DNS_RESOLVER_H */ diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h index db5481b..ed29bcd 100644 --- a/lib/dns/include/dns/result.h +++ b/lib/dns/include/dns/result.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.104.10.6 2005/06/17 02:04:32 marka Exp $ */ +/* $Id: result.h,v 1.116 2008/09/25 04:02:39 tbox Exp $ */ #ifndef DNS_RESULT_H #define DNS_RESULT_H 1 -/*! \file */ +/*! \file dns/result.h */ #include <isc/lang.h> #include <isc/resultclass.h> @@ -147,8 +147,9 @@ #define DNS_R_COVERINGNSEC (ISC_RESULTCLASS_DNS + 101) #define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102) #define DNS_R_DUPLICATE (ISC_RESULTCLASS_DNS + 103) +#define DNS_R_INVALIDNSEC3 (ISC_RESULTCLASS_DNS + 104) -#define DNS_R_NRESULTS 104 /*%< Number of results */ +#define DNS_R_NRESULTS 105 /*%< Number of results */ /* * DNS wire format rcodes. diff --git a/lib/dns/include/dns/rootns.h b/lib/dns/include/dns/rootns.h index a3ddc48..6da3f79 100644 --- a/lib/dns/include/dns/rootns.h +++ b/lib/dns/include/dns/rootns.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rootns.h,v 1.9.18.3 2005/04/27 05:01:38 sra Exp $ */ +/* $Id: rootns.h,v 1.16 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_ROOTNS_H #define DNS_ROOTNS_H 1 -/*! \file */ +/*! \file dns/rootns.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/sdb.h b/lib/dns/include/dns/sdb.h index de849f9..c850028 100644 --- a/lib/dns/include/dns/sdb.h +++ b/lib/dns/include/dns/sdb.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdb.h,v 1.15.18.2 2005/04/29 00:16:21 marka Exp $ */ +/* $Id: sdb.h,v 1.21.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_SDB_H #define DNS_SDB_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/sdb.h * \brief * Simple database API. */ @@ -127,12 +127,12 @@ dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods, * The allnodes function, if non-NULL, fills in an opaque structure to be * used by a database iterator. This allows the zone to be transferred. * This may use a considerable amount of memory for large zones, and the - * zone transfer may not be fully RFC1035 compliant if the zone is + * zone transfer may not be fully RFC1035 compliant if the zone is * frequently changed. * * The create function will be called for each zone configured * into the name server using this database type. It can be used - * to create a "database object" containg zone specific data, + * to create a "database object" containing zone specific data, * which can make use of the database arguments specified in the * name server configuration. * diff --git a/lib/dns/include/dns/sdlz.h b/lib/dns/include/dns/sdlz.h index 13ba14a..acb0437 100644 --- a/lib/dns/include/dns/sdlz.h +++ b/lib/dns/include/dns/sdlz.h @@ -1,8 +1,8 @@ /* - * Portions Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -50,9 +50,9 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdlz.h,v 1.2.2.2 2005/09/06 03:47:19 marka Exp $ */ +/* $Id: sdlz.h,v 1.7.332.2 2009/01/18 23:47:41 tbox Exp $ */ -/*! \file */ +/*! \file dns/sdlz.h */ #ifndef SDLZ_H #define SDLZ_H 1 @@ -148,7 +148,7 @@ typedef void /*%< * Method prototype. Drivers implementing the SDLZ interface may * supply a destroy method. This method is called when the DNS server - * is shuting down and no longer needs the driver. A SDLZ driver does + * is shutting down and no longer needs the driver. A SDLZ driver does * not have to implement a destroy method. */ @@ -173,7 +173,7 @@ typedef isc_result_t * \li 3) we run out of domain name labels. I.E. we have tried the * shortest domain name * - * \li 4) the number of labels in the domain name is less than min_lables + * \li 4) the number of labels in the domain name is less than min_labels * for dns_dlzfindzone * * The driver's find zone method should return ISC_R_SUCCESS if the diff --git a/lib/dns/include/dns/secalg.h b/lib/dns/include/dns/secalg.h index 0466d91..2e4fe3e 100644 --- a/lib/dns/include/dns/secalg.h +++ b/lib/dns/include/dns/secalg.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: secalg.h,v 1.13.18.2 2005/04/29 00:16:21 marka Exp $ */ +/* $Id: secalg.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_SECALG_H #define DNS_SECALG_H 1 -/*! \file */ +/*! \file dns/secalg.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/secproto.h b/lib/dns/include/dns/secproto.h index a6cfd5c..b9179c0 100644 --- a/lib/dns/include/dns/secproto.h +++ b/lib/dns/include/dns/secproto.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: secproto.h,v 1.10.18.2 2005/04/29 00:16:21 marka Exp $ */ +/* $Id: secproto.h,v 1.16 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_SECPROTO_H #define DNS_SECPROTO_H 1 -/*! \file */ +/*! \file dns/secproto.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/soa.h b/lib/dns/include/dns/soa.h index 70c6725..bb56365 100644 --- a/lib/dns/include/dns/soa.h +++ b/lib/dns/include/dns/soa.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa.h,v 1.3.18.2 2005/04/29 00:16:22 marka Exp $ */ +/* $Id: soa.h,v 1.9 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_SOA_H #define DNS_SOA_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/soa.h * \brief * SOA utilities. */ diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h index b709030..f013bd0 100644 --- a/lib/dns/include/dns/ssu.h +++ b/lib/dns/include/dns/ssu.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ssu.h,v 1.13.18.4 2006/02/16 23:51:32 marka Exp $ */ +/* $Id: ssu.h,v 1.24 2008/01/18 23:46:58 tbox Exp $ */ #ifndef DNS_SSU_H #define DNS_SSU_H 1 -/*! \file */ +/*! \file dns/ssu.h */ #include <isc/lang.h> @@ -28,14 +28,19 @@ ISC_LANG_BEGINDECLS -#define DNS_SSUMATCHTYPE_NAME 0 -#define DNS_SSUMATCHTYPE_SUBDOMAIN 1 -#define DNS_SSUMATCHTYPE_WILDCARD 2 -#define DNS_SSUMATCHTYPE_SELF 3 -#define DNS_SSUMATCHTYPE_SELFSUB 4 -#define DNS_SSUMATCHTYPE_SELFWILD 5 -#define DNS_SSUMATCHTYPE_MAX 5 /* maximum defined value */ - +#define DNS_SSUMATCHTYPE_NAME 0 +#define DNS_SSUMATCHTYPE_SUBDOMAIN 1 +#define DNS_SSUMATCHTYPE_WILDCARD 2 +#define DNS_SSUMATCHTYPE_SELF 3 +#define DNS_SSUMATCHTYPE_SELFSUB 4 +#define DNS_SSUMATCHTYPE_SELFWILD 5 +#define DNS_SSUMATCHTYPE_SELFKRB5 6 +#define DNS_SSUMATCHTYPE_SELFMS 7 +#define DNS_SSUMATCHTYPE_SUBDOMAINMS 8 +#define DNS_SSUMATCHTYPE_SUBDOMAINKRB5 9 +#define DNS_SSUMATCHTYPE_TCPSELF 10 +#define DNS_SSUMATCHTYPE_6TO4SELF 11 +#define DNS_SSUMATCHTYPE_MAX 11 /* max value */ isc_result_t dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table); @@ -91,8 +96,8 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant, * at that name. * * Notes: - *\li If 'matchtype' is SELF, this rule only matches if the name - * to be updated matches the signing identity. + *\li If 'matchtype' is of SELF type, this rule only matches if the + * name to be updated matches the signing identity. * *\li If 'ntypes' is 0, this rule applies to all types except * NS, SOA, RRSIG, and NSEC. @@ -114,16 +119,35 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant, isc_boolean_t dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer, - dns_name_t *name, dns_rdatatype_t type); + dns_name_t *name, isc_netaddr_t *tcpaddr, + dns_rdatatype_t type); /*%< * Checks that the attempted update of (name, type) is allowed according * to the rules specified in the simple-secure-update rule table. If - * no rules are matched, access is denied. If signer is NULL, access - * is denied. + * no rules are matched, access is denied. + * + * Notes: + * 'tcpaddr' should only be set if the request received + * via TCP. This provides a weak assurance that the + * request was not spoofed. 'tcpaddr' is to to validate + * DNS_SSUMATCHTYPE_TCPSELF and DNS_SSUMATCHTYPE_6TO4SELF + * rules. + * + * For DNS_SSUMATCHTYPE_TCPSELF the addresses are mapped to + * the standard reverse names under IN-ADDR.ARPA and IP6.ARPA. + * RFC 1035, Section 3.5, "IN-ADDR.ARPA domain" and RFC 3596, + * Section 2.5, "IP6.ARPA Domain". + * + * For DNS_SSUMATCHTYPE_6TO4SELF, IPv4 address are converted + * to a 6to4 prefix (48 bits) per the rules in RFC 3056. Only + * the top 48 bits of the IPv6 address are mapped to the reverse + * name. This is independent of whether the most significant 16 + * bits match 2002::/16, assigned for 6to4 prefixes, or not. * * Requires: *\li 'table' is a valid SSU table *\li 'signer' is NULL or a valid absolute name + *\li 'tcpaddr' is NULL or a valid network address. *\li 'name' is a valid absolute name */ diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h index 6cd95ac..0b35aa8 100644 --- a/lib/dns/include/dns/stats.h +++ b/lib/dns/include/dns/stats.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,19 +15,77 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.h,v 1.5.18.4 2005/06/27 00:20:03 marka Exp $ */ +/* $Id: stats.h,v 1.18.56.2 2009/01/29 23:47:44 tbox Exp $ */ #ifndef DNS_STATS_H #define DNS_STATS_H 1 -/*! \file */ +/*! \file dns/stats.h */ #include <dns/types.h> /*% - * Query statistics counter types. + * Statistics counters. Used as isc_statscounter_t values. */ -typedef enum { +enum { + /*% + * Resolver statistics counters. + */ + dns_resstatscounter_queryv4 = 0, + dns_resstatscounter_queryv6 = 1, + dns_resstatscounter_responsev4 = 2, + dns_resstatscounter_responsev6 = 3, + dns_resstatscounter_nxdomain = 4, + dns_resstatscounter_servfail = 5, + dns_resstatscounter_formerr = 6, + dns_resstatscounter_othererror = 7, + dns_resstatscounter_edns0fail = 8, + dns_resstatscounter_mismatch = 9, + dns_resstatscounter_truncated = 10, + dns_resstatscounter_lame = 11, + dns_resstatscounter_retry = 12, + dns_resstatscounter_gluefetchv4 = 13, + dns_resstatscounter_gluefetchv6 = 14, + dns_resstatscounter_gluefetchv4fail = 15, + dns_resstatscounter_gluefetchv6fail = 16, + dns_resstatscounter_val = 17, + dns_resstatscounter_valsuccess = 18, + dns_resstatscounter_valnegsuccess = 19, + dns_resstatscounter_valfail = 20, + dns_resstatscounter_dispabort = 21, + dns_resstatscounter_dispsockfail = 22, + dns_resstatscounter_querytimeout = 23, + dns_resstatscounter_queryrtt0 = 24, + dns_resstatscounter_queryrtt1 = 25, + dns_resstatscounter_queryrtt2 = 26, + dns_resstatscounter_queryrtt3 = 27, + dns_resstatscounter_queryrtt4 = 28, + dns_resstatscounter_queryrtt5 = 29, + + dns_resstatscounter_max = 30, + + /*% + * Zone statistics counters. + */ + dns_zonestatscounter_notifyoutv4 = 0, + dns_zonestatscounter_notifyoutv6 = 1, + dns_zonestatscounter_notifyinv4 = 2, + dns_zonestatscounter_notifyinv6 = 3, + dns_zonestatscounter_notifyrej = 4, + dns_zonestatscounter_soaoutv4 = 5, + dns_zonestatscounter_soaoutv6 = 6, + dns_zonestatscounter_axfrreqv4 = 7, + dns_zonestatscounter_axfrreqv6 = 8, + dns_zonestatscounter_ixfrreqv4 = 9, + dns_zonestatscounter_ixfrreqv6 = 10, + dns_zonestatscounter_xfrsuccess = 11, + dns_zonestatscounter_xfrfail = 12, + + dns_zonestatscounter_max = 13, + + /*% + * Query statistics counters (obsolete). + */ dns_statscounter_success = 0, /*%< Successful lookup */ dns_statscounter_referral = 1, /*%< Referral result */ dns_statscounter_nxrrset = 2, /*%< NXRRSET result */ @@ -35,18 +93,261 @@ typedef enum { dns_statscounter_recursion = 4, /*%< Recursion was used */ dns_statscounter_failure = 5, /*%< Some other failure */ dns_statscounter_duplicate = 6, /*%< Duplicate query */ - dns_statscounter_dropped = 7 /*%< Duplicate query */ -} dns_statscounter_t; + dns_statscounter_dropped = 7 /*%< Duplicate query (dropped) */ +}; #define DNS_STATS_NCOUNTERS 8 +#if 0 +/*%< + * Flag(s) for dns_xxxstats_dump(). DNS_STATSDUMP_VERBOSE is obsolete. + * ISC_STATSDUMP_VERBOSE should be used instead. These two values are + * intentionally defined to be the same value to ensure binary compatibility. + */ +#define DNS_STATSDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */ +#endif + +/*%< + * (Obsoleted) + */ LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[]; +/*% + * Attributes for statistics counters of RRset and Rdatatype types. + * + * _OTHERTYPE + * The rdata type is not explicitly supported and the corresponding counter + * is counted for other such types, too. When this attribute is set, + * the base type is of no use. + * + * _NXRRSET + * RRset type counters only. Indicates the RRset is non existent. + * + * _NXDOMAIN + * RRset type counters only. Indicates a non existent name. When this + * attribute is set, the base type is of no use. + */ +#define DNS_RDATASTATSTYPE_ATTR_OTHERTYPE 0x0001 +#define DNS_RDATASTATSTYPE_ATTR_NXRRSET 0x0002 +#define DNS_RDATASTATSTYPE_ATTR_NXDOMAIN 0x0004 + +/*%< + * Conversion macros among dns_rdatatype_t, attributes and isc_statscounter_t. + */ +#define DNS_RDATASTATSTYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF)) +#define DNS_RDATASTATSTYPE_ATTR(type) ((type) >> 16) +#define DNS_RDATASTATSTYPE_VALUE(b, a) (((a) << 16) | (b)) + +/*%< + * Types of dump callbacks. + */ +typedef void (*dns_generalstats_dumper_t)(isc_statscounter_t, isc_uint64_t, + void *); +typedef void (*dns_rdatatypestats_dumper_t)(dns_rdatastatstype_t, isc_uint64_t, + void *); +typedef void (*dns_opcodestats_dumper_t)(dns_opcode_t, isc_uint64_t, void *); + +isc_result_t +dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters); +/*%< + * Create a statistics counter structure of general type. It counts a general + * set of counters indexed by an ID between 0 and ncounters -1. + * This function is obsolete. A more general function, isc_stats_create(), + * should be used. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per rdatatype. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per RRset. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per opcode. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +void +dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp); +/*%< + * Attach to a statistics set. + * + * Requires: + *\li 'stats' is a valid dns_stats_t. + * + *\li 'statsp' != NULL && '*statsp' == NULL + */ + +void +dns_stats_detach(dns_stats_t **statsp); +/*%< + * Detaches from the statistics set. + * + * Requires: + *\li 'statsp' != NULL and '*statsp' is a valid dns_stats_t. + */ + +void +dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter); +/*%< + * Increment the counter-th counter of stats. This function is obsolete. + * A more general function, isc_stats_increment(), should be used. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + * + *\li counter is less than the maximum available ID for the stats specified + * on creation. + */ + +void +dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type); +/*%< + * Increment the statistics counter for 'type'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatatypestats_create(). + */ + +void +dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); +/*%< + * Increment the statistics counter for 'rrsettype'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create(). + */ + +void +dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); +/*%< + * Decrement the statistics counter for 'rrsettype'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create(). + */ + +void +dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code); +/*%< + * Increment the statistics counter for 'code'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_opcodestats_create(). + */ + +void +dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with its current value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * This function is obsolete. A more general function, isc_stats_dump(), + * should be used. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding opcode, the current + * counter value and the given argument arg. By default counters that have a + * value of 0 is skipped; if options has the ISC_STATSDUMP_VERBOSE flag, even + * such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + isc_result_t dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp); /*%< * Allocate an array of query statistics counters from the memory * context 'mctx'. + * + * This function is obsoleted. Use dns_xxxstats_create() instead. */ void @@ -54,6 +355,8 @@ dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp); /*%< * Free an array of query statistics counters allocated from the memory * context 'mctx'. + * + * This function is obsoleted. Use dns_stats_destroy() instead. */ ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/tcpmsg.h b/lib/dns/include/dns/tcpmsg.h index 075f463..fe83c53 100644 --- a/lib/dns/include/dns/tcpmsg.h +++ b/lib/dns/include/dns/tcpmsg.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tcpmsg.h,v 1.16.18.2 2005/04/29 00:16:22 marka Exp $ */ +/* $Id: tcpmsg.h,v 1.22 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_TCPMSG_H #define DNS_TCPMSG_H 1 -/*! \file */ +/*! \file dns/tcpmsg.h */ #include <isc/buffer.h> #include <isc/lang.h> diff --git a/lib/dns/include/dns/time.h b/lib/dns/include/dns/time.h index 9e8f5cc..5b47d11 100644 --- a/lib/dns/include/dns/time.h +++ b/lib/dns/include/dns/time.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: time.h,v 1.11.18.2 2005/04/29 00:16:23 marka Exp $ */ +/* $Id: time.h,v 1.17 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_TIME_H #define DNS_TIME_H 1 -/*! \file */ +/*! \file dns/time.h */ /*** *** Imports diff --git a/lib/dns/include/dns/timer.h b/lib/dns/include/dns/timer.h index cd936a0..48d6d56 100644 --- a/lib/dns/include/dns/timer.h +++ b/lib/dns/include/dns/timer.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: timer.h,v 1.3.18.2 2005/04/29 00:16:23 marka Exp $ */ +/* $Id: timer.h,v 1.9 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_TIMER_H #define DNS_TIMER_H 1 -/*! \file */ +/*! \file dns/timer.h */ /*** *** Imports diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h index 4e3e80a..3511f2f 100644 --- a/lib/dns/include/dns/tkey.h +++ b/lib/dns/include/dns/tkey.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,18 +15,19 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tkey.h,v 1.19.18.2 2005/04/29 00:16:23 marka Exp $ */ +/* $Id: tkey.h,v 1.26.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_TKEY_H #define DNS_TKEY_H 1 -/*! \file */ +/*! \file dns/tkey.h */ #include <isc/lang.h> #include <dns/types.h> #include <dst/dst.h> +#include <dst/gssapi.h> ISC_LANG_BEGINDECLS @@ -40,13 +41,14 @@ ISC_LANG_BEGINDECLS struct dns_tkeyctx { dst_key_t *dhkey; dns_name_t *domain; - void *gsscred; + gss_cred_id_t gsscred; isc_mem_t *mctx; isc_entropy_t *ectx; }; isc_result_t -dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp); +dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, + dns_tkeyctx_t **tctxp); /*%< * Create an empty TKEY context. * @@ -119,13 +121,29 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, */ isc_result_t -dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, - dns_name_t *gname, void *cred, - isc_uint32_t lifetime, void **context); +dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, + isc_buffer_t *intoken, isc_uint32_t lifetime, + gss_ctx_id_t *context, isc_boolean_t win2k); /*%< - * XXX + * Builds a query containing a TKEY that will generate a GSSAPI context. + * The key is requested to have the specified lifetime (in seconds). + * + * Requires: + *\li 'msg' is a valid message + *\li 'name' is a valid name + *\li 'gname' is a valid name + *\li 'context' is a pointer to a valid gss_ctx_id_t + * (which may have the value GSS_C_NO_CONTEXT) + *\li 'win2k' when true says to turn on some hacks to work + * with the non-standard GSS-TSIG of Windows 2000 + * + * Returns: + *\li ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + *\li other an error occurred while building the message */ + isc_result_t dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key); /*%< @@ -144,7 +162,7 @@ dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key); isc_result_t dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, - dst_key_t *key, isc_buffer_t *nonce, + dst_key_t *key, isc_buffer_t *nonce, dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring); /*%< * Processes a response to a query containing a TKEY that was @@ -167,8 +185,9 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, isc_result_t dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, - dns_name_t *gname, void *cred, void **context, - dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring); + dns_name_t *gname, gss_ctx_id_t *context, + isc_buffer_t *outtoken, dns_tsigkey_t **outkey, + dns_tsig_keyring_t *ring); /*%< * XXX */ @@ -193,6 +212,39 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, */ +isc_result_t +dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, + dns_name_t *server, gss_ctx_id_t *context, + dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, + isc_boolean_t win2k); + +/* + * Client side negotiation of GSS-TSIG. Process the response + * to a TKEY, and establish a TSIG key if negotiation was successful. + * Build a response to the input TKEY message. Can take multiple + * calls to successfully establish the context. + * + * Requires: + * 'qmsg' is a valid message, the original TKEY request; + * it will be filled with the new message to send + * 'rmsg' is a valid message, the incoming TKEY message + * 'server' is the server name + * 'context' is the input context handle + * 'outkey' receives the established key, if non-NULL; + * if non-NULL must point to NULL + * 'ring' is the keyring in which to establish the key, + * or NULL + * 'win2k' when true says to turn on some hacks to work + * with the non-standard GSS-TSIG of Windows 2000 + * + * Returns: + * ISC_R_SUCCESS context was successfully established + * ISC_R_NOTFOUND couldn't find a needed part of the query + * or response + * DNS_R_CONTINUE additional context negotiation is required; + * send the new qmsg to the server + */ + ISC_LANG_ENDDECLS #endif /* DNS_TKEY_H */ diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index b3fd6cc..e8c0e2c 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsig.h,v 1.43.18.4 2006/01/27 23:57:44 marka Exp $ */ +/* $Id: tsig.h,v 1.51 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_TSIG_H #define DNS_TSIG_H 1 -/*! \file */ +/*! \file dns/tsig.h */ #include <isc/lang.h> #include <isc/refcount.h> @@ -59,6 +59,7 @@ LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha512_name; struct dns_tsig_keyring { dns_rbt_t *keys; + unsigned int writecount; isc_rwlock_t lock; isc_mem_t *mctx; }; @@ -79,7 +80,9 @@ struct dns_tsigkey { }; #define dns_tsigkey_identity(tsigkey) \ - ((tsigkey)->generated ? ((tsigkey)->creator) : (&((tsigkey)->name))) + ((tsigkey) == NULL ? NULL : \ + (tsigkey)->generated ? ((tsigkey)->creator) : \ + (&((tsigkey)->name))) ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/ttl.h b/lib/dns/include/dns/ttl.h index ad01578..c252518 100644 --- a/lib/dns/include/dns/ttl.h +++ b/lib/dns/include/dns/ttl.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ttl.h,v 1.13.18.2 2005/04/29 00:16:24 marka Exp $ */ +/* $Id: ttl.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_TTL_H #define DNS_TTL_H 1 -/*! \file */ +/*! \file dns/ttl.h */ /*** *** Imports diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 8dcbe57..e07a796 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.109.18.12 2006/05/02 12:55:31 shane Exp $ */ +/* $Id: types.h,v 1.130.50.3 2009/01/29 22:40:35 jinmei Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 -/*! \file +/*! \file dns/types.h * \brief * Including this file gives you type declarations suitable for use in * .h files, which lets us avoid circular type reference problems. @@ -68,6 +68,8 @@ typedef struct dns_fetch dns_fetch_t; typedef struct dns_fixedname dns_fixedname_t; typedef struct dns_forwarders dns_forwarders_t; typedef struct dns_fwdtable dns_fwdtable_t; +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 struct dns_keytable dns_keytable_t; @@ -105,6 +107,8 @@ typedef isc_uint8_t dns_secproto_t; typedef struct dns_signature dns_signature_t; typedef struct dns_ssurule dns_ssurule_t; typedef struct dns_ssutable dns_ssutable_t; +typedef struct dns_stats dns_stats_t; +typedef isc_uint32_t dns_rdatastatstype_t; typedef struct dns_tkeyctx dns_tkeyctx_t; typedef isc_uint16_t dns_trust_t; typedef struct dns_tsig_keyring dns_tsig_keyring_t; @@ -118,6 +122,19 @@ typedef ISC_LIST(dns_zone_t) dns_zonelist_t; typedef struct dns_zonemgr dns_zonemgr_t; typedef struct dns_zt dns_zt_t; +/* + * If we are not using GSSAPI, define the types we use as opaque types here. + */ +#ifndef GSSAPI +typedef struct not_defined_gss_cred_id *gss_cred_id_t; +typedef struct not_defined_gss_ctx *gss_ctx_id_t; +#endif +typedef struct dst_gssapi_signverifyctx dst_gssapi_signverifyctx_t; + +typedef enum { + dns_hash_sha1 = 1 +} dns_hash_t; + typedef enum { dns_fwdpolicy_none = 0, dns_fwdpolicy_first = 1, @@ -249,11 +266,11 @@ enum { dns_trust_additional = 2, #define dns_trust_additional ((dns_trust_t)dns_trust_additional) - /* Received in a referral response. */ + /* Received in a referral response. */ dns_trust_glue = 3, #define dns_trust_glue ((dns_trust_t)dns_trust_glue) - /* Answser from a non-authoritative server */ + /* Answer from a non-authoritative server */ dns_trust_answer = 4, #define dns_trust_answer ((dns_trust_t)dns_trust_answer) @@ -262,11 +279,11 @@ enum { dns_trust_authauthority = 5, #define dns_trust_authauthority ((dns_trust_t)dns_trust_authauthority) - /* Answser from an authoritative server */ + /* Answer from an authoritative server */ dns_trust_authanswer = 6, #define dns_trust_authanswer ((dns_trust_t)dns_trust_authanswer) - /* Successfully DNSSEC validated */ + /* Successfully DNSSEC validated */ dns_trust_secure = 7, #define dns_trust_secure ((dns_trust_t)dns_trust_secure) @@ -276,7 +293,7 @@ enum { }; /*% - * Name checking severites. + * Name checking severities. */ typedef enum { dns_severity_ignore, @@ -308,7 +325,7 @@ typedef void typedef void (*dns_updatecallback_t)(void *, isc_result_t, dns_message_t *); -typedef int +typedef int (*dns_rdatasetorderfunc_t)(const dns_rdata_t *, const void *); typedef isc_boolean_t diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h index c94fc3a..2555214 100644 --- a/lib/dns/include/dns/validator.h +++ b/lib/dns/include/dns/validator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.h,v 1.27.18.10 2007/09/26 04:39:45 each Exp $ */ +/* $Id: validator.h,v 1.41.48.3 2009/01/18 23:25:17 marka Exp $ */ #ifndef DNS_VALIDATOR_H #define DNS_VALIDATOR_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/validator.h * * \brief * DNS Validator @@ -74,7 +74,7 @@ * caller so that they may be freed. * * If the RESULT is ISC_R_SUCCESS and the answer is secure then - * proofs[] will contain the the names of the NSEC records that hold the + * proofs[] will contain the names of the NSEC records that hold the * various proofs. Note the same name may appear multiple times. */ typedef struct dns_validatorevent { @@ -99,12 +99,17 @@ typedef struct dns_validatorevent { /* * Proofs to be cached. */ - dns_name_t * proofs[3]; + dns_name_t * proofs[4]; + /* + * Optout proof seen. + */ + isc_boolean_t optout; } dns_validatorevent_t; #define DNS_VALIDATOR_NOQNAMEPROOF 0 #define DNS_VALIDATOR_NODATAPROOF 1 #define DNS_VALIDATOR_NOWILDCARDPROOF 2 +#define DNS_VALIDATOR_CLOSESTENCLOSER 3 /*% * A validator object represents a validation in progress. @@ -139,11 +144,14 @@ struct dns_validator { dns_rdataset_t * dsset; dns_rdataset_t * soaset; dns_rdataset_t * nsecset; + dns_rdataset_t * nsec3set; dns_name_t * soaname; dns_rdataset_t frdataset; dns_rdataset_t fsigrdataset; dns_fixedname_t fname; dns_fixedname_t wild; + dns_fixedname_t nearest; + dns_fixedname_t closest; ISC_LINK(dns_validator_t) link; dns_rdataset_t dlv; dns_fixedname_t dlvsep; @@ -202,7 +210,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, * options: * If DNS_VALIDATOR_DLV is set the caller knows there is not a * trusted key and the validator should immediately attempt to validate - * the answer by looking for a appopriate DLV RRset. + * the answer by looking for an appropriate DLV RRset. */ void diff --git a/lib/dns/include/dns/version.h b/lib/dns/include/dns/version.h index bb254534..2a33dcf 100644 --- a/lib/dns/include/dns/version.h +++ b/lib/dns/include/dns/version.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,9 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: version.h,v 1.3.18.2 2005/04/29 00:16:25 marka Exp $ */ +/* $Id: version.h,v 1.9 2007/06/19 23:47:17 tbox Exp $ */ -/*! \file */ +/*! \file dns/version.h */ #include <isc/platform.h> diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index ea3d4c7..5b53c16 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.91.18.9 2006/03/09 23:38:21 marka Exp $ */ +/* $Id: view.h,v 1.111.88.4 2009/01/29 22:40:35 jinmei Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/view.h * \brief * DNS View * @@ -100,6 +100,9 @@ struct dns_view { isc_event_t resevent; isc_event_t adbevent; isc_event_t reqevent; + isc_stats_t * resstats; + dns_stats_t * resquerystats; + /* Configurable data. */ dns_tsig_keyring_t * statickeys; dns_tsig_keyring_t * dynamickeys; @@ -116,10 +119,17 @@ struct dns_view { isc_boolean_t acceptexpired; dns_transfer_format_t transfer_format; dns_acl_t * queryacl; + dns_acl_t * queryonacl; dns_acl_t * recursionacl; + dns_acl_t * recursiononacl; dns_acl_t * sortlist; + dns_acl_t * notifyacl; + dns_acl_t * transferacl; + dns_acl_t * updateacl; + dns_acl_t * upfwdacl; isc_boolean_t requestixfr; isc_boolean_t provideixfr; + isc_boolean_t requestnsid; dns_ttl_t maxcachettl; dns_ttl_t maxncachettl; in_port_t dstport; @@ -224,7 +234,7 @@ void dns_view_flushanddetach(dns_view_t **viewp); /*%< * Detach '*viewp' from its view. If this was the last reference - * uncommited changed in zones will be flushed to disk. + * uncommitted changed in zones will be flushed to disk. * * Requires: * @@ -363,7 +373,7 @@ dns_view_setdstport(dns_view_t *view, in_port_t dstport); *\li 'dstport' is a valid TCP/UDP port number. * * Ensures: - *\li External name servers will be assumed to be listning + *\li External name servers will be assumed to be listening * on 'dstport'. For servers whose address has already * obtained obtained at the time of the call, the view may * continue to use the previously set port until the address @@ -591,6 +601,19 @@ dns_viewlist_find(dns_viewlist_t *list, const char *name, */ isc_result_t +dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name, isc_boolean_t allclasses, + dns_rdataclass_t rdclass, dns_zone_t **zonep); + +/*%< + * Search zone with 'name' in view with 'rdclass' in viewlist 'list' + * If found, zone is returned in *zonep. If allclasses is set rdclass is ignored + * + * Returns: + *\li #ISC_R_SUCCESS A matching zone was found. + *\li #ISC_R_NOTFOUND No matching zone was found. + */ + +isc_result_t dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep); /*%< * Search for the zone 'name' in the zone table of 'view'. @@ -615,7 +638,7 @@ dns_view_loadnew(dns_view_t *view, isc_boolean_t stop); /*%< * Load zones attached to this view. dns_view_load() loads * all zones whose master file has changed since the last - * load; dns_view_loadnew() loads only zones that have never + * load; dns_view_loadnew() loads only zones that have never * been loaded. * * If 'stop' is ISC_TRUE, stop on the first error and return it. @@ -633,7 +656,7 @@ dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, * Find the TSIG key configured in 'view' with name 'keyname', * if any. * - * Reqires: + * Requires: *\li keyp points to a NULL dns_tsigkey_t *. * * Returns: @@ -649,7 +672,7 @@ dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr, * Find the TSIG key configured in 'view' for the server whose * address is 'peeraddr', if any. * - * Reqires: + * Requires: * keyp points to a NULL dns_tsigkey_t *. * * Returns: @@ -691,7 +714,7 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp); * easily obtainable by other means. * * Requires: - * + * *\li 'view' is valid. * *\li 'fp' refers to a file open for writing. @@ -734,7 +757,7 @@ isc_result_t dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name); /*%< * Add the given name to the delegation only table. - * + * * * Requires: *\li 'view' is valid. @@ -749,7 +772,7 @@ isc_result_t dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name); /*%< * Add the given name to be excluded from the root-delegation-only. - * + * * * Requires: *\li 'view' is valid. @@ -771,8 +794,8 @@ dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name); *\li 'name' is valid. * * Returns: - *\li #ISC_TRUE if the name is is the table. - *\li #ISC_FALSE othewise. + *\li #ISC_TRUE if the name is the table. + *\li #ISC_FALSE otherwise. */ void @@ -801,4 +824,56 @@ dns_view_freezezones(dns_view_t *view, isc_boolean_t freeze); * Requires: * \li 'view' is valid. */ + +void +dns_view_setresstats(dns_view_t *view, isc_stats_t *stats); +/*%< + * Set a general resolver statistics counter set 'stats' for 'view'. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics supporting resolver statistics counters + * (see dns/stats.h). + */ + +void +dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp); +/*%< + * Get the general statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ + +void +dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats); +/*%< + * Set a statistics counter set of rdata type, 'stats', for 'view'. Once the + * statistic set is installed, view's resolver will count outgoing queries + * per rdata type. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics created by dns_rdatatypestats_create(). + */ + +void +dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp); +/*%< + * Get the rdatatype statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ + #endif /* DNS_VIEW_H */ diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index fcd482e..04866ee 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.h,v 1.20.18.5 2006/07/20 01:10:30 marka Exp $ */ +/* $Id: xfrin.h,v 1.28.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DNS_XFRIN_H #define DNS_XFRIN_H 1 @@ -24,7 +24,7 @@ ***** Module Info *****/ -/*! \file +/*! \file dns/xfrin.h * \brief * Incoming zone transfers (AXFR + IXFR). */ @@ -90,7 +90,7 @@ dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr); /*%< * If the zone transfer 'xfr' has already finished, * do nothing. Otherwise, abort it and cause it to call - * its done callback with a status of ISC_R_CANCELLED. + * its done callback with a status of ISC_R_CANCELED. */ void diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 7cb8272..e2859ae 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.126.18.19 2006/08/01 03:45:21 marka Exp $ */ +/* $Id: zone.h,v 1.160.50.4 2009/01/29 22:40:35 jinmei Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 -/*! \file */ +/*! \file dns/zone.h */ /*** *** Imports @@ -33,6 +33,7 @@ #include <isc/rwlock.h> #include <dns/masterdump.h> +#include <dns/rdatastruct.h> #include <dns/types.h> typedef enum { @@ -66,6 +67,9 @@ typedef enum { #define DNS_ZONEOPT_WARNSRVCNAME 0x00200000U /*%< warn on SRV CNAME check */ #define DNS_ZONEOPT_IGNORESRVCNAME 0x00400000U /*%< ignore SRV CNAME check */ #define DNS_ZONEOPT_UPDATECHECKKSK 0x00800000U /*%< check dnskey KSK flag */ +#define DNS_ZONEOPT_TRYTCPREFRESH 0x01000000U /*%< try tcp refresh on udp failure */ +#define DNS_ZONEOPT_NOTIFYTOSOA 0x02000000U /*%< Notify the SOA MNAME */ +#define DNS_ZONEOPT_NSEC3TESTZONE 0x04000000U /*%< nsec3-test-zone */ #ifndef NOMINUM_PUBLIC /* @@ -145,6 +149,15 @@ dns_zone_getclass(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +isc_uint32_t +dns_zone_getserial(dns_zone_t *zone); +/*%< + * Returns the current serial number of the zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + void dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type); /*%< @@ -406,7 +419,7 @@ dns_zone_refresh(dns_zone_t *zone); isc_result_t dns_zone_flush(dns_zone_t *zone); /*%< - * Write the zone to database if there are uncommited changes. + * Write the zone to database if there are uncommitted changes. * * Require: *\li 'zone' to be a valid zone. @@ -458,7 +471,7 @@ dns_zone_fulldumptostream(dns_zone_t *zone, FILE *fd); void dns_zone_maintenance(dns_zone_t *zone); /*%< - * Perform regular maintenace on the zone. This is called as a + * Perform regular maintenance on the zone. This is called as a * result of a zone being managed. * * Require @@ -503,7 +516,7 @@ dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, * Require: *\li 'zone' to be a valid zone. *\li 'notify' to be non-NULL if count != 0. - *\li 'count' to be the number of notifyees. + *\li 'count' to be the number of notifiees. * * Returns: *\li #ISC_R_SUCCESS @@ -701,6 +714,16 @@ dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl); */ void +dns_zone_setqueryonacl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the query-on acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be a valid acl. + */ + +void dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl); /*%< * Sets the update acl list for the zone. @@ -757,6 +780,19 @@ dns_zone_getqueryacl(dns_zone_t *zone); */ dns_acl_t * +dns_zone_getqueryonacl(dns_zone_t *zone); +/*%< + * Returns the current query-on acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +dns_acl_t * dns_zone_getupdateacl(dns_zone_t *zone); /*%< * Returns the current update acl or NULL. @@ -832,6 +868,15 @@ dns_zone_clearqueryacl(dns_zone_t *zone); */ void +dns_zone_clearqueryonacl(dns_zone_t *zone); +/*%< + * Clear the current query-on acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void dns_zone_clearxfracl(dns_zone_t *zone); /*%< * Clear the current transfer acl. @@ -844,12 +889,16 @@ isc_boolean_t dns_zone_getupdatedisabled(dns_zone_t *zone); /*%< * Return update disabled. + * Transient unless called when running in isc_task_exclusive() mode. */ void dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state); /*%< * Set update disabled. + * Should only be called only when running in isc_task_exclusive() mode. + * Failure to do so may result in updates being committed after the + * call has been made. */ isc_boolean_t @@ -905,13 +954,13 @@ isc_result_t dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, dns_message_t *msg); /*%< - * Tell the zone that it has recieved a NOTIFY message from another - * server. This may cause some zone maintainence activity to occur. + * Tell the zone that it has received a NOTIFY message from another + * server. This may cause some zone maintenance activity to occur. * * Requires: *\li 'zone' to be a valid zone. *\li '*from' to contain the address of the server from which 'msg' - * was recieved. + * was received. *\li 'msg' a message with opcode NOTIFY and qr clear. * * Returns: @@ -1036,7 +1085,7 @@ dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump); * If "dump" is ISC_TRUE, then the new zone contents are dumped * into to the zone's master file for persistence. When replacing * a zone database by one just loaded from a master file, set - * "dump" to ISC_FALSE to avoid a redunant redump of the data just + * "dump" to ISC_FALSE to avoid a redundant redump of the data just * loaded. Otherwise, it should be set to ISC_TRUE. * * If the "diff-on-reload" option is enabled in the configuration file, @@ -1048,7 +1097,7 @@ dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump); * * Returns: * \li DNS_R_SUCCESS - * \li DNS_R_BADZONE zone failed basic consistancy checks: + * \li DNS_R_BADZONE zone failed basic consistency checks: * * a single SOA must exist * * some NS records must exist. * Others @@ -1134,7 +1183,7 @@ dns_zone_getmgr(dns_zone_t *zone); void dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval); /*%< - * Set the zone's SIG validity interval. This is the length of time + * Set the zone's RRSIG validity interval. This is the length of time * for which DNSSEC signatures created as a result of dynamic updates * to secure zones will remain valid, in seconds. * @@ -1145,7 +1194,26 @@ dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval); isc_uint32_t dns_zone_getsigvalidityinterval(dns_zone_t *zone); /*%< - * Get the zone's SIG validity interval. + * Get the zone's RRSIG validity interval. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_setsigresigninginterval(dns_zone_t *zone, isc_uint32_t interval); +/*%< + * Set the zone's RRSIG re-signing interval. A dynamic zone's RRSIG's + * will be re-signed 'interval' amount of time before they expire. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +isc_uint32_t +dns_zone_getsigresigninginterval(dns_zone_t *zone); +/*%< + * Get the zone's RRSIG re-signing interval. * * Requires: * \li 'zone' to be a valid zone. @@ -1159,10 +1227,10 @@ dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype); isc_result_t dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg, - dns_updatecallback_t callback, void *callback_arg); + dns_updatecallback_t callback, void *callback_arg); /*%< * Forward 'msg' to each master in turn until we get an answer or we - * have exausted the list of masters. 'callback' will be called with + * have exhausted the list of masters. 'callback' will be called with * ISC_R_SUCCESS if we get an answer and the returned message will be * passed as 'answer_message', otherwise a non ISC_R_SUCCESS result code * will be passed and answer_message will be NULL. The callback function @@ -1195,6 +1263,8 @@ dns_zone_next(dns_zone_t *zone, dns_zone_t **next); * (result ISC_R_NOMORE). */ + + isc_result_t dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first); /*%< @@ -1267,7 +1337,7 @@ isc_result_t dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr); /*%< * Force zone maintenance of all zones managed by 'zmgr' at its - * earliest conveniene. + * earliest convenience. */ void @@ -1336,7 +1406,7 @@ dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, isc_uint32_t value); isc_uint32_t dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr); /*%< - * Return the the maximum number of simultaneous transfers in allowed. + * Return the maximum number of simultaneous transfers in allowed. * * Requires: *\li 'zmgr' to be a valid zone manager. @@ -1363,7 +1433,7 @@ dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr); void dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, isc_uint32_t iolimit); /*%< - * Set the number of simultaneous file descriptors available for + * Set the number of simultaneous file descriptors available for * reading and writing masterfiles. * * Requires: @@ -1374,7 +1444,7 @@ dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, isc_uint32_t iolimit); isc_uint32_t dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr); /*%< - * Get the number of simultaneous file descriptors available for + * Get the number of simultaneous file descriptors available for * reading and writing masterfiles. * * Requires: @@ -1410,6 +1480,18 @@ dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state); */ void +dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now); +/*%< + * Add the pair of addresses to the unreachable cache. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'remote' to be a valid sockaddr. + *\li 'local' to be a valid sockaddr. + */ + +void dns_zone_forcereload(dns_zone_t *zone); /*%< * Force a reload of specified zone. @@ -1430,22 +1512,55 @@ dns_zone_isforced(dns_zone_t *zone); isc_result_t dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on); /*%< - * Make the zone keep or not keep an array of statistics - * counter. - * - * Requires: - * \li zone be a valid zone. + * This function is obsoleted by dns_zone_setrequeststats(). */ isc_uint64_t * dns_zone_getstatscounters(dns_zone_t *zone); /*%< + * This function is obsoleted by dns_zone_getrequeststats(). + */ + +void +dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats); +/*%< + * Set a general zone-maintenance statistics set 'stats' for 'zone'. This + * function is expected to be called only on zone creation (when necessary). + * Once installed, it cannot be removed or replaced. Also, there is no + * interface to get the installed stats from the zone; the caller must keep the + * stats to reference (e.g. dump) it later. + * * Requires: - * zone be a valid zone. + * \li 'zone' to be a valid zone and does not have a statistics set already + * installed. + * + *\li stats is a valid statistics supporting zone statistics counters + * (see dns/stats.h). + */ + +void +dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats); +/*%< + * Set an additional statistics set to zone. It is attached in the zone + * but is not counted in the zone module; only the caller updates the counters. + * + * Requires: + * \li 'zone' to be a valid zone. + * + *\li stats is a valid statistics. + */ + +isc_stats_t * +dns_zone_getrequeststats(dns_zone_t *zone); +/*%< + * Get the additional statistics for zone, if one is installed. + * + * Requires: + * \li 'zone' to be a valid zone. * * Returns: - * \li A pointer to the zone's array of statistics counters, - * or NULL if it has none. + * \li when available, a pointer to the statistics set installed in zone; + * otherwise NULL. */ void @@ -1484,7 +1599,7 @@ void dns_zone_name(dns_zone_t *zone, char *buf, size_t len); /*%< * Return the name of the zone with class and view. - * + * * Requires: *\li 'zone' to be valid. *\li 'buf' to be non NULL. @@ -1492,7 +1607,7 @@ dns_zone_name(dns_zone_t *zone, char *buf, size_t len); isc_result_t dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata); -/* +/*%< * Check if this record meets the check-names policy. * * Requires: @@ -1508,7 +1623,7 @@ dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata); void dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache); -/* +/*%< * Associate the zone with an additional cache. * * Require: @@ -1521,7 +1636,7 @@ dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache); void dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx); -/* +/*%< * Set the post load integrity callback function 'checkmx'. * 'checkmx' will be called if the MX is not within the zone. * @@ -1531,7 +1646,7 @@ dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx); void dns_zone_setchecksrv(dns_zone_t *zone, dns_checkmxfunc_t checksrv); -/* +/*%< * Set the post load integrity callback function 'checksrv'. * 'checksrv' will be called if the SRV TARGET is not within the zone. * @@ -1541,7 +1656,7 @@ dns_zone_setchecksrv(dns_zone_t *zone, dns_checkmxfunc_t checksrv); void dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns); -/* +/*%< * Set the post load integrity callback function 'checkmx'. * 'checkmx' will be called if the MX is not within the zone. * @@ -1551,7 +1666,7 @@ dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns); void dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay); -/* +/*%< * Set the minimum delay between sets of notify messages. * * Requires: @@ -1560,7 +1675,7 @@ dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay); isc_uint32_t dns_zone_getnotifydelay(dns_zone_t *zone); -/* +/*%< * Get the minimum delay between sets of notify messages. * * Requires: @@ -1569,7 +1684,7 @@ dns_zone_getnotifydelay(dns_zone_t *zone); void dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg); -/* +/*%< * Set the isself callback function and argument. * * isc_boolean_t @@ -1581,6 +1696,41 @@ dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg); * delivered to 'myview'. */ +void +dns_zone_setnodes(dns_zone_t *zone, isc_uint32_t nodes); +/*%< + * Set the number of nodes that will be checked per quantum. + */ + +void +dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures); +/*%< + * Set the number of signatures that will be generated per quantum. + */ + +isc_result_t +dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, + isc_uint16_t keyid, isc_boolean_t delete); +/*%< + * Initiate/resume signing of the entire zone with the zone DNSKEY(s) + * that match the given algorithm and keyid. + */ + +isc_result_t +dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param); +/*%< + * Incrementally add a NSEC3 chain that corresponds to 'nsec3param'. + */ + +void +dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type); +dns_rdatatype_t +dns_zone_getprivatetype(dns_zone_t *zone); +/* + * Get/Set the private record type. It is expected that these interfaces + * will not be permanent. + */ + ISC_LANG_ENDDECLS #endif /* DNS_ZONE_H */ diff --git a/lib/dns/include/dns/zonekey.h b/lib/dns/include/dns/zonekey.h index ba4e076..d9ba862 100644 --- a/lib/dns/include/dns/zonekey.h +++ b/lib/dns/include/dns/zonekey.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zonekey.h,v 1.4.18.2 2005/04/29 00:16:26 marka Exp $ */ +/* $Id: zonekey.h,v 1.10 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_ZONEKEY_H #define DNS_ZONEKEY_H 1 -/*! \file */ +/*! \file dns/zonekey.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dns/zt.h b/lib/dns/include/dns/zt.h index 436ef4c..6cfe3d3 100644 --- a/lib/dns/include/dns/zt.h +++ b/lib/dns/include/dns/zt.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zt.h,v 1.30.18.3 2005/04/27 05:01:42 sra Exp $ */ +/* $Id: zt.h,v 1.38 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_ZT_H #define DNS_ZT_H 1 -/*! \file */ +/*! \file dns/zt.h */ #include <isc/lang.h> diff --git a/lib/dns/include/dst/Makefile.in b/lib/dns/include/dst/Makefile.in index deaa221..4ed4ec0 100644 --- a/lib/dns/include/dst/Makefile.in +++ b/lib/dns/include/dst/Makefile.in @@ -1,7 +1,7 @@ -# Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2001 Internet Software Consortium. # -# Permission to use, copy, modify, and distribute this software for any +# 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. # @@ -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.1.6.1 2004/12/09 04:41:47 marka Exp $ +# $Id: Makefile.in,v 1.4 2007/12/11 20:28:55 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -21,7 +21,7 @@ top_srcdir = @top_srcdir@ @BIND9_VERSION@ -HEADERS = dst.h lib.h result.h +HEADERS = dst.h gssapi.h lib.h result.h SUBDIRS = TARGETS = diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 8d99186..702ad71 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,17 +15,19 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst.h,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ */ +/* $Id: dst.h,v 1.12 2008/09/24 02:46:23 marka Exp $ */ #ifndef DST_DST_H #define DST_DST_H 1 -/*! \file */ +/*! \file dst/dst.h */ #include <isc/lang.h> #include <dns/types.h> +#include <dst/gssapi.h> + ISC_LANG_BEGINDECLS /*** @@ -49,6 +51,8 @@ typedef struct dst_context dst_context_t; #define DST_ALG_DSA 3 #define DST_ALG_ECC 4 #define DST_ALG_RSASHA1 5 +#define DST_ALG_NSEC3DSA 6 +#define DST_ALG_NSEC3RSASHA1 7 #define DST_ALG_HMACMD5 157 #define DST_ALG_GSSAPI 160 #define DST_ALG_HMACSHA1 161 /* XXXMPA */ @@ -398,16 +402,28 @@ dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer); *\li If successful, key will contain a valid private key. */ +gss_ctx_id_t +dst_key_getgssctx(const dst_key_t *key); +/*%< + * Returns the opaque key data. + * Be cautions when using this value unless you know what you are doing. + * + * Requires: + *\li "key" is not NULL. + * + * Returns: + *\li gssctx key data, possibly NULL. + */ isc_result_t -dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx, - dst_key_t **keyp); +dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, + dst_key_t **keyp); /*%< * Converts a GSSAPI opaque context id into a DST key. * * Requires: *\li "name" is a valid absolute dns name. - *\li "opaque" is a GSSAPI context id. + *\li "gssctx" is a GSSAPI context id. *\li "mctx" is a valid memory context. *\li "keyp" is not NULL and "*keyp" is NULL. * @@ -421,6 +437,12 @@ dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx, */ isc_result_t +dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + const char *engine, const char *label, const char *pin, + isc_mem_t *mctx, dst_key_t **keyp); + +isc_result_t dst_key_generate(dns_name_t *name, unsigned int alg, unsigned int bits, unsigned int param, unsigned int flags, unsigned int protocol, diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h index e30fb0c..446b76d 100644 --- a/lib/dns/include/dst/gssapi.h +++ b/lib/dns/include/dst/gssapi.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,16 +15,32 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gssapi.h,v 1.1.6.3 2005/04/29 00:16:28 marka Exp $ */ +/* $Id: gssapi.h,v 1.9.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef DST_GSSAPI_H #define DST_GSSAPI_H 1 -/*! \file */ +/*! \file dst/gssapi.h */ +#include <isc/formatcheck.h> #include <isc/lang.h> - +#include <isc/platform.h> #include <isc/types.h> +#include <dns/types.h> + +#ifdef GSSAPI +#ifdef _WINDOWS +/* + * MSVC does not like macros in #include lines. + */ +#include <gssapi/gssapi.h> +#else +#include ISC_PLATFORM_GSSAPIHEADER +#endif +#ifndef GSS_SPNEGO_MECHANISM +#define GSS_SPNEGO_MECHANISM ((void*)0) +#endif +#endif ISC_LANG_BEGINDECLS @@ -37,20 +53,153 @@ ISC_LANG_BEGINDECLS ***/ isc_result_t -dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred); +dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, + gss_cred_id_t *cred); +/* + * Acquires GSS credentials. + * + * Requires: + * 'name' is a valid name, preferably one known by the GSS provider + * 'initiate' indicates whether the credentials are for initiating or + * accepting contexts + * 'cred' is a pointer to NULL, which will be allocated with the + * credential handle. Call dst_gssapi_releasecred to free + * the memory. + * + * Returns: + * ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + * other an error occurred while building the message + */ + +isc_result_t +dst_gssapi_releasecred(gss_cred_id_t *cred); +/* + * Releases GSS credentials. Calling this function does release the + * memory allocated for the credential in dst_gssapi_acquirecred() + * + * Requires: + * 'mctx' is a valid memory context + * 'cred' is a pointer to the credential to be released + * + * Returns: + * ISC_R_SUCCESS credential was released successfully + * other an error occurred while releaseing + * the credential + */ + +isc_result_t +dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, + isc_buffer_t *outtoken, gss_ctx_id_t *gssctx); +/* + * Initiates a GSS context. + * + * Requires: + * 'name' is a valid name, preferably one known by the GSS + * provider + * 'intoken' is a token received from the acceptor, or NULL if + * there isn't one + * 'outtoken' is a buffer to receive the token generated by + * gss_init_sec_context() to be sent to the acceptor + * 'context' is a pointer to a valid gss_ctx_id_t + * (which may have the value GSS_C_NO_CONTEXT) + * + * Returns: + * ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + * other an error occurred while building the message + */ isc_result_t -dst_gssapi_initctx(dns_name_t *name, void *cred, - isc_region_t *intoken, isc_buffer_t *outtoken, - void **context); +dst_gssapi_acceptctx(gss_cred_id_t cred, + isc_region_t *intoken, isc_buffer_t **outtoken, + gss_ctx_id_t *context, dns_name_t *principal, + isc_mem_t *mctx); +/* + * Accepts a GSS context. + * + * Requires: + * 'mctx' is a valid memory context + * 'cred' is the acceptor's valid GSS credential handle + * 'intoken' is a token received from the initiator + * 'outtoken' is a pointer a buffer pointer used to return the token + * generated by gss_accept_sec_context() to be sent to the + * initiator + * 'context' is a valid pointer to receive the generated context handle. + * On the initial call, it should be a pointer to NULL, which + * will be allocated as a gss_ctx_id_t. Subsequent calls + * should pass in the handle generated on the first call. + * Call dst_gssapi_releasecred to delete the context and free + * the memory. + * + * Requires: + * 'outtoken' to != NULL && *outtoken == NULL. + * + * Returns: + * ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + * other an error occurred while building the message + */ isc_result_t -dst_gssapi_acceptctx(dns_name_t *name, void *cred, - isc_region_t *intoken, isc_buffer_t *outtoken, - void **context); +dst_gssapi_deletectx(isc_mem_t *mctx, gss_ctx_id_t *gssctx); +/* + * Destroys a GSS context. This function deletes the context from the GSS + * provider and then frees the memory used by the context pointer. + * + * Requires: + * 'mctx' is a valid memory context + * 'context' is a valid GSS context + * + * Returns: + * ISC_R_SUCCESS + */ + + +void +gss_log(int level, const char *fmt, ...) +ISC_FORMAT_PRINTF(2, 3); +/* + * Logging function for GSS. + * + * Requires + * 'level' is the log level to be used, as an integer + * 'fmt' is a printf format specifier + */ + +char * +gss_error_tostring(isc_uint32_t major, isc_uint32_t minor, + char *buf, size_t buflen); +/* + * Render a GSS major status/minor status pair into a string + * + * Requires: + * 'major' is a GSS major status code + * 'minor' is a GSS minor status code + * + * Returns: + * A string containing the text representation of the error codes. + * Users should copy the string if they wish to keep it. + */ +isc_boolean_t +dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name, + dns_name_t *realm); /* - * XXX + * Compare a "signer" (in the format of a Kerberos-format Kerberos5 + * principal: host/example.com@EXAMPLE.COM) to the realm name stored + * in "name" (which represents the realm name). + * + */ + +isc_boolean_t +dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, + dns_name_t *realm); +/* + * Compare a "signer" (in the format of a Kerberos-format Kerberos5 + * principal: host/example.com@EXAMPLE.COM) to the realm name stored + * in "name" (which represents the realm name). + * */ ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dst/lib.h b/lib/dns/include/dst/lib.h index bd71261..886575e 100644 --- a/lib/dns/include/dst/lib.h +++ b/lib/dns/include/dst/lib.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.h,v 1.1.6.3 2005/04/29 00:16:29 marka Exp $ */ +/* $Id: lib.h,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DST_LIB_H #define DST_LIB_H 1 -/*! \file */ +/*! \file dst/lib.h */ #include <isc/types.h> #include <isc/lang.h> diff --git a/lib/dns/include/dst/result.h b/lib/dns/include/dst/result.h index aa03b73..d77b72e 100644 --- a/lib/dns/include/dst/result.h +++ b/lib/dns/include/dst/result.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.1.6.3 2005/04/29 00:16:29 marka Exp $ */ +/* $Id: result.h,v 1.9 2008/04/01 23:47:10 tbox Exp $ */ #ifndef DST_RESULT_H #define DST_RESULT_H 1 -/*! \file */ +/*! \file dst/result.h */ #include <isc/lang.h> #include <isc/resultclass.h> @@ -54,8 +54,9 @@ #define DST_R_COMPUTESECRETFAILURE (ISC_RESULTCLASS_DST + 18) #define DST_R_NORANDOMNESS (ISC_RESULTCLASS_DST + 19) #define DST_R_BADKEYTYPE (ISC_RESULTCLASS_DST + 20) +#define DST_R_NOENGINE (ISC_RESULTCLASS_DST + 21) -#define DST_R_NRESULTS 21 /* Number of results */ +#define DST_R_NRESULTS 22 /* Number of results */ ISC_LANG_BEGINDECLS diff --git a/lib/dns/iptable.c b/lib/dns/iptable.c new file mode 100644 index 0000000..55a5351 --- /dev/null +++ b/lib/dns/iptable.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2007-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: iptable.c,v 1.12.44.3 2009/02/18 23:47:12 tbox Exp $ */ + +#include <config.h> + +#include <isc/mem.h> +#include <isc/radix.h> + +#include <dns/acl.h> + +static void destroy_iptable(dns_iptable_t *dtab); + +/* + * Create a new IP table and the underlying radix structure + */ +isc_result_t +dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target) { + isc_result_t result; + dns_iptable_t *tab; + + tab = isc_mem_get(mctx, sizeof(*tab)); + if (tab == NULL) + return (ISC_R_NOMEMORY); + tab->mctx = mctx; + isc_refcount_init(&tab->refcount, 1); + tab->radix = NULL; + tab->magic = DNS_IPTABLE_MAGIC; + + result = isc_radix_create(mctx, &tab->radix, RADIX_MAXBITS); + if (result != ISC_R_SUCCESS) + goto cleanup; + + *target = tab; + return (ISC_R_SUCCESS); + + cleanup: + dns_iptable_detach(&tab); + return (result); +} + +isc_boolean_t dns_iptable_neg = ISC_FALSE; +isc_boolean_t dns_iptable_pos = ISC_TRUE; + +/* + * Add an IP prefix to an existing IP table + */ +isc_result_t +dns_iptable_addprefix(dns_iptable_t *tab, isc_netaddr_t *addr, + isc_uint16_t bitlen, isc_boolean_t pos) +{ + isc_result_t result; + isc_prefix_t pfx; + isc_radix_node_t *node = NULL; + int family; + + INSIST(DNS_IPTABLE_VALID(tab)); + INSIST(tab->radix); + + NETADDR_TO_PREFIX_T(addr, pfx, bitlen); + + result = isc_radix_insert(tab->radix, &node, NULL, &pfx); + if (result != ISC_R_SUCCESS) { + isc_refcount_destroy(&pfx.refcount); + return(result); + } + + /* If a node already contains data, don't overwrite it */ + family = pfx.family; + if (family == AF_UNSPEC) { + /* "any" or "none" */ + INSIST(pfx.bitlen == 0); + if (pos) { + if (node->data[0] == NULL) + node->data[0] = &dns_iptable_pos; + if (node->data[1] == NULL) + node->data[1] = &dns_iptable_pos; + } else { + if (node->data[0] == NULL) + node->data[0] = &dns_iptable_neg; + if (node->data[1] == NULL) + node->data[1] = &dns_iptable_neg; + } + } else { + /* any other prefix */ + if (node->data[ISC_IS6(family)] == NULL) { + if (pos) + node->data[ISC_IS6(family)] = &dns_iptable_pos; + else + node->data[ISC_IS6(family)] = &dns_iptable_neg; + } + } + + isc_refcount_destroy(&pfx.refcount); + return (ISC_R_SUCCESS); +} + +/* + * Merge one IP table into another one. + */ +isc_result_t +dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, isc_boolean_t pos) +{ + isc_result_t result; + isc_radix_node_t *node, *new_node; + int max_node = 0; + + RADIX_WALK (source->radix->head, node) { + new_node = NULL; + result = isc_radix_insert (tab->radix, &new_node, node, NULL); + + if (result != ISC_R_SUCCESS) + return(result); + + /* + * If we're negating a nested ACL, then we should + * reverse the sense of every node. However, this + * could lead to a negative node in a nested ACL + * becoming a positive match in the parent, which + * could be a security risk. To prevent this, we + * just leave the negative nodes negative. + */ + if (!pos) { + if (node->data[0] && + *(isc_boolean_t *) node->data[0] == ISC_TRUE) + new_node->data[0] = &dns_iptable_neg; + + if (node->data[1] && + *(isc_boolean_t *) node->data[1] == ISC_TRUE) + new_node->data[1] = &dns_iptable_neg; + } + + if (node->node_num[0] > max_node) + max_node = node->node_num[0]; + if (node->node_num[1] > max_node) + max_node = node->node_num[1]; + } RADIX_WALK_END; + + tab->radix->num_added_node += max_node; + return (ISC_R_SUCCESS); +} + +void +dns_iptable_attach(dns_iptable_t *source, dns_iptable_t **target) { + REQUIRE(DNS_IPTABLE_VALID(source)); + isc_refcount_increment(&source->refcount, NULL); + *target = source; +} + +void +dns_iptable_detach(dns_iptable_t **tabp) { + dns_iptable_t *tab = *tabp; + unsigned int refs; + REQUIRE(DNS_IPTABLE_VALID(tab)); + isc_refcount_decrement(&tab->refcount, &refs); + if (refs == 0) + destroy_iptable(tab); + *tabp = NULL; +} + +static void +destroy_iptable(dns_iptable_t *dtab) { + + REQUIRE(DNS_IPTABLE_VALID(dtab)); + + if (dtab->radix != NULL) { + isc_radix_destroy(dtab->radix, NULL); + dtab->radix = NULL; + } + + isc_refcount_destroy(&dtab->refcount); + dtab->magic = 0; + isc_mem_put(dtab->mctx, dtab, sizeof(*dtab)); +} diff --git a/lib/dns/journal.c b/lib/dns/journal.c index 4e4010f..8c21f1e 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.c,v 1.86.18.14 2008/09/25 04:01:36 tbox Exp $ */ +/* $Id: journal.c,v 1.103.48.2 2009/01/18 23:47:37 tbox Exp $ */ #include <config.h> @@ -42,7 +42,7 @@ #include <dns/soa.h> /*! \file - * \brief Journalling. + * \brief Journaling. * * A journal file consists of * @@ -172,7 +172,7 @@ dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, return (result); } -/* Journalling */ +/* Journaling */ /*% * On-disk representation of a "pointer" to a journal entry. @@ -641,7 +641,7 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, dns_rdata_init(&j->it.rdata); /* - * Set up empty initial buffers for uncheched and checked + * Set up empty initial buffers for unchecked and checked * wire format RR data. They will be reallocated * later. */ @@ -709,8 +709,35 @@ ixfr_order(const void *av, const void *bv) { dns_difftuple_t const *a = *ap; dns_difftuple_t const *b = *bp; int r; + int bop = 0, aop = 0; + + switch (a->op) { + case DNS_DIFFOP_DEL: + case DNS_DIFFOP_DELRESIGN: + aop = 1; + break; + case DNS_DIFFOP_ADD: + case DNS_DIFFOP_ADDRESIGN: + aop = 0; + break; + default: + INSIST(0); + } + + switch (b->op) { + case DNS_DIFFOP_DEL: + case DNS_DIFFOP_DELRESIGN: + bop = 1; + break; + case DNS_DIFFOP_ADD: + case DNS_DIFFOP_ADDRESIGN: + bop = 0; + break; + default: + INSIST(0); + } - r = (b->op == DNS_DIFFOP_DEL) - (a->op == DNS_DIFFOP_DEL); + r = bop - aop; if (r != 0) return (r); @@ -1191,7 +1218,7 @@ dns_journal_destroy(dns_journal_t **journalp) { /* XXX Share code with incoming IXFR? */ static isc_result_t -roll_forward(dns_journal_t *j, dns_db_t *db) { +roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) { isc_buffer_t source; /* Transaction data from disk */ isc_buffer_t target; /* Ditto after _fromwire check */ isc_uint32_t db_serial; /* Database SOA serial */ @@ -1202,6 +1229,7 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { dns_diff_t diff; unsigned int n_soa = 0; unsigned int n_put = 0; + dns_diffop_t op; REQUIRE(DNS_JOURNAL_VALID(j)); REQUIRE(DNS_DB_VALID(db)); @@ -1209,7 +1237,7 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { dns_diff_init(j->mctx, &diff); /* - * Set up empty initial buffers for uncheched and checked + * Set up empty initial buffers for unchecked and checked * wire format transaction data. They will be reallocated * later. */ @@ -1273,9 +1301,14 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { "initial SOA", j->filename); FAIL(ISC_R_UNEXPECTED); } - CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ? - DNS_DIFFOP_DEL : DNS_DIFFOP_ADD, - name, ttl, rdata, &tuple)); + if ((options & DNS_JOURNALOPT_RESIGN) != 0) + op = (n_soa == 1) ? DNS_DIFFOP_DELRESIGN : + DNS_DIFFOP_ADDRESIGN; + else + op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD; + + CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata, + &tuple)); dns_diff_append(&diff, &tuple); if (++n_put > 100) { @@ -1317,7 +1350,9 @@ roll_forward(dns_journal_t *j, dns_db_t *db) { } isc_result_t -dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) { +dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, + unsigned int options, const char *filename) +{ dns_journal_t *j; isc_result_t result; @@ -1336,7 +1371,7 @@ dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) { if (JOURNAL_EMPTY(&j->header)) result = DNS_R_UPTODATE; else - result = roll_forward(j, db); + result = roll_forward(j, db, options); dns_journal_destroy(&j); @@ -1374,7 +1409,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) { dns_diff_init(j->mctx, &diff); /* - * Set up empty initial buffers for uncheched and checked + * Set up empty initial buffers for unchecked and checked * wire format transaction data. They will be reallocated * later. */ @@ -1852,10 +1887,10 @@ dns_db_diff(isc_mem_t *mctx, if (result != ISC_R_SUCCESS) return (result); - result = dns_db_createiterator(db[0], ISC_FALSE, &dbit[0]); + result = dns_db_createiterator(db[0], 0, &dbit[0]); if (result != ISC_R_SUCCESS) goto cleanup_journal; - result = dns_db_createiterator(db[1], ISC_FALSE, &dbit[1]); + result = dns_db_createiterator(db[1], 0, &dbit[1]); if (result != ISC_R_SUCCESS) goto cleanup_interator0; diff --git a/lib/dns/key.c b/lib/dns/key.c index b0f2c0a..5cf4442 100644 --- a/lib/dns/key.c +++ b/lib/dns/key.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: key.c,v 1.1.6.6 2006/01/27 23:57:44 marka Exp $ */ +/* $Id: key.c,v 1.8 2007/06/19 23:47:16 tbox Exp $ */ #include <config.h> diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c index ec0f8e4..bffd2d3 100644 --- a/lib/dns/keytable.c +++ b/lib/dns/keytable.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keytable.c,v 1.28.18.4 2005/12/05 00:00:03 marka Exp $ */ +/* $Id: keytable.c,v 1.34 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/lib.c b/lib/dns/lib.c index 423908a..6f98b537 100644 --- a/lib/dns/lib.c +++ b/lib/dns/lib.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.c,v 1.11.18.3 2005/08/15 01:46:50 marka Exp $ */ +/* $Id: lib.c,v 1.16 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/log.c b/lib/dns/log.c index 939ea36..7551e15 100644 --- a/lib/dns/log.c +++ b/lib/dns/log.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.c,v 1.36.18.4 2005/09/05 00:18:24 marka Exp $ */ +/* $Id: log.c,v 1.45 2007/06/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -29,7 +29,7 @@ /*% * When adding a new category, be sure to add the appropriate - * #define to <dns/log.h>. + * \#define to <dns/log.h>. */ LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = { { "notify", 0 }, @@ -43,12 +43,13 @@ LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = { { "dispatch", 0 }, { "lame-servers", 0 }, { "delegation-only", 0 }, + { "edns-disabled", 0 }, { NULL, 0 } }; /*% * When adding a new module, be sure to add the appropriate - * #define to <dns/log.h>. + * \#define to <dns/log.h>. */ LIBDNS_EXTERNAL_DATA isc_logmodule_t dns_modules[] = { { "dns/db", 0 }, diff --git a/lib/dns/lookup.c b/lib/dns/lookup.c index a3ddad4..d5fc7aa 100644 --- a/lib/dns/lookup.c +++ b/lib/dns/lookup.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lookup.c,v 1.14.18.7 2007/08/28 07:20:04 tbox Exp $ */ +/* $Id: lookup.c,v 1.21 2007/06/18 23:47:40 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/master.c b/lib/dns/master.c index b04f2eb..462269e 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.c,v 1.148.18.21 2008/01/17 23:45:58 tbox Exp $ */ +/* $Id: master.c,v 1.171.120.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -139,6 +139,7 @@ struct dns_loadctx { /* locked by lock */ isc_uint32_t references; dns_incctx_t *inc; + isc_uint32_t resign; }; struct dns_incctx { @@ -503,7 +504,7 @@ incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) { static isc_result_t loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, - unsigned int options, dns_name_t *top, + unsigned int options, isc_uint32_t resign, dns_name_t *top, dns_rdataclass_t zclass, dns_name_t *origin, dns_rdatacallbacks_t *callbacks, isc_task_t *task, dns_loaddonefunc_t done, void *done_arg, isc_lex_t *lex, @@ -580,6 +581,7 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, lctx->options = options; lctx->seen_include = ISC_FALSE; lctx->zclass = zclass; + lctx->resign = resign; lctx->result = ISC_R_SUCCESS; dns_fixedname_init(&lctx->fixed_top); @@ -1738,8 +1740,7 @@ load_text(dns_loadctx_t *lctx) { char namebuf[DNS_NAME_FORMATSIZE]; dns_name_format(ictx->current, namebuf, sizeof(namebuf)); - (*callbacks->error)(callbacks, - "%s:%lu: SOA " + (*callbacks->error)(callbacks, "%s:%lu: SOA " "record not at top of zone (%s)", source, line, namebuf); result = DNS_R_NOTZONETOP; @@ -1834,7 +1835,7 @@ load_text(dns_loadctx_t *lctx) { /* * Find type in rdatalist. * If it does not exist create new one and prepend to list - * as this will mimimise list traversal. + * as this will minimise list traversal. */ if (ictx->glue != NULL) this = ISC_LIST_HEAD(glue_list); @@ -2324,8 +2325,8 @@ dns_master_loadfile(const char *master_file, dns_name_t *top, dns_rdataclass_t zclass, unsigned int options, dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx) { - return (dns_master_loadfile2(master_file, top, origin, zclass, options, - callbacks, mctx, dns_masterformat_text)); + return (dns_master_loadfile3(master_file, top, origin, zclass, options, + 0, callbacks, mctx, dns_masterformat_text)); } isc_result_t @@ -2335,11 +2336,23 @@ dns_master_loadfile2(const char *master_file, dns_name_t *top, dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx, dns_masterformat_t format) { + return (dns_master_loadfile3(master_file, top, origin, zclass, options, + 0, callbacks, mctx, format)); +} + +isc_result_t +dns_master_loadfile3(const char *master_file, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx, + dns_masterformat_t format) +{ dns_loadctx_t *lctx = NULL; isc_result_t result; - result = loadctx_create(format, mctx, options, top, zclass, origin, - callbacks, NULL, NULL, NULL, NULL, &lctx); + result = loadctx_create(format, mctx, options, resign, top, zclass, + origin, callbacks, NULL, NULL, NULL, NULL, + &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2362,8 +2375,8 @@ dns_master_loadfileinc(const char *master_file, dns_name_t *top, isc_task_t *task, dns_loaddonefunc_t done, void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx) { - return (dns_master_loadfileinc2(master_file, top, origin, zclass, - options, callbacks, task, done, + return (dns_master_loadfileinc3(master_file, top, origin, zclass, + options, 0, callbacks, task, done, done_arg, lctxp, mctx, dns_masterformat_text)); } @@ -2376,14 +2389,29 @@ dns_master_loadfileinc2(const char *master_file, dns_name_t *top, void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx, dns_masterformat_t format) { + return (dns_master_loadfileinc3(master_file, top, origin, zclass, + options, 0, callbacks, task, done, + done_arg, lctxp, mctx, format)); +} + +isc_result_t +dns_master_loadfileinc3(const char *master_file, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, isc_uint32_t resign, + dns_rdatacallbacks_t *callbacks, isc_task_t *task, + dns_loaddonefunc_t done, void *done_arg, + dns_loadctx_t **lctxp, isc_mem_t *mctx, + dns_masterformat_t format) +{ dns_loadctx_t *lctx = NULL; isc_result_t result; REQUIRE(task != NULL); REQUIRE(done != NULL); - result = loadctx_create(format, mctx, options, top, zclass, origin, - callbacks, task, done, done_arg, NULL, &lctx); + result = loadctx_create(format, mctx, options, resign, top, zclass, + origin, callbacks, task, done, done_arg, NULL, + &lctx); if (result != ISC_R_SUCCESS) return (result); @@ -2412,7 +2440,7 @@ dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin, REQUIRE(stream != NULL); - result = loadctx_create(dns_masterformat_text, mctx, options, top, + result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, NULL, NULL, NULL, NULL, &lctx); if (result != ISC_R_SUCCESS) @@ -2445,7 +2473,7 @@ dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin, REQUIRE(task != NULL); REQUIRE(done != NULL); - result = loadctx_create(dns_masterformat_text, mctx, options, top, + result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, task, done, done_arg, NULL, &lctx); if (result != ISC_R_SUCCESS) @@ -2478,7 +2506,7 @@ dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top, REQUIRE(buffer != NULL); - result = loadctx_create(dns_masterformat_text, mctx, options, top, + result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, NULL, NULL, NULL, NULL, &lctx); if (result != ISC_R_SUCCESS) @@ -2511,7 +2539,7 @@ dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top, REQUIRE(task != NULL); REQUIRE(done != NULL); - result = loadctx_create(dns_masterformat_text, mctx, options, top, + result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, task, done, done_arg, NULL, &lctx); if (result != ISC_R_SUCCESS) @@ -2543,7 +2571,7 @@ dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top, REQUIRE(lex != NULL); - result = loadctx_create(dns_masterformat_text, mctx, options, top, + result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, NULL, NULL, NULL, lex, &lctx); if (result != ISC_R_SUCCESS) @@ -2571,7 +2599,7 @@ dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top, REQUIRE(task != NULL); REQUIRE(done != NULL); - result = loadctx_create(dns_masterformat_text, mctx, options, top, + result = loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass, origin, callbacks, task, done, done_arg, lex, &lctx); if (result != ISC_R_SUCCESS) @@ -2700,6 +2728,27 @@ grow_rdata(int new_len, dns_rdata_t *old, int old_len, return (new); } +static isc_uint32_t +resign_fromlist(dns_rdatalist_t *this, isc_uint32_t resign) { + dns_rdata_t *rdata; + dns_rdata_rrsig_t sig; + isc_uint32_t when; + + rdata = ISC_LIST_HEAD(this->rdata); + INSIST(rdata != NULL); + (void)dns_rdata_tostruct(rdata, &sig, NULL); + when = sig.timeexpire - resign; + + rdata = ISC_LIST_NEXT(rdata, link); + while (rdata != NULL) { + (void)dns_rdata_tostruct(rdata, &sig, NULL); + if (sig.timeexpire - resign < when) + when = sig.timeexpire - resign; + rdata = ISC_LIST_NEXT(rdata, link); + } + return (when); +} + /* * Convert each element from a rdatalist_t to rdataset then call commit. * Unlink each element as we go. @@ -2726,14 +2775,22 @@ commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx, RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset) == ISC_R_SUCCESS); dataset.trust = dns_trust_ultimate; + /* + * If this is a secure dynamic zone set the re-signing time. + */ + if (dataset.type == dns_rdatatype_rrsig && + (lctx->options & DNS_MASTER_RESIGN) != 0) { + dataset.attributes |= DNS_RDATASETATTR_RESIGN; + dns_name_format(owner, namebuf, sizeof(namebuf)); + dataset.resign = resign_fromlist(this, lctx->resign); + } result = ((*callbacks->add)(callbacks->add_private, owner, &dataset)); if (result == ISC_R_NOMEMORY) { (*error)(callbacks, "dns_master_load: %s", dns_result_totext(result)); } else if (result != ISC_R_SUCCESS) { - dns_name_format(owner, namebuf, - sizeof(namebuf)); + dns_name_format(owner, namebuf, sizeof(namebuf)); if (source != NULL) { (*error)(callbacks, "%s: %s:%lu: %s: %s", "dns_master_load", source, line, diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 1ffdfcb..5eac96f 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.c,v 1.73.18.16 2008/08/13 23:46:04 tbox Exp $ */ +/* $Id: masterdump.c,v 1.94.50.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -108,7 +108,8 @@ dns_master_style_default = { LIBDNS_EXTERNAL_DATA const dns_master_style_t dns_master_style_full = { - DNS_STYLEFLAG_COMMENT, + DNS_STYLEFLAG_COMMENT | + DNS_STYLEFLAG_RESIGN, 46, 46, 46, 64, 120, 8 }; @@ -283,7 +284,7 @@ totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) { /* * Do not return ISC_R_NOSPACE if the line break string * buffer is too small, because that would just make - * dump_rdataset() retry indenfinitely with ever + * dump_rdataset() retry indefinitely with ever * bigger target buffers. That's a different buffer, * so it won't help. Use DNS_R_TEXTTOOLONG as a substitute. */ @@ -784,6 +785,13 @@ static const char *trustnames[] = { "local" /* aka ultimate */ }; +const char * +dns_trust_totext(dns_trust_t trust) { + if (trust >= sizeof(trustnames)/sizeof(*trustnames)) + return ("bad"); + return (trustnames[trust]); +} + static isc_result_t dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name, dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, @@ -840,6 +848,15 @@ dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name, if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0) name = NULL; } + if (ctx->style.flags & DNS_STYLEFLAG_RESIGN && + rds->attributes & DNS_RDATASETATTR_RESIGN) { + isc_buffer_t b; + char buf[sizeof("YYYYMMDDHHMMSS")]; + memset(buf, 0, sizeof(buf)); + isc_buffer_init(&b, buf, sizeof(buf) - 1); + dns_time64_totext((isc_uint64_t)rds->resign, &b); + fprintf(f, "; resign=%s\n", buf); + } dns_rdataset_disassociate(rds); } @@ -1020,9 +1037,9 @@ dumpctx_destroy(dns_dumpctx_t *dctx) { dctx->magic = 0; DESTROYLOCK(&dctx->lock); + dns_dbiterator_destroy(&dctx->dbiter); if (dctx->version != NULL) dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); - dns_dbiterator_destroy(&dctx->dbiter); dns_db_detach(&dctx->db); if (dctx->task != NULL) isc_task_detach(&dctx->task); @@ -1177,7 +1194,7 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, { dns_dumpctx_t *dctx; isc_result_t result; - isc_boolean_t relative; + unsigned int options; dctx = isc_mem_get(mctx, sizeof(*dctx)); if (dctx == NULL) @@ -1224,10 +1241,10 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, if (dctx->format == dns_masterformat_text && (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) { - relative = ISC_TRUE; + options = DNS_DB_RELATIVENAMES; } else - relative = ISC_FALSE; - result = dns_db_createiterator(dctx->db, relative, &dctx->dbiter); + options = 0; + result = dns_db_createiterator(dctx->db, options, &dctx->dbiter); if (result != ISC_R_SUCCESS) goto cleanup; diff --git a/lib/dns/message.c b/lib/dns/message.c index 8c56377..b541635 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.c,v 1.222.18.16 2008/07/28 23:46:20 tbox Exp $ */ +/* $Id: message.c,v 1.245.50.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -24,6 +24,7 @@ ***/ #include <config.h> +#include <ctype.h> #include <isc/buffer.h> #include <isc/mem.h> @@ -45,6 +46,35 @@ #include <dns/tsig.h> #include <dns/view.h> +#ifdef SKAN_MSG_DEBUG +static void +hexdump(const char *msg, const char *msg2, void *base, size_t len) { + unsigned char *p; + unsigned int cnt; + + p = base; + cnt = 0; + + printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base); + + while (cnt < len) { + if (cnt % 16 == 0) + printf("%p: ", p); + else if (cnt % 8 == 0) + printf(" |"); + printf(" %02x %c", *p, (isprint(*p) ? *p : ' ')); + p++; + cnt++; + + if (cnt % 16 == 0) + printf("\n"); + } + + if (cnt % 16 != 0) + printf("\n"); +} +#endif + #define DNS_MESSAGE_OPCODE_MASK 0x7800U #define DNS_MESSAGE_OPCODE_SHIFT 11 #define DNS_MESSAGE_RCODE_MASK 0x000fU @@ -65,6 +95,8 @@ #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \ && ((s) < DNS_PSEUDOSECTION_MAX)) +#define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0) + /*% * This is the size of each individual scratchpad buffer, and the numbers * of various block allocations used within the server. @@ -138,7 +170,7 @@ static const char *rcodetext[] = { /*% * "helper" type, which consists of a block of some type, and is linkable. * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer - * size, or the allocated elements will not be alligned correctly. + * size, or the allocated elements will not be aligned correctly. */ struct dns_msgblock { unsigned int count; @@ -1462,14 +1494,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, rdataset->ttl = ttl; } - /* - * XXXMLG Perform a totally ugly hack here to pull - * the rdatalist out of the private field in the rdataset, - * and append this rdata to the rdatalist's linked list - * of rdata. - */ - rdatalist = (dns_rdatalist_t *)(rdataset->private1); - + /* Append this rdata to the rdataset. */ + dns_rdatalist_fromrdataset(rdataset, &rdatalist); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); /* @@ -1934,7 +1960,7 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, * * XXXMLG Need to change this when * dns_rdataset_towire() can render partial - * sets starting at some arbitary point in the + * sets starting at some arbitrary point in the * set. This will include setting a bit in the * rdataset to indicate that a partial * rendering was done, and some state saved @@ -1964,6 +1990,8 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, (sectionid == DNS_SECTION_ANSWER || sectionid == DNS_SECTION_AUTHORITY)) msg->flags &= ~DNS_MESSAGEFLAG_AD; + if (OPTOUT(rdataset)) + msg->flags &= ~DNS_MESSAGEFLAG_AD; rdataset->attributes |= DNS_RDATASETATTR_RENDERED; @@ -2899,6 +2927,35 @@ dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) { return (dns_message_checksig(msg, view)); } +#ifdef SKAN_MSG_DEBUG +void +dns_message_dumpsig(dns_message_t *msg, char *txt1) { + dns_rdata_t querytsigrdata = DNS_RDATA_INIT; + dns_rdata_any_tsig_t querytsig; + isc_result_t result; + + if (msg->tsig != NULL) { + result = dns_rdataset_first(msg->tsig); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdataset_current(msg->tsig, &querytsigrdata); + result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + hexdump(txt1, "TSIG", querytsig.signature, + querytsig.siglen); + } + + if (msg->querytsig != NULL) { + result = dns_rdataset_first(msg->querytsig); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdataset_current(msg->querytsig, &querytsigrdata); + result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + hexdump(txt1, "QUERYTSIG", querytsig.signature, + querytsig.siglen); + } +} +#endif + isc_result_t dns_message_checksig(dns_message_t *msg, dns_view_t *view) { isc_buffer_t b, msgb; @@ -2907,10 +2964,14 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) { if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) return (ISC_R_SUCCESS); + INSIST(msg->saved.base != NULL); isc_buffer_init(&msgb, msg->saved.base, msg->saved.length); isc_buffer_add(&msgb, msg->saved.length); if (msg->tsigkey != NULL || msg->tsig != NULL) { +#ifdef SKAN_MSG_DEBUG + dns_message_dumpsig(msg, "dns_message_checksig#1"); +#endif if (view != NULL) return (dns_view_checksig(view, &msgb, msg)); else @@ -2963,6 +3024,7 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) { { dst_key_t *key = NULL; + dns_rdata_reset(&rdata); dns_rdataset_current(&keyset, &rdata); isc_buffer_init(&b, rdata.data, rdata.length); isc_buffer_add(&b, rdata.length); @@ -3068,6 +3130,10 @@ dns_message_pseudosectiontotext(dns_message_t *msg, isc_result_t result; char buf[sizeof("1234567890")]; isc_uint32_t mbz; + dns_rdata_t rdata; + isc_buffer_t optbuf; + isc_uint16_t optcode, optlen; + unsigned char *optdata; REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(target != NULL); @@ -3097,6 +3163,50 @@ dns_message_pseudosectiontotext(dns_message_t *msg, ADD_STRING(target, "; udp: "); snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); ADD_STRING(target, buf); + + result = dns_rdataset_first(ps); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + /* Print EDNS info, if any */ + dns_rdata_init(&rdata); + dns_rdataset_current(ps, &rdata); + if (rdata.length < 4) + return (ISC_R_SUCCESS); + + isc_buffer_init(&optbuf, rdata.data, rdata.length); + isc_buffer_add(&optbuf, rdata.length); + optcode = isc_buffer_getuint16(&optbuf); + optlen = isc_buffer_getuint16(&optbuf); + + if (optcode == DNS_OPT_NSID) { + ADD_STRING(target, "; NSID"); + } else { + ADD_STRING(target, "; OPT="); + sprintf(buf, "%u", optcode); + ADD_STRING(target, buf); + } + + if (optlen != 0) { + int i; + ADD_STRING(target, ": "); + + optdata = rdata.data + 4; + for (i = 0; i < optlen; i++) { + sprintf(buf, "%02x ", optdata[i]); + ADD_STRING(target, buf); + } + for (i = 0; i < optlen; i++) { + ADD_STRING(target, " ("); + if (isprint(optdata[i])) + isc_buffer_putmem(target, &optdata[i], + 1); + else + isc_buffer_putstr(target, "."); + ADD_STRING(target, ")"); + } + } + ADD_STRING(target, "\n"); return (ISC_R_SUCCESS); case DNS_PSEUDOSECTION_TSIG: ps = dns_message_gettsig(msg, &name); diff --git a/lib/dns/name.c b/lib/dns/name.c index 7f5d4e9..f4ea3e9 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.c,v 1.144.18.16 2006/12/07 07:03:10 marka Exp $ */ +/* $Id: name.c,v 1.165 2008/04/01 23:47:10 tbox Exp $ */ /*! \file */ @@ -155,7 +155,7 @@ do { \ static unsigned char root_ndata[] = { '\0' }; static unsigned char root_offsets[] = { 0 }; -static dns_name_t root = +static dns_name_t root = { DNS_NAME_MAGIC, root_ndata, 1, 1, @@ -298,7 +298,7 @@ dns_name_ismailbox(const dns_name_t *name) { REQUIRE(name->labels > 0); REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE); - /* + /* * Root label. */ if (name->length == 1) @@ -312,7 +312,7 @@ dns_name_ismailbox(const dns_name_t *name) { if (!domainchar(ch)) return (ISC_FALSE); } - + if (ndata == name->ndata + name->length) return (ISC_FALSE); @@ -347,8 +347,8 @@ dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) { REQUIRE(VALID_NAME(name)); REQUIRE(name->labels > 0); REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE); - - /* + + /* * Root label. */ if (name->length == 1) @@ -918,7 +918,7 @@ dns_name_getlabelsequence(const dns_name_t *source, target->ndata = &source->ndata[firstoffset]; target->length = endoffset - firstoffset; - + if (first + n == source->labels && n > 0 && (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) target->attributes |= DNS_NAMEATTR_ABSOLUTE; @@ -991,7 +991,7 @@ dns_name_fromregion(dns_name_t *name, const isc_region_t *r) { name->length = len; } else { name->ndata = r->base; - name->length = (r->length <= DNS_NAME_MAXWIRE) ? + name->length = (r->length <= DNS_NAME_MAXWIRE) ? r->length : DNS_NAME_MAXWIRE; } @@ -1049,7 +1049,7 @@ dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, REQUIRE(ISC_BUFFER_VALID(source)); REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || (target == NULL && ISC_BUFFER_VALID(name->buffer))); - + downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0); if (target == NULL && name->buffer != NULL) { @@ -1297,24 +1297,25 @@ totext_filter_proc_key_init(void) { if (result != ISC_R_SUCCESS) return (result); - if (!thread_key_initialized) { + if (!thread_key_initialized) { LOCK(&thread_key_mutex); if (thread_key_mctx == NULL) result = isc_mem_create2(0, 0, &thread_key_mctx, 0); if (result != ISC_R_SUCCESS) goto unlock; + isc_mem_setname(thread_key_mctx, "threadkey", NULL); isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE); - + if (!thread_key_initialized && isc_thread_key_create(&totext_filter_proc_key, - free_specific) != 0) { + free_specific) != 0) { result = ISC_R_FAILURE; isc_mem_detach(&thread_key_mctx); } else thread_key_initialized = 1; unlock: UNLOCK(&thread_key_mutex); - } + } return (result); } #endif @@ -1930,7 +1931,8 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, methods = dns_compress_getmethods(cctx); - if ((methods & DNS_COMPRESS_GLOBAL14) != 0) + if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 && + (methods & DNS_COMPRESS_GLOBAL14) != 0) gf = dns_compress_findglobal(cctx, name, &gp, &go); else gf = ISC_FALSE; @@ -2298,7 +2300,7 @@ dns_name_settotextfilter(dns_name_totextfilter_t proc) { result = ISC_R_UNEXPECTED; return (result); } - + mem = isc_mem_get(thread_key_mctx, sizeof(*mem)); if (mem == NULL) return (ISC_R_NOMEMORY); diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c index 1fdc5c8..af0450b 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ncache.c,v 1.36.18.3 2005/04/29 00:15:59 marka Exp $ */ +/* $Id: ncache.c,v 1.43 2008/09/25 04:02:38 tbox Exp $ */ /*! \file */ @@ -30,6 +30,9 @@ #include <dns/rdata.h> #include <dns/rdatalist.h> #include <dns/rdataset.h> +#include <dns/rdatastruct.h> + +#define DNS_NCACHE_RDATA 20U /* * The format of an ncache rdata is a sequence of one or more records of @@ -92,6 +95,16 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) { + return (dns_ncache_addoptout(message, cache, node, covers, now, maxttl, + ISC_FALSE, addedrdataset)); +} + +isc_result_t +dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, + dns_dbnode_t *node, dns_rdatatype_t covers, + isc_stdtime_t now, dns_ttl_t maxttl, + isc_boolean_t optout, dns_rdataset_t *addedrdataset) +{ isc_result_t result; isc_buffer_t buffer; isc_region_t r; @@ -100,10 +113,11 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_name_t *name; dns_ttl_t ttl; dns_trust_t trust; - dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_t rdata[DNS_NCACHE_RDATA]; dns_rdataset_t ncrdataset; dns_rdatalist_t ncrdatalist; unsigned char data[4096]; + unsigned int next = 0; /* * Convert the authority data from 'message' into a negative cache @@ -118,7 +132,17 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, */ /* - * First, build an ncache rdata in buffer. + * Initialize the list. + */ + ncrdatalist.rdclass = dns_db_class(cache); + ncrdatalist.type = 0; + ncrdatalist.covers = covers; + ncrdatalist.ttl = maxttl; + ISC_LIST_INIT(ncrdatalist.rdata); + ISC_LINK_INIT(&ncrdatalist, link); + + /* + * Build an ncache rdatas into buffer. */ ttl = maxttl; trust = 0xffff; @@ -142,7 +166,8 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, if (type == dns_rdatatype_rrsig) type = rdataset->covers; if (type == dns_rdatatype_soa || - type == dns_rdatatype_nsec) { + type == dns_rdatatype_nsec || + type == dns_rdatatype_nsec3) { if (ttl > rdataset->ttl) ttl = rdataset->ttl; if (trust > rdataset->trust) @@ -171,6 +196,21 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, &buffer); if (result != ISC_R_SUCCESS) return (result); + + if (next >= DNS_NCACHE_RDATA) + return (ISC_R_NOSPACE); + dns_rdata_init(&rdata[next]); + isc_buffer_remainingregion(&buffer, &r); + rdata[next].data = r.base; + rdata[next].length = r.length; + rdata[next].rdclass = + ncrdatalist.rdclass; + rdata[next].type = 0; + rdata[next].flags = 0; + ISC_LIST_APPEND(ncrdatalist.rdata, + &rdata[next], link); + isc_buffer_forward(&buffer, r.length); + next++; } } } @@ -226,27 +266,24 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, trust = dns_trust_authauthority; } else trust = dns_trust_additional; + /* + * Now add it to the cache. + */ + if (next >= DNS_NCACHE_RDATA) + return (ISC_R_NOSPACE); + dns_rdata_init(&rdata[next]); + isc_buffer_remainingregion(&buffer, &r); + rdata[next].data = r.base; + rdata[next].length = r.length; + rdata[next].rdclass = ncrdatalist.rdclass; + rdata[next].type = 0; + rdata[next].flags = 0; + ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link); } - /* - * Now add it to the cache. - */ INSIST(trust != 0xffff); - isc_buffer_usedregion(&buffer, &r); - rdata.data = r.base; - rdata.length = r.length; - rdata.rdclass = dns_db_class(cache); - rdata.type = 0; - rdata.flags = 0; - - ncrdatalist.rdclass = rdata.rdclass; - ncrdatalist.type = 0; - ncrdatalist.covers = covers; - ncrdatalist.ttl = ttl; - ISC_LIST_INIT(ncrdatalist.rdata); - ISC_LINK_INIT(&ncrdatalist, link); - ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link); + ncrdatalist.ttl = ttl; dns_rdataset_init(&ncrdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) @@ -254,6 +291,8 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, ncrdataset.trust = trust; if (message->rcode == dns_rcode_nxdomain) ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN; + if (optout) + ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT; return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0, addedrdataset)); @@ -281,18 +320,14 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, REQUIRE(rdataset != NULL); REQUIRE(rdataset->type == 0); - result = dns_rdataset_first(rdataset); - if (result != ISC_R_SUCCESS) - return (result); - dns_rdataset_current(rdataset, &rdata); - INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); - isc_buffer_init(&source, rdata.data, rdata.length); - isc_buffer_add(&source, rdata.length); - savedbuffer = *target; - count = 0; - do { + + result = dns_rdataset_first(rdataset); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); dns_name_init(&name, NULL); isc_buffer_remainingregion(&source, &remaining); dns_name_fromregion(&name, &remaining); @@ -370,8 +405,12 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, count++; } - isc_buffer_remainingregion(&source, &remaining); - } while (remaining.length > 0); + INSIST(isc_buffer_remaininglength(&source) == 0); + result = dns_rdataset_next(rdataset); + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto rollback; *countp = count; @@ -478,6 +517,8 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; @@ -491,8 +532,6 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, isc_buffer_t source; dns_name_t tname; dns_rdatatype_t ttype; - unsigned int i, rcount; - isc_uint16_t length; REQUIRE(ncacherdataset != NULL); REQUIRE(ncacherdataset->type == 0); @@ -501,14 +540,10 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, REQUIRE(type != dns_rdatatype_rrsig); result = dns_rdataset_first(ncacherdataset); - if (result != ISC_R_SUCCESS) - return (result); - dns_rdataset_current(ncacherdataset, &rdata); - INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE); - isc_buffer_init(&source, rdata.data, rdata.length); - isc_buffer_add(&source, rdata.length); - - do { + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(ncacherdataset, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); dns_name_init(&tname, NULL); isc_buffer_remainingregion(&source, &remaining); dns_name_fromregion(&tname, &remaining); @@ -523,21 +558,15 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, isc_buffer_remainingregion(&source, &remaining); break; } - - rcount = isc_buffer_getuint16(&source); - for (i = 0; i < rcount; i++) { - isc_buffer_remainingregion(&source, &remaining); - INSIST(remaining.length >= 2); - length = isc_buffer_getuint16(&source); - isc_buffer_remainingregion(&source, &remaining); - INSIST(remaining.length >= length); - isc_buffer_forward(&source, length); - } - isc_buffer_remainingregion(&source, &remaining); - } while (remaining.length > 0); - - if (remaining.length == 0) + result = dns_rdataset_next(ncacherdataset); + dns_rdata_reset(&rdata); + } + if (result == ISC_R_NOMORE) return (ISC_R_NOTFOUND); + if (result != ISC_R_SUCCESS) + return (result); + + INSIST(remaining.length != 0); rdataset->methods = &rdataset_methods; rdataset->rdclass = ncacherdataset->rdclass; @@ -555,5 +584,75 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, */ rdataset->privateuint4 = 0; rdataset->private5 = NULL; + rdataset->private6 = NULL; return (ISC_R_SUCCESS); } + +void +dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, + dns_rdataset_t *rdataset) +{ + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_region_t remaining, sigregion; + isc_buffer_t source; + dns_name_t tname; + dns_rdatatype_t type; + unsigned int count; + dns_rdata_rrsig_t rrsig; + unsigned char *raw; + + REQUIRE(ncacherdataset != NULL); + REQUIRE(ncacherdataset->type == 0); + REQUIRE(found != NULL); + REQUIRE(!dns_rdataset_isassociated(rdataset)); + + dns_rdataset_current(ncacherdataset, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); + + dns_name_init(&tname, NULL); + isc_buffer_remainingregion(&source, &remaining); + dns_name_fromregion(found, &remaining); + INSIST(remaining.length >= found->length); + isc_buffer_forward(&source, found->length); + remaining.length -= found->length; + + INSIST(remaining.length >= 4); + type = isc_buffer_getuint16(&source); + isc_buffer_remainingregion(&source, &remaining); + + rdataset->methods = &rdataset_methods; + rdataset->rdclass = ncacherdataset->rdclass; + rdataset->type = type; + if (type == dns_rdatatype_rrsig) { + /* + * Extract covers from RRSIG. + */ + raw = remaining.base; + count = raw[0] * 256 + raw[1]; + INSIST(count > 0); + raw += 2; + sigregion.length = raw[0] * 256 + raw[1]; + raw += 2; + sigregion.base = raw; + dns_rdata_reset(&rdata); + dns_rdata_fromregion(&rdata, rdataset->rdclass, + rdataset->type, &sigregion); + (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); + rdataset->covers = rrsig.covered; + } else + rdataset->covers = 0; + rdataset->ttl = ncacherdataset->ttl; + rdataset->trust = ncacherdataset->trust; + rdataset->private1 = NULL; + rdataset->private2 = NULL; + + rdataset->private3 = remaining.base; + + /* + * Reset iterator state. + */ + rdataset->privateuint4 = 0; + rdataset->private5 = NULL; + rdataset->private6 = NULL; +} diff --git a/lib/dns/nsec.c b/lib/dns/nsec.c index c1de67e..39f409c 100644 --- a/lib/dns/nsec.c +++ b/lib/dns/nsec.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec.c,v 1.5.20.2 2005/04/29 00:15:59 marka Exp $ */ +/* $Id: nsec.c,v 1.11.48.2 2009/01/06 23:47:26 tbox Exp $ */ /*! \file */ @@ -33,6 +33,8 @@ #include <dns/rdatastruct.h> #include <dns/result.h> +#include <dst/dst.h> + #define RETERR(x) do { \ result = (x); \ if (result != ISC_R_SUCCESS) \ @@ -88,6 +90,7 @@ dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, */ bm = r.base + r.length + 512; nsec_bits = r.base + r.length; + set_bit(bm, dns_rdatatype_rrsig, 1); set_bit(bm, dns_rdatatype_nsec, 1); max_type = dns_rdatatype_nsec; dns_rdataset_init(&rdataset); @@ -100,7 +103,9 @@ dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, result = dns_rdatasetiter_next(rdsiter)) { dns_rdatasetiter_current(rdsiter, &rdataset); - if (rdataset.type != dns_rdatatype_nsec) { + if (rdataset.type != dns_rdatatype_nsec && + rdataset.type != dns_rdatatype_nsec3 && + rdataset.type != dns_rdatatype_rrsig) { if (rdataset.type > max_type) max_type = rdataset.type; set_bit(bm, rdataset.type, 1); @@ -197,7 +202,7 @@ dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) { /* This should never fail */ result = dns_rdata_tostruct(nsec, &nsecstruct, NULL); INSIST(result == ISC_R_SUCCESS); - + present = ISC_FALSE; for (i = 0; i < nsecstruct.len; i += len) { INSIST(i + 2 <= nsecstruct.len); @@ -215,6 +220,58 @@ dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) { type % 256)); break; } - dns_rdata_freestruct(&nsec); + dns_rdata_freestruct(&nsecstruct); return (present); } + +isc_result_t +dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t *answer) +{ + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_dnskey_t dnskey; + isc_result_t result; + + REQUIRE(answer != NULL); + + dns_rdataset_init(&rdataset); + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, + 0, 0, &rdataset, NULL); + dns_db_detachnode(db, &node); + + if (result == ISC_R_NOTFOUND) { + *answer = ISC_FALSE; + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS) + return (result); + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &dnskey, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if (dnskey.algorithm == DST_ALG_RSAMD5 || + dnskey.algorithm == DST_ALG_RSASHA1 || + dnskey.algorithm == DST_ALG_DSA || + dnskey.algorithm == DST_ALG_ECC) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) + *answer = ISC_TRUE; + if (result == ISC_R_NOMORE) { + *answer = ISC_FALSE; + result = ISC_R_SUCCESS; + } + return (result); +} diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c new file mode 100644 index 0000000..54a6993 --- /dev/null +++ b/lib/dns/nsec3.c @@ -0,0 +1,1377 @@ +/* + * Copyright (C) 2006, 2008 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: nsec3.c,v 1.6 2008/11/17 23:46:42 marka Exp $ */ + +#include <config.h> + +#include <isc/base32.h> +#include <isc/buffer.h> +#include <isc/hex.h> +#include <isc/iterated_hash.h> +#include <isc/string.h> +#include <isc/util.h> + +#include <dst/dst.h> + +#include <dns/db.h> +#include <dns/dbiterator.h> +#include <dns/diff.h> +#include <dns/fixedname.h> +#include <dns/nsec3.h> +#include <dns/rdata.h> +#include <dns/rdatalist.h> +#include <dns/rdataset.h> +#include <dns/rdatasetiter.h> +#include <dns/rdatastruct.h> +#include <dns/result.h> + +#define CHECK(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto failure; \ + } while (0) + +#define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0) +#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) +#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) + +static void +set_bit(unsigned char *array, unsigned int index, unsigned int bit) { + unsigned int shift, mask; + + shift = 7 - (index % 8); + mask = 1 << shift; + + if (bit != 0) + array[index / 8] |= mask; + else + array[index / 8] &= (~mask & 0xFF); +} + +static unsigned int +bit_isset(unsigned char *array, unsigned int index) { + unsigned int byte, shift, mask; + + byte = array[index / 8]; + shift = 7 - (index % 8); + mask = 1 << shift; + + return ((byte & mask) != 0); +} + +isc_result_t +dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, + dns_dbnode_t *node, unsigned int hashalg, + unsigned int flags, unsigned int iterations, + const unsigned char *salt, size_t salt_length, + const unsigned char *nexthash, size_t hash_length, + unsigned char *buffer, dns_rdata_t *rdata) +{ + isc_result_t result; + dns_rdataset_t rdataset; + isc_region_t r; + unsigned int i, window; + int octet; + isc_boolean_t found; + + unsigned char *nsec_bits, *bm; + unsigned int max_type; + dns_rdatasetiter_t *rdsiter; + unsigned char *p; + + REQUIRE(salt_length < 256U); + REQUIRE(hash_length < 256U); + REQUIRE(flags <= 0xffU); + REQUIRE(hashalg <= 0xffU); + REQUIRE(iterations <= 0xffffU); + + switch (hashalg) { + case dns_hash_sha1: + REQUIRE(hash_length == ISC_SHA1_DIGESTLENGTH); + break; + } + + memset(buffer, 0, DNS_NSEC3_BUFFERSIZE); + + p = buffer; + + *p++ = hashalg; + *p++ = flags; + + *p++ = iterations >> 8; + *p++ = iterations; + + *p++ = salt_length; + memcpy(p, salt, salt_length); + p += salt_length; + + *p++ = hash_length; + memcpy(p, nexthash, hash_length); + p += hash_length; + + r.length = p - buffer; + r.base = buffer; + + /* + * Use the end of the space for a raw bitmap leaving enough + * space for the window identifiers and length octets. + */ + bm = r.base + r.length + 512; + nsec_bits = r.base + r.length; + max_type = 0; + if (node == NULL) + goto collapse_bitmap; + dns_rdataset_init(&rdataset); + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, version, 0, &rdsiter); + if (result != ISC_R_SUCCESS) + return (result); + found = ISC_FALSE; + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) + { + dns_rdatasetiter_current(rdsiter, &rdataset); + if (rdataset.type != dns_rdatatype_nsec && + rdataset.type != dns_rdatatype_nsec3 && + rdataset.type != dns_rdatatype_rrsig) { + if (rdataset.type > max_type) + max_type = rdataset.type; + set_bit(bm, rdataset.type, 1); + /* Don't set RRSIG for insecure delegation. */ + if (rdataset.type != dns_rdatatype_ns) + found = ISC_TRUE; + } + dns_rdataset_disassociate(&rdataset); + } + if (found) { + if (dns_rdatatype_rrsig > max_type) + max_type = dns_rdatatype_rrsig; + set_bit(bm, dns_rdatatype_rrsig, 1); + } + + /* + * At zone cuts, deny the existence of glue in the parent zone. + */ + if (bit_isset(bm, dns_rdatatype_ns) && + ! bit_isset(bm, dns_rdatatype_soa)) { + for (i = 0; i <= max_type; i++) { + if (bit_isset(bm, i) && + ! dns_rdatatype_iszonecutauth((dns_rdatatype_t)i)) + set_bit(bm, i, 0); + } + } + + dns_rdatasetiter_destroy(&rdsiter); + if (result != ISC_R_NOMORE) + return (result); + + collapse_bitmap: + for (window = 0; window < 256; window++) { + if (window * 256 > max_type) + break; + for (octet = 31; octet >= 0; octet--) + if (bm[window * 32 + octet] != 0) + break; + if (octet < 0) + continue; + nsec_bits[0] = window; + nsec_bits[1] = octet + 1; + /* + * Note: potentially overlapping move. + */ + memmove(&nsec_bits[2], &bm[window * 32], octet + 1); + nsec_bits += 3 + octet; + } + r.length = nsec_bits - r.base; + INSIST(r.length <= DNS_NSEC3_BUFFERSIZE); + dns_rdata_fromregion(rdata, dns_db_class(db), dns_rdatatype_nsec3, &r); + + return (ISC_R_SUCCESS); +} + +isc_boolean_t +dns_nsec3_typepresent(dns_rdata_t *rdata, dns_rdatatype_t type) { + dns_rdata_nsec3_t nsec3; + isc_result_t result; + isc_boolean_t present; + unsigned int i, len, window; + + REQUIRE(rdata != NULL); + REQUIRE(rdata->type == dns_rdatatype_nsec3); + + /* This should never fail */ + result = dns_rdata_tostruct(rdata, &nsec3, NULL); + INSIST(result == ISC_R_SUCCESS); + + present = ISC_FALSE; + for (i = 0; i < nsec3.len; i += len) { + INSIST(i + 2 <= nsec3.len); + window = nsec3.typebits[i]; + len = nsec3.typebits[i + 1]; + INSIST(len > 0 && len <= 32); + i += 2; + INSIST(i + len <= nsec3.len); + if (window * 256 > type) + break; + if ((window + 1) * 256 <= type) + continue; + if (type < (window * 256) + len * 8) + present = ISC_TF(bit_isset(&nsec3.typebits[i], + type % 256)); + break; + } + dns_rdata_freestruct(&nsec3); + return (present); +} + +isc_result_t +dns_nsec3_hashname(dns_fixedname_t *result, + unsigned char rethash[NSEC3_MAX_HASH_LENGTH], + size_t *hash_length, dns_name_t *name, dns_name_t *origin, + dns_hash_t hashalg, unsigned int iterations, + const unsigned char *salt, size_t saltlength) +{ + unsigned char hash[NSEC3_MAX_HASH_LENGTH]; + unsigned char nametext[DNS_NAME_FORMATSIZE]; + dns_fixedname_t fixed; + dns_name_t *downcased; + isc_buffer_t namebuffer; + isc_region_t region; + size_t len; + + if (rethash == NULL) + rethash = hash; + + memset(rethash, 0, NSEC3_MAX_HASH_LENGTH); + + dns_fixedname_init(&fixed); + downcased = dns_fixedname_name(&fixed); + dns_name_downcase(name, downcased, NULL); + + /* hash the node name */ + len = isc_iterated_hash(rethash, hashalg, iterations, salt, saltlength, + downcased->ndata, downcased->length); + if (len == 0U) + return (DNS_R_BADALG); + + if (hash_length != NULL) + *hash_length = len; + + /* convert the hash to base32hex */ + region.base = rethash; + region.length = len; + isc_buffer_init(&namebuffer, nametext, sizeof nametext); + isc_base32hex_totext(®ion, 1, "", &namebuffer); + + /* convert the hex to a domain name */ + dns_fixedname_init(result); + return (dns_name_fromtext(dns_fixedname_name(result), &namebuffer, + origin, 0, NULL)); +} + +unsigned int +dns_nsec3_hashlength(dns_hash_t hash) { + + switch (hash) { + case dns_hash_sha1: return(ISC_SHA1_DIGESTLENGTH); + } + return (0); +} + +isc_boolean_t +dns_nsec3_supportedhash(dns_hash_t hash) { + switch (hash) { + case dns_hash_sha1: return (ISC_TRUE); + } + return (ISC_FALSE); +} + +/*% + * Update a single RR in version 'ver' of 'db' and log the + * update in 'diff'. + * + * Ensures: + * \li '*tuple' == NULL. Either the tuple is freed, or its + * ownership has been transferred to the diff. + */ +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); +} + +/*% + * Set '*exists' to true iff the given name exists, to false otherwise. + */ +static isc_result_t +name_exists(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + isc_boolean_t *exists) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdatasetiter_t *iter = NULL; + + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) { + *exists = ISC_FALSE; + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_db_allrdatasets(db, node, version, + (isc_stdtime_t) 0, &iter); + if (result != ISC_R_SUCCESS) + goto cleanup_node; + + result = dns_rdatasetiter_first(iter); + if (result == ISC_R_SUCCESS) { + *exists = ISC_TRUE; + } else if (result == ISC_R_NOMORE) { + *exists = ISC_FALSE; + result = ISC_R_SUCCESS; + } else + *exists = ISC_FALSE; + dns_rdatasetiter_destroy(&iter); + + cleanup_node: + dns_db_detachnode(db, &node); + return (result); +} + +static isc_boolean_t +match_nsec3param(const dns_rdata_nsec3_t *nsec3, + const dns_rdata_nsec3param_t *nsec3param) +{ + if (nsec3->hash == nsec3param->hash && + nsec3->iterations == nsec3param->iterations && + nsec3->salt_length == nsec3param->salt_length && + !memcmp(nsec3->salt, nsec3param->salt, nsec3->salt_length)) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/*% + * Delete NSEC3 records at "name" which match "param", recording the + * change in "diff". + */ +static isc_result_t +delete(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL ; + dns_difftuple_t *tuple = NULL; + dns_rdata_nsec3_t nsec3; + dns_rdataset_t rdataset; + isc_result_t result; + + result = dns_db_findnsec3node(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, &rdataset, NULL); + + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + goto cleanup_node; + } + if (result != ISC_R_SUCCESS) + goto cleanup_node; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &nsec3, NULL)); + + if (!match_nsec3param(&nsec3, nsec3param)) + continue; + + result = dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, name, + rdataset.ttl, &rdata, &tuple); + if (result != ISC_R_SUCCESS) + goto failure; + result = do_one_tuple(&tuple, db, version, diff); + if (result != ISC_R_SUCCESS) + goto failure; + } + if (result != ISC_R_NOMORE) + goto failure; + result = ISC_R_SUCCESS; + + failure: + dns_rdataset_disassociate(&rdataset); + cleanup_node: + dns_db_detachnode(db, &node); + + return (result); +} + +#ifndef RFC5155_STRICT +static isc_boolean_t +better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { + dns_rdataset_t rdataset; + isc_result_t result; + + if (REMOVE(param->data[1])) + return (ISC_TRUE); + + dns_rdataset_init(&rdataset); + dns_rdataset_clone(nsec3paramset, &rdataset); + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + if (rdata.length != param->length) + continue; + if (rdata.data[0] != param->data[0] || + REMOVE(rdata.data[1]) || + rdata.data[2] != param->data[2] || + rdata.data[3] != param->data[3] || + rdata.data[4] != param->data[4] || + memcmp(&rdata.data[5], ¶m->data[5], param->data[4])) + continue; + if (CREATE(rdata.data[1]) && !CREATE(param->data[1])) { + dns_rdataset_disassociate(&rdataset); + return (ISC_TRUE); + } + } + dns_rdataset_disassociate(&rdataset); + return (ISC_FALSE); +} +#endif + +static isc_result_t +find_nsec3(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *rdataset, + const dns_rdata_nsec3param_t *nsec3param) +{ + isc_result_t result; + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, nsec3, NULL)); + dns_rdata_reset(&rdata); + if (match_nsec3param(nsec3, nsec3param)) + break; + } + failure: + return (result); +} + +isc_result_t +dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, const dns_rdata_nsec3param_t *nsec3param, + dns_ttl_t nsecttl, isc_boolean_t unsecure, dns_diff_t *diff) +{ + dns_dbiterator_t *dbit = NULL; + dns_dbnode_t *node = NULL; + dns_dbnode_t *newnode = NULL; + dns_difftuple_t *tuple = NULL; + dns_fixedname_t fixed; + dns_fixedname_t fprev; + dns_hash_t hash; + dns_name_t *hashname; + dns_name_t *origin; + dns_name_t *prev; + dns_name_t empty; + dns_rdata_nsec3_t nsec3; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + int pass; + isc_boolean_t exists; + isc_boolean_t remove_unsecure = ISC_FALSE; + isc_uint8_t flags; + isc_buffer_t buffer; + isc_result_t result; + unsigned char *old_next; + unsigned char *salt; + unsigned char nexthash[NSEC3_MAX_HASH_LENGTH]; + unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE]; + unsigned int iterations; + unsigned int labels; + size_t next_length; + unsigned int old_length; + unsigned int salt_length; + + dns_fixedname_init(&fixed); + hashname = dns_fixedname_name(&fixed); + dns_fixedname_init(&fprev); + prev = dns_fixedname_name(&fprev); + + dns_rdataset_init(&rdataset); + + origin = dns_db_origin(db); + + /* + * Chain parameters. + */ + hash = nsec3param->hash; + iterations = nsec3param->iterations; + salt_length = nsec3param->salt_length; + salt = nsec3param->salt; + + /* + * Default flags for a new chain. + */ + flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT; + + /* + * If this is the first NSEC3 in the chain nexthash will + * remain pointing to itself. + */ + next_length = sizeof(nexthash); + CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length, + name, origin, hash, iterations, + salt, salt_length)); + + /* + * Create the node if it doesn't exist and hold + * a reference to it until we have added the NSEC3. + */ + CHECK(dns_db_findnsec3node(db, hashname, ISC_TRUE, &newnode)); + + /* + * Seek the iterator to the 'newnode'. + */ + CHECK(dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbit)); + CHECK(dns_dbiterator_seek(dbit, hashname)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, newnode, version, dns_rdatatype_nsec3, + 0, (isc_stdtime_t) 0, &rdataset, NULL); + /* + * If we updating a existing NSEC3 then find its + * next field. + */ + if (result == ISC_R_SUCCESS) { + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_SUCCESS) { + if (!CREATE(nsec3param->flags)) + flags = nsec3.flags; + next_length = nsec3.next_length; + INSIST(next_length <= sizeof(nexthash)); + memcpy(nexthash, nsec3.next, next_length); + dns_rdataset_disassociate(&rdataset); + /* + * If the NSEC3 is not for a unsecure delegation then + * we are just updating it. If it is for a unsecure + * delegation then we need find out if we need to + * remove the NSEC3 record or not by examining the + * previous NSEC3 record. + */ + if (!unsecure) + goto addnsec3; + else + remove_unsecure = ISC_TRUE; + } else { + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_NOMORE) + goto failure; + } + } + + /* + * Find the previous NSEC3 (if any) and update it if required. + */ + pass = 0; + do { + result = dns_dbiterator_prev(dbit); + if (result == ISC_R_NOMORE) { + pass++; + CHECK(dns_dbiterator_last(dbit)); + } + CHECK(dns_dbiterator_current(dbit, &node, prev)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, &rdataset, + NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + continue; + + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_NOMORE) { + dns_rdataset_disassociate(&rdataset); + continue; + } + if (result != ISC_R_SUCCESS) + goto failure; + + if (remove_unsecure) { + dns_rdataset_disassociate(&rdataset); + /* + * We have found the previous NSEC3 record and can now + * see if the existing NSEC3 record needs to be + * updated or deleted. + */ + if (!OPTOUT(nsec3.flags)) { + /* + * Just update the NSEC3 record. + */ + goto addnsec3; + } else { + /* + * This is actually a deletion not a add. + */ + result = dns_nsec3_delnsec3(db, version, name, + nsec3param, diff); + goto failure; + } + } else { + /* + * Is this is a unsecure delegation we are adding? + * If so no change is required. + */ + if (OPTOUT(nsec3.flags) && unsecure) { + dns_rdataset_disassociate(&rdataset); + goto failure; + } + } + + old_next = nsec3.next; + old_length = nsec3.next_length; + + /* + * Delete the old previous NSEC3. + */ + CHECK(delete(db, version, prev, nsec3param, diff)); + + /* + * Fixup the previous NSEC3. + */ + nsec3.next = nexthash; + nsec3.next_length = next_length; + isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); + CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, + dns_rdatatype_nsec3, &nsec3, + &buffer)); + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, prev, + rdataset.ttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, version, diff)); + INSIST(old_length <= sizeof(nexthash)); + memcpy(nexthash, old_next, old_length); + if (!CREATE(nsec3param->flags)) + flags = nsec3.flags; + dns_rdata_reset(&rdata); + dns_rdataset_disassociate(&rdataset); + break; + } while (pass < 2); + + addnsec3: + /* + * Create the NSEC3 RDATA. + */ + CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); + CHECK(dns_nsec3_buildrdata(db, version, node, hash, flags, iterations, + salt, salt_length, nexthash, next_length, + nsec3buf, &rdata)); + dns_db_detachnode(db, &node); + + /* + * Delete the old NSEC3 and record the change. + */ + CHECK(delete(db, version, hashname, nsec3param, diff)); + /* + * Add the new NSEC3 and record the change. + */ + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + hashname, nsecttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, version, diff)); + INSIST(tuple == NULL); + dns_rdata_reset(&rdata); + dns_db_detachnode(db, &newnode); + + /* + * Add missing NSEC3 records for empty nodes + */ + dns_name_init(&empty, NULL); + dns_name_clone(name, &empty); + do { + labels = dns_name_countlabels(&empty) - 1; + if (labels <= dns_name_countlabels(origin)) + break; + dns_name_getlabelsequence(&empty, 1, labels, &empty); + CHECK(name_exists(db, version, &empty, &exists)); + if (exists) + break; + CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length, + &empty, origin, hash, iterations, + salt, salt_length)); + + /* + * Create the node if it doesn't exist and hold + * a reference to it until we have added the NSEC3 + * or we discover we don't need to add make a change. + */ + CHECK(dns_db_findnsec3node(db, hashname, ISC_TRUE, &newnode)); + result = dns_db_findrdataset(db, newnode, version, + dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, &rdataset, + NULL); + if (result == ISC_R_SUCCESS) { + result = find_nsec3(&nsec3, &rdataset, nsec3param); + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) { + dns_db_detachnode(db, &newnode); + break; + } + if (result != ISC_R_NOMORE) + goto failure; + } + + /* + * Find the previous NSEC3 and update it. + */ + CHECK(dns_dbiterator_seek(dbit, hashname)); + pass = 0; + do { + result = dns_dbiterator_prev(dbit); + if (result == ISC_R_NOMORE) { + pass++; + CHECK(dns_dbiterator_last(dbit)); + } + CHECK(dns_dbiterator_current(dbit, &node, prev)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, + &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + continue; + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_NOMORE) { + dns_rdataset_disassociate(&rdataset); + continue; + } + if (result != ISC_R_SUCCESS) + goto failure; + + old_next = nsec3.next; + old_length = nsec3.next_length; + + /* + * Delete the old previous NSEC3. + */ + CHECK(delete(db, version, prev, nsec3param, diff)); + + /* + * Fixup the previous NSEC3. + */ + nsec3.next = nexthash; + nsec3.next_length = next_length; + isc_buffer_init(&buffer, nsec3buf, + sizeof(nsec3buf)); + CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, + dns_rdatatype_nsec3, &nsec3, + &buffer)); + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + prev, rdataset.ttl, &rdata, + &tuple)); + CHECK(do_one_tuple(&tuple, db, version, diff)); + INSIST(old_length <= sizeof(nexthash)); + memcpy(nexthash, old_next, old_length); + if (!CREATE(nsec3param->flags)) + flags = nsec3.flags; + dns_rdata_reset(&rdata); + dns_rdataset_disassociate(&rdataset); + break; + } while (pass < 2); + + INSIST(pass < 2); + + /* + * Create the NSEC3 RDATA for the empty node. + */ + CHECK(dns_nsec3_buildrdata(db, version, NULL, hash, flags, + iterations, salt, salt_length, + nexthash, next_length, nsec3buf, + &rdata)); + /* + * Delete the old NSEC3 and record the change. + */ + CHECK(delete(db, version, hashname, nsec3param, diff)); + + /* + * Add the new NSEC3 and record the change. + */ + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + hashname, nsecttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, version, diff)); + INSIST(tuple == NULL); + dns_rdata_reset(&rdata); + dns_db_detachnode(db, &newnode); + } while (1); + + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + failure: + if (dbit != NULL) + dns_dbiterator_destroy(&dbit); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + if (newnode != NULL) + dns_db_detachnode(db, &newnode); + return (result); +} + +/*% + * Add NSEC3 records for "name", recording the change in "diff". + * The existing NSEC3 records are removed. + */ +isc_result_t +dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, dns_ttl_t nsecttl, + isc_boolean_t unsecure, dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL; + dns_rdata_nsec3param_t nsec3param; + dns_rdataset_t rdataset; + isc_result_t result; + + dns_rdataset_init(&rdataset); + + /* + * Find the NSEC3 parameters for this zone. + */ + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, 0, 0, + &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Update each active NSEC3 chain. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + dns_rdata_tostruct(&rdata, &nsec3param, NULL); + +#ifdef RFC5155_STRICT + if (nsec3param.flags != 0) + continue; +#else + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) + continue; + if (better_param(&rdataset, &rdata)) + continue; +#endif + + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param, + nsecttl, unsecure, diff)); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + + return (result); +} + +isc_result_t +dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff) +{ + dns_dbiterator_t *dbit = NULL; + dns_dbnode_t *node = NULL; + dns_difftuple_t *tuple = NULL; + dns_fixedname_t fixed; + dns_fixedname_t fprev; + dns_hash_t hash; + dns_name_t *hashname; + dns_name_t *origin; + dns_name_t *prev; + dns_name_t empty; + dns_rdata_nsec3_t nsec3; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + int pass; + isc_boolean_t exists; + isc_buffer_t buffer; + isc_result_t result; + unsigned char *salt; + unsigned char nexthash[NSEC3_MAX_HASH_LENGTH]; + unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE]; + unsigned int iterations; + unsigned int labels; + size_t next_length; + unsigned int salt_length; + + dns_fixedname_init(&fixed); + hashname = dns_fixedname_name(&fixed); + dns_fixedname_init(&fprev); + prev = dns_fixedname_name(&fprev); + + dns_rdataset_init(&rdataset); + + origin = dns_db_origin(db); + + /* + * Chain parameters. + */ + hash = nsec3param->hash; + iterations = nsec3param->iterations; + salt_length = nsec3param->salt_length; + salt = nsec3param->salt; + + /* + * If this is the first NSEC3 in the chain nexthash will + * remain pointing to itself. + */ + next_length = sizeof(nexthash); + CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length, + name, origin, hash, iterations, + salt, salt_length)); + + CHECK(dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbit)); + + result = dns_dbiterator_seek(dbit, hashname); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + CHECK(dns_dbiterator_current(dbit, &node, NULL)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3, + 0, (isc_stdtime_t) 0, &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * If we find a existing NSEC3 for this chain then save the + * next field. + */ + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_SUCCESS) { + next_length = nsec3.next_length; + INSIST(next_length <= sizeof(nexthash)); + memcpy(nexthash, nsec3.next, next_length); + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_NOMORE) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Find the previous NSEC3 and update it. + */ + pass = 0; + do { + result = dns_dbiterator_prev(dbit); + if (result == ISC_R_NOMORE) { + pass++; + CHECK(dns_dbiterator_last(dbit)); + } + CHECK(dns_dbiterator_current(dbit, &node, prev)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, &rdataset, + NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + continue; + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_NOMORE) { + dns_rdataset_disassociate(&rdataset); + continue; + } + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Delete the old previous NSEC3. + */ + CHECK(delete(db, version, prev, nsec3param, diff)); + + /* + * Fixup the previous NSEC3. + */ + nsec3.next = nexthash; + nsec3.next_length = next_length; + isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); + CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, + dns_rdatatype_nsec3, &nsec3, + &buffer)); + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, prev, + rdataset.ttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, version, diff)); + dns_rdata_reset(&rdata); + dns_rdataset_disassociate(&rdataset); + break; + } while (pass < 2); + + /* + * Delete the old NSEC3 and record the change. + */ + CHECK(delete(db, version, hashname, nsec3param, diff)); + + /* + * Delete NSEC3 records for now non active nodes. + */ + dns_name_init(&empty, NULL); + dns_name_clone(name, &empty); + do { + labels = dns_name_countlabels(&empty) - 1; + if (labels <= dns_name_countlabels(origin)) + break; + dns_name_getlabelsequence(&empty, 1, labels, &empty); + CHECK(name_exists(db, version, &empty, &exists)); + if (exists) + break; + + CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length, + &empty, origin, hash, iterations, + salt, salt_length)); + result = dns_dbiterator_seek(dbit, hashname); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + CHECK(dns_dbiterator_current(dbit, &node, NULL)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, &rdataset, + NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_SUCCESS) { + next_length = nsec3.next_length; + INSIST(next_length <= sizeof(nexthash)); + memcpy(nexthash, nsec3.next, next_length); + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_NOMORE) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + pass = 0; + do { + result = dns_dbiterator_prev(dbit); + if (result == ISC_R_NOMORE) { + pass++; + CHECK(dns_dbiterator_last(dbit)); + } + CHECK(dns_dbiterator_current(dbit, &node, prev)); + CHECK(dns_dbiterator_pause(dbit)); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3, 0, + (isc_stdtime_t) 0, + &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + continue; + result = find_nsec3(&nsec3, &rdataset, nsec3param); + if (result == ISC_R_NOMORE) { + dns_rdataset_disassociate(&rdataset); + continue; + } + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Delete the old previous NSEC3. + */ + CHECK(delete(db, version, prev, nsec3param, diff)); + + /* + * Fixup the previous NSEC3. + */ + nsec3.next = nexthash; + nsec3.next_length = next_length; + isc_buffer_init(&buffer, nsec3buf, + sizeof(nsec3buf)); + CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, + dns_rdatatype_nsec3, &nsec3, + &buffer)); + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + prev, rdataset.ttl, &rdata, + &tuple)); + CHECK(do_one_tuple(&tuple, db, version, diff)); + dns_rdata_reset(&rdata); + dns_rdataset_disassociate(&rdataset); + break; + } while (pass < 2); + + INSIST(pass < 2); + + /* + * Delete the old NSEC3 and record the change. + */ + CHECK(delete(db, version, hashname, nsec3param, diff)); + } while (1); + + success: + result = ISC_R_SUCCESS; + + failure: + if (dbit != NULL) + dns_dbiterator_destroy(&dbit); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +isc_result_t +dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL; + dns_rdata_nsec3param_t nsec3param; + dns_rdataset_t rdataset; + isc_result_t result; + + dns_rdataset_init(&rdataset); + + /* + * Find the NSEC3 parameters for this zone. + */ + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, 0, 0, + &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Update each active NSEC3 chain. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + dns_rdata_tostruct(&rdata, &nsec3param, NULL); + +#ifdef RFC5155_STRICT + if (nsec3param.flags != 0) + continue; +#else + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) + continue; + if (better_param(&rdataset, &rdata)) + continue; +#endif + + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff)); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + + return (result); +} + +isc_result_t +dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t complete, isc_boolean_t *answer) +{ + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_nsec3param_t nsec3param; + isc_result_t result; + + REQUIRE(answer != NULL); + + dns_rdataset_init(&rdataset); + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, 0, 0, + &rdataset, NULL); + dns_db_detachnode(db, &node); + + if (result == ISC_R_NOTFOUND) { + *answer = ISC_FALSE; + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS) + return (result); + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if ((nsec3param.flags) == 0 || + (!complete && CREATE(nsec3param.flags))) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) + *answer = ISC_TRUE; + if (result == ISC_R_NOMORE) { + *answer = ISC_FALSE; + result = ISC_R_SUCCESS; + } + return (result); +} + +isc_result_t +dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version, + isc_mem_t *mctx, unsigned int *iterationsp) +{ + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dst_key_t *key = NULL; + isc_buffer_t buffer; + isc_result_t result; + isc_uint16_t bits, minbits = 4096; + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, + 0, 0, &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) { + *iterationsp = 0; + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS) + goto failure; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + isc_buffer_init(&buffer, rdata.data, rdata.length); + isc_buffer_add(&buffer, rdata.length); + CHECK(dst_key_fromdns(dns_db_origin(db), rdataset.rdclass, + &buffer, mctx, &key)); + bits = dst_key_getbits(key); + dst_key_free(&key); + if (minbits > bits) + minbits = bits; + } + if (result != ISC_R_NOMORE) + goto failure; + + if (minbits <= 1024) + *iterationsp = 150; + else if (minbits <= 2048) + *iterationsp = 500; + else + *iterationsp = 2500; + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + return (result); +} diff --git a/lib/dns/openssl_link.c b/lib/dns/openssl_link.c index bb76e0e..2dc7d7e 100644 --- a/lib/dns/openssl_link.c +++ b/lib/dns/openssl_link.c @@ -1,6 +1,19 @@ /* - * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2003 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * * Permission to use, copy, modify, and/or distribute this software for any @@ -18,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: openssl_link.c,v 1.1.6.12 2007/08/28 07:20:04 tbox Exp $ + * $Id: openssl_link.c,v 1.22.112.3 2009/02/11 03:07:01 jinmei Exp $ */ #ifdef OPENSSL @@ -41,22 +54,36 @@ #include <openssl/conf.h> #include <openssl/crypto.h> -#if defined(CRYPTO_LOCK_ENGINE) && (OPENSSL_VERSION_NUMBER != 0x00907000L) +#if defined(CRYPTO_LOCK_ENGINE) && (OPENSSL_VERSION_NUMBER >= 0x0090707f) #define USE_ENGINE 1 #endif #ifdef USE_ENGINE #include <openssl/engine.h> + +#ifdef ENGINE_ID +const char *engine_id = ENGINE_ID; +#else +const char *engine_id; +#endif #endif static RAND_METHOD *rm = NULL; + static isc_mutex_t *locks = NULL; static int nlocks; #ifdef USE_ENGINE static ENGINE *e; +static ENGINE *he; #endif +#ifdef USE_PKCS11 +static isc_result_t +dst__openssl_load_engine(const char *name, const char *engine_id, + const char **pre_cmds, int pre_num, + const char **post_cmds, int post_num); +#endif static int entropy_get(unsigned char *buf, int num) { @@ -68,6 +95,11 @@ entropy_get(unsigned char *buf, int num) { } static int +entropy_status(void) { + return (dst__entropy_status() > 32); +} + +static int entropy_getpseudo(unsigned char *buf, int num) { isc_result_t result; if (num < 0) @@ -116,23 +148,17 @@ mem_free(void *ptr) { static void * mem_realloc(void *ptr, size_t size) { - void *p; - INSIST(dst__memory_pool != NULL); - p = NULL; - if (size > 0U) { - p = mem_alloc(size); - if (p != NULL && ptr != NULL) - memcpy(p, ptr, size); - } - if (ptr != NULL) - mem_free(ptr); - return (p); + return (isc_mem_reallocate(dst__memory_pool, ptr, size)); } isc_result_t dst__openssl_init() { isc_result_t result; +#ifdef USE_ENGINE + /* const char *name; */ + ENGINE *re; +#endif #ifdef DNS_CRYPTO_LEAKS CRYPTO_malloc_debug_init(); @@ -149,6 +175,7 @@ dst__openssl_init() { goto cleanup_mutexalloc; CRYPTO_set_locking_callback(lock_callback); CRYPTO_set_id_callback(id_callback); + rm = mem_alloc(sizeof(RAND_METHOD)); if (rm == NULL) { result = ISC_R_NOMEMORY; @@ -159,18 +186,87 @@ dst__openssl_init() { rm->cleanup = NULL; rm->add = entropy_add; rm->pseudorand = entropy_getpseudo; - rm->status = NULL; + rm->status = entropy_status; #ifdef USE_ENGINE - e = ENGINE_new(); - if (e == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup_rm; + OPENSSL_config(NULL); +#ifdef USE_PKCS11 +#ifndef PKCS11_SO_PATH +#define PKCS11_SO_PATH "/usr/local/lib/engines/engine_pkcs11.so" +#endif +#ifndef PKCS11_MODULE_PATH +#define PKCS11_MODULE_PATH "/usr/lib/libpkcs11.so" +#endif + { + /* + * to use this to config the PIN, add in openssl.cnf: + * - at the beginning: "openssl_conf = openssl_def" + * - at any place these sections: + * [ openssl_def ] + * engines = engine_section + * [ engine_section ] + * pkcs11 = pkcs11_section + * [ pkcs11_section ] + * PIN = my___pin + */ + + const char *pre_cmds[] = { + "SO_PATH", PKCS11_SO_PATH, + "LOAD", NULL, + "MODULE_PATH", PKCS11_MODULE_PATH + }; + const char *post_cmds[] = { + /* "PIN", "my___pin" */ + }; + result = dst__openssl_load_engine("pkcs11", "pkcs11", + pre_cmds, 0, + post_cmds, /*1*/ 0); + if (result != ISC_R_SUCCESS) + goto cleanup_rm; } - ENGINE_set_RAND(e, rm); - RAND_set_rand_method(rm); +#endif /* USE_PKCS11 */ + if (engine_id != NULL) { + e = ENGINE_by_id(engine_id); + if (e == NULL) { + result = ISC_R_NOTFOUND; + goto cleanup_rm; + } + if (!ENGINE_init(e)) { + result = ISC_R_FAILURE; + ENGINE_free(e); + goto cleanup_rm; + } + ENGINE_set_default(e, ENGINE_METHOD_ALL); + ENGINE_free(e); + } else { + ENGINE_register_all_complete(); + for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { + + /* + * Something weird here. If we call ENGINE_finish() + * ENGINE_get_default_RAND() will fail. + */ + if (ENGINE_init(e)) { + if (he == NULL) + he = e; + } + } + } + re = ENGINE_get_default_RAND(); + if (re == NULL) { + re = ENGINE_new(); + if (re == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_rm; + } + ENGINE_set_RAND(re, rm); + ENGINE_set_default_RAND(re); + ENGINE_free(re); + } else + ENGINE_finish(re); + #else RAND_set_rand_method(rm); -#endif +#endif /* USE_ENGINE */ return (ISC_R_SUCCESS); #ifdef USE_ENGINE @@ -195,9 +291,15 @@ dst__openssl_destroy() { CONF_modules_unload(1); #endif EVP_cleanup(); +#if defined(USE_ENGINE) + if (e != NULL) { + ENGINE_finish(e); + e = NULL; + } #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L ENGINE_cleanup(); #endif +#endif #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) CRYPTO_cleanup_all_ex_data(); #endif @@ -209,19 +311,6 @@ dst__openssl_destroy() { CRYPTO_mem_leaks_fp(stderr); #endif -#if 0 - /* - * The old error sequence that leaked. Remove for 9.4.1 if - * there are no issues by then. - */ - ERR_clear_error(); -#ifdef USE_ENGINE - if (e != NULL) { - ENGINE_free(e); - e = NULL; - } -#endif -#endif if (rm != NULL) { #if OPENSSL_VERSION_NUMBER >= 0x00907000L RAND_cleanup(); @@ -251,6 +340,93 @@ dst__openssl_toresult(isc_result_t fallback) { return (result); } +ENGINE * +dst__openssl_getengine(const char *name) { + + UNUSED(name); + + +#if defined(USE_ENGINE) + return (he); +#else + return (NULL); +#endif +} + +isc_result_t +dst__openssl_setdefault(const char *name) { + + UNUSED(name); + +#if defined(USE_ENGINE) + ENGINE_set_default(e, ENGINE_METHOD_ALL); +#endif + /* + * XXXMPA If the engine does not have a default RAND method + * restore our method. + */ + return (ISC_R_SUCCESS); +} + +#ifdef USE_PKCS11 +/* + * 'name' is the name the engine is known by to the dst library. + * This may or may not match the name the engine is known by to + * openssl. It is the name that is stored in the private key file. + * + * 'engine_id' is the openssl engine name. + * + * pre_cmds and post_cmds a sequence if command argument pairs + * pre_num and post_num are a count of those pairs. + * + * "SO_PATH", PKCS11_SO_PATH ("/usr/local/lib/engines/engine_pkcs11.so") + * "LOAD", NULL + * "MODULE_PATH", PKCS11_MODULE_PATH ("/usr/lib/libpkcs11.so") + */ +static isc_result_t +dst__openssl_load_engine(const char *name, const char *engine_id, + const char **pre_cmds, int pre_num, + const char **post_cmds, int post_num) +{ + ENGINE *e; + + UNUSED(name); + + if (!strcasecmp(engine_id, "dynamic")) + ENGINE_load_dynamic(); + e = ENGINE_by_id(engine_id); + if (e == NULL) + return (ISC_R_NOTFOUND); + while (pre_num--) { + if (!ENGINE_ctrl_cmd_string(e, pre_cmds[0], pre_cmds[1], 0)) { + ENGINE_free(e); + return (ISC_R_FAILURE); + } + pre_cmds += 2; + } + if (!ENGINE_init(e)) { + ENGINE_free(e); + return (ISC_R_FAILURE); + } + /* + * ENGINE_init() returned a functional reference, so free the + * structural reference from ENGINE_by_id(). + */ + ENGINE_free(e); + while (post_num--) { + if (!ENGINE_ctrl_cmd_string(e, post_cmds[0], post_cmds[1], 0)) { + ENGINE_free(e); + return (ISC_R_FAILURE); + } + post_cmds += 2; + } + if (he != NULL) + ENGINE_finish(he); + he = e; + return (ISC_R_SUCCESS); +} +#endif /* USE_PKCS11 */ + #else /* OPENSSL */ #include <isc/util.h> diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index 8f47482..abc3b7c 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -1,6 +1,19 @@ /* - * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * * Permission to use, copy, modify, and/or distribute this software for any @@ -18,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: openssldh_link.c,v 1.1.6.10 2007/08/28 07:20:04 tbox Exp $ + * $Id: openssldh_link.c,v 1.14 2008/04/01 23:47:10 tbox Exp $ */ #ifdef OPENSSL @@ -37,8 +50,6 @@ #include "dst_openssl.h" #include "dst_parse.h" -#include <openssl/dh.h> - #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \ "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \ "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF" @@ -71,11 +82,11 @@ openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, isc_region_t r; unsigned int len; - REQUIRE(pub->opaque != NULL); - REQUIRE(priv->opaque != NULL); + REQUIRE(pub->keydata.dh != NULL); + REQUIRE(priv->keydata.dh != NULL); - dhpub = (DH *) pub->opaque; - dhpriv = (DH *) priv->opaque; + dhpub = pub->keydata.dh; + dhpriv = priv->keydata.dh; len = DH_size(dhpriv); isc_buffer_availableregion(secret, &r); @@ -93,8 +104,8 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { int status; DH *dh1, *dh2; - dh1 = (DH *) key1->opaque; - dh2 = (DH *) key2->opaque; + dh1 = key1->keydata.dh; + dh2 = key2->keydata.dh; if (dh1 == NULL && dh2 == NULL) return (ISC_TRUE); @@ -122,8 +133,8 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { int status; DH *dh1, *dh2; - dh1 = (DH *) key1->opaque; - dh2 = (DH *) key2->opaque; + dh1 = key1->keydata.dh; + dh2 = key2->keydata.dh; if (dh1 == NULL && dh2 == NULL) return (ISC_TRUE); @@ -141,7 +152,7 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { static isc_result_t openssldh_generate(dst_key_t *key, int generator) { #if OPENSSL_VERSION_NUMBER > 0x00908000L - BN_GENCB cb; + BN_GENCB cb; #endif DH *dh = NULL; @@ -192,20 +203,20 @@ openssldh_generate(dst_key_t *key, int generator) { } dh->flags &= ~DH_FLAG_CACHE_MONT_P; - key->opaque = dh; + key->keydata.dh = dh; return (ISC_R_SUCCESS); } static isc_boolean_t openssldh_isprivate(const dst_key_t *key) { - DH *dh = (DH *) key->opaque; + DH *dh = key->keydata.dh; return (ISC_TF(dh != NULL && dh->priv_key != NULL)); } static void openssldh_destroy(dst_key_t *key) { - DH *dh = key->opaque; + DH *dh = key->keydata.dh; if (dh == NULL) return; @@ -215,7 +226,7 @@ openssldh_destroy(dst_key_t *key) { if (dh->g == &bn2) dh->g = NULL; DH_free(dh); - key->opaque = NULL; + key->keydata.dh = NULL; } static void @@ -242,9 +253,9 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { isc_region_t r; isc_uint16_t dnslen, plen, glen, publen; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.dh != NULL); - dh = (DH *) key->opaque; + dh = key->keydata.dh; isc_buffer_availableregion(data, &r); @@ -401,7 +412,7 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_buffer_forward(data, plen + glen + publen + 6); - key->opaque = (void *) dh; + key->keydata.dh = dh; return (ISC_R_SUCCESS); } @@ -414,10 +425,10 @@ openssldh_tofile(const dst_key_t *key, const char *directory) { unsigned char *bufs[4]; isc_result_t result; - if (key->opaque == NULL) + if (key->keydata.dh == NULL) return (DST_R_NULLKEY); - dh = (DH *) key->opaque; + dh = key->keydata.dh; for (i = 0; i < 4; i++) { bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p)); @@ -484,7 +495,7 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer) { if (dh == NULL) DST_RET(ISC_R_NOMEMORY); dh->flags &= ~DH_FLAG_CACHE_MONT_P; - key->opaque = dh; + key->keydata.dh = dh; for (i = 0; i < priv.nelements; i++) { BIGNUM *bn; @@ -597,6 +608,7 @@ static dst_func_t openssldh_functions = { openssldh_tofile, openssldh_parse, openssldh_cleanup, + NULL, /*%< fromlabel */ }; isc_result_t diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c index 2ff33f32..14e89e1 100644 --- a/lib/dns/openssldsa_link.c +++ b/lib/dns/openssldsa_link.c @@ -1,6 +1,19 @@ /* - * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. + * + * 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 AND NETWORK ASSOCIATES 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. + * * Portions Copyright (C) 1995-2000 by Network Associates, Inc. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,9 +29,12 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: openssldsa_link.c,v 1.1.6.9.28.1 2008/12/24 00:21:22 marka Exp $ */ +/* $Id: openssldsa_link.c,v 1.13.120.2 2009/01/14 23:47:26 tbox Exp $ */ #ifdef OPENSSL +#ifndef USE_EVP +#define USE_EVP 1 +#endif #include <config.h> @@ -41,32 +57,68 @@ static isc_result_t openssldsa_todns(const dst_key_t *key, isc_buffer_t *data); static isc_result_t openssldsa_createctx(dst_key_t *key, dst_context_t *dctx) { +#if USE_EVP + EVP_MD_CTX *evp_md_ctx; + + UNUSED(key); + + evp_md_ctx = EVP_MD_CTX_create(); + if (evp_md_ctx == NULL) + return (ISC_R_NOMEMORY); + + if (!EVP_DigestInit_ex(evp_md_ctx, EVP_dss1(), NULL)) { + EVP_MD_CTX_destroy(evp_md_ctx); + return (ISC_R_FAILURE); + } + + dctx->ctxdata.evp_md_ctx = evp_md_ctx; + + return (ISC_R_SUCCESS); +#else isc_sha1_t *sha1ctx; UNUSED(key); sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t)); isc_sha1_init(sha1ctx); - dctx->opaque = sha1ctx; + dctx->ctxdata.sha1ctx = sha1ctx; return (ISC_R_SUCCESS); +#endif } static void openssldsa_destroyctx(dst_context_t *dctx) { - isc_sha1_t *sha1ctx = dctx->opaque; +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + + if (evp_md_ctx != NULL) { + EVP_MD_CTX_destroy(evp_md_ctx); + dctx->ctxdata.evp_md_ctx = NULL; + } +#else + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; if (sha1ctx != NULL) { isc_sha1_invalidate(sha1ctx); isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t)); - dctx->opaque = NULL; + dctx->ctxdata.sha1ctx = NULL; } +#endif } static isc_result_t openssldsa_adddata(dst_context_t *dctx, const isc_region_t *data) { - isc_sha1_t *sha1ctx = dctx->opaque; +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + + if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) { + return (ISC_R_FAILURE); + } +#else + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; isc_sha1_update(sha1ctx, data->base, data->length); +#endif return (ISC_R_SUCCESS); } @@ -81,23 +133,72 @@ BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) { static isc_result_t openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { - isc_sha1_t *sha1ctx = dctx->opaque; dst_key_t *key = dctx->key; - DSA *dsa = key->opaque; - DSA_SIG *dsasig; + DSA *dsa = key->keydata.dsa; isc_region_t r; + DSA_SIG *dsasig; +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + EVP_PKEY *pkey; + unsigned char *sigbuf; + const unsigned char *sb; + unsigned int siglen; +#else + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; unsigned char digest[ISC_SHA1_DIGESTLENGTH]; +#endif isc_buffer_availableregion(sig, &r); if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1) return (ISC_R_NOSPACE); +#if USE_EVP + pkey = EVP_PKEY_new(); + if (pkey == NULL) + return (ISC_R_NOMEMORY); + if (!EVP_PKEY_set1_DSA(pkey, dsa)) { + EVP_PKEY_free(pkey); + return (ISC_R_FAILURE); + } + sigbuf = malloc(EVP_PKEY_size(pkey)); + if (sigbuf == NULL) { + EVP_PKEY_free(pkey); + return (ISC_R_NOMEMORY); + } + if (!EVP_SignFinal(evp_md_ctx, sigbuf, &siglen, pkey)) { + EVP_PKEY_free(pkey); + free(sigbuf); + return (ISC_R_FAILURE); + } + INSIST(EVP_PKEY_size(pkey) >= (int) siglen); + EVP_PKEY_free(pkey); + /* Convert from Dss-Sig-Value (RFC2459). */ + dsasig = DSA_SIG_new(); + if (dsasig == NULL) { + free(sigbuf); + return (ISC_R_NOMEMORY); + } + sb = sigbuf; + if (d2i_DSA_SIG(&dsasig, &sb, (long) siglen) == NULL) { + free(sigbuf); + return (ISC_R_FAILURE); + } + free(sigbuf); +#elif 0 + /* Only use EVP for the Digest */ + if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &siglen)) { + return (ISC_R_FAILURE); + } + dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa); + if (dsasig == NULL) + return (dst__openssl_toresult(DST_R_SIGNFAILURE)); +#else isc_sha1_final(sha1ctx, digest); dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa); if (dsasig == NULL) return (dst__openssl_toresult(DST_R_SIGNFAILURE)); - +#endif *r.base++ = (key->key_size - 512)/64; BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH); r.base += ISC_SHA1_DIGESTLENGTH; @@ -111,27 +212,70 @@ openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t openssldsa_verify(dst_context_t *dctx, const isc_region_t *sig) { - isc_sha1_t *sha1ctx = dctx->opaque; dst_key_t *key = dctx->key; - DSA *dsa = key->opaque; - DSA_SIG *dsasig; + DSA *dsa = key->keydata.dsa; int status = 0; - unsigned char digest[ISC_SHA1_DIGESTLENGTH]; unsigned char *cp = sig->base; + DSA_SIG *dsasig; +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; +#if 0 + EVP_PKEY *pkey; + unsigned char *sigbuf; +#endif + unsigned int siglen; +#else + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; +#endif + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + +#if USE_EVP +#if 1 + /* Only use EVP for the digest */ + if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &siglen)) { + return (ISC_R_FAILURE); + } +#endif +#else isc_sha1_final(sha1ctx, digest); +#endif - if (sig->length < 2 * ISC_SHA1_DIGESTLENGTH + 1) + if (sig->length != 2 * ISC_SHA1_DIGESTLENGTH + 1) { return (DST_R_VERIFYFAILURE); + } cp++; /*%< Skip T */ dsasig = DSA_SIG_new(); + if (dsasig == NULL) + return (ISC_R_NOMEMORY); dsasig->r = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL); cp += ISC_SHA1_DIGESTLENGTH; dsasig->s = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL); cp += ISC_SHA1_DIGESTLENGTH; +#if 0 + pkey = EVP_PKEY_new(); + if (pkey == NULL) + return (ISC_R_NOMEMORY); + if (!EVP_PKEY_set1_DSA(pkey, dsa)) { + EVP_PKEY_free(pkey); + return (ISC_R_FAILURE); + } + /* Convert to Dss-Sig-Value (RFC2459). */ + sigbuf = malloc(EVP_PKEY_size(pkey) + 50); + if (sigbuf == NULL) { + EVP_PKEY_free(pkey); + return (ISC_R_NOMEMORY); + } + siglen = (unsigned) i2d_DSA_SIG(dsasig, &sigbuf); + INSIST(EVP_PKEY_size(pkey) >= (int) siglen); + status = EVP_VerifyFinal(evp_md_ctx, sigbuf, siglen, pkey); + EVP_PKEY_free(pkey); + free(sigbuf); +#else status = DSA_do_verify(digest, ISC_SHA1_DIGESTLENGTH, dsasig, dsa); +#endif DSA_SIG_free(dsasig); if (status != 1) return (dst__openssl_toresult(DST_R_VERIFYFAILURE)); @@ -144,8 +288,8 @@ openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) { int status; DSA *dsa1, *dsa2; - dsa1 = (DSA *) key1->opaque; - dsa2 = (DSA *) key2->opaque; + dsa1 = key1->keydata.dsa; + dsa2 = key2->keydata.dsa; if (dsa1 == NULL && dsa2 == NULL) return (ISC_TRUE); @@ -172,7 +316,7 @@ openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) { static isc_result_t openssldsa_generate(dst_key_t *key, int unused) { #if OPENSSL_VERSION_NUMBER > 0x00908000L - BN_GENCB cb; + BN_GENCB cb; #endif DSA *dsa; unsigned char rand_array[ISC_SHA1_DIGESTLENGTH]; @@ -186,12 +330,12 @@ openssldsa_generate(dst_key_t *key, int unused) { return (result); #if OPENSSL_VERSION_NUMBER > 0x00908000L - dsa = DSA_new(); + dsa = DSA_new(); if (dsa == NULL) return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); BN_GENCB_set_old(&cb, NULL, NULL); - + if (!DSA_generate_parameters_ex(dsa, key->key_size, rand_array, ISC_SHA1_DIGESTLENGTH, NULL, NULL, &cb)) @@ -213,22 +357,22 @@ openssldsa_generate(dst_key_t *key, int unused) { } dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; - key->opaque = dsa; + key->keydata.dsa = dsa; return (ISC_R_SUCCESS); } static isc_boolean_t openssldsa_isprivate(const dst_key_t *key) { - DSA *dsa = (DSA *) key->opaque; + DSA *dsa = key->keydata.dsa; return (ISC_TF(dsa != NULL && dsa->priv_key != NULL)); } static void openssldsa_destroy(dst_key_t *key) { - DSA *dsa = key->opaque; + DSA *dsa = key->keydata.dsa; DSA_free(dsa); - key->opaque = NULL; + key->keydata.dsa = NULL; } @@ -239,9 +383,9 @@ openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) { int dnslen; unsigned int t, p_bytes; - REQUIRE(key->opaque != NULL); + REQUIRE(key->keydata.dsa != NULL); - dsa = (DSA *) key->opaque; + dsa = key->keydata.dsa; isc_buffer_availableregion(data, &r); @@ -315,7 +459,7 @@ openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes); - key->opaque = (void *) dsa; + key->keydata.dsa = dsa; return (ISC_R_SUCCESS); } @@ -328,10 +472,10 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) { dst_private_t priv; unsigned char bufs[5][128]; - if (key->opaque == NULL) + if (key->keydata.dsa == NULL) return (DST_R_NULLKEY); - dsa = (DSA *) key->opaque; + dsa = key->keydata.dsa; priv.elements[cnt].tag = TAG_DSA_PRIME; priv.elements[cnt].length = BN_num_bytes(dsa->p); @@ -385,7 +529,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) { if (dsa == NULL) DST_RET(ISC_R_NOMEMORY); dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; - key->opaque = dsa; + key->keydata.dsa = dsa; for (i=0; i < priv.nelements; i++) { BIGNUM *bn; @@ -442,6 +586,7 @@ static dst_func_t openssldsa_functions = { openssldsa_tofile, openssldsa_parse, NULL, /*%< cleanup */ + NULL, /*%< fromlabel */ }; isc_result_t diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index aacba45..d557c43 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -17,9 +17,15 @@ /* * Principal Author: Brian Wellington - * $Id: opensslrsa_link.c,v 1.1.6.11.58.1 2008/12/24 00:21:22 marka Exp $ + * $Id: opensslrsa_link.c,v 1.20.50.3 2009/01/18 23:25:16 marka Exp $ */ #ifdef OPENSSL +#ifndef USE_EVP +#define USE_EVP 1 +#endif +#if USE_EVP +#define USE_EVP_RSA 1 +#endif #include <config.h> @@ -42,6 +48,7 @@ #if OPENSSL_VERSION_NUMBER > 0x00908000L #include <openssl/bn.h> #endif +#include <openssl/engine.h> /* * We don't use configure for windows so enforce the OpenSSL version @@ -57,8 +64,8 @@ /* - * XXXMPA Temporarially disable RSA_BLINDING as it requires - * good quality random data that cannot currently be guarenteed. + * XXXMPA Temporarily disable RSA_BLINDING as it requires + * good quality random data that cannot currently be guaranteed. * XXXMPA Find which versions of openssl use pseudo random data * and set RSA_FLAG_BLINDING for those. */ @@ -97,14 +104,38 @@ } while (0) #endif +#define DST_RET(a) {ret = a; goto err;} + static isc_result_t opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data); static isc_result_t opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) { +#if USE_EVP + EVP_MD_CTX *evp_md_ctx; + const EVP_MD *type; +#endif + UNUSED(key); REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || - dctx->key->key_alg == DST_ALG_RSASHA1); + dctx->key->key_alg == DST_ALG_RSASHA1 || + dctx->key->key_alg == DST_ALG_NSEC3RSASHA1); +#if USE_EVP + evp_md_ctx = EVP_MD_CTX_create(); + if (evp_md_ctx == NULL) + return (ISC_R_NOMEMORY); + + if (dctx->key->key_alg == DST_ALG_RSAMD5) + type = EVP_md5(); /* MD5 + RSA */ + else + type = EVP_sha1(); /* SHA1 + RSA */ + + if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) { + EVP_MD_CTX_destroy(evp_md_ctx); + return (ISC_R_FAILURE); + } + dctx->ctxdata.evp_md_ctx = evp_md_ctx; +#else if (dctx->key->key_alg == DST_ALG_RSAMD5) { isc_md5_t *md5ctx; @@ -112,7 +143,7 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) { if (md5ctx == NULL) return (ISC_R_NOMEMORY); isc_md5_init(md5ctx); - dctx->opaque = md5ctx; + dctx->ctxdata.md5ctx = md5ctx; } else { isc_sha1_t *sha1ctx; @@ -120,58 +151,87 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) { if (sha1ctx == NULL) return (ISC_R_NOMEMORY); isc_sha1_init(sha1ctx); - dctx->opaque = sha1ctx; + dctx->ctxdata.sha1ctx = sha1ctx; } +#endif return (ISC_R_SUCCESS); } static void opensslrsa_destroyctx(dst_context_t *dctx) { +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; +#endif + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || - dctx->key->key_alg == DST_ALG_RSASHA1); + dctx->key->key_alg == DST_ALG_RSASHA1 || + dctx->key->key_alg == DST_ALG_NSEC3RSASHA1); +#if USE_EVP + if (evp_md_ctx != NULL) { + EVP_MD_CTX_destroy(evp_md_ctx); + dctx->ctxdata.evp_md_ctx = NULL; + } +#else if (dctx->key->key_alg == DST_ALG_RSAMD5) { - isc_md5_t *md5ctx = dctx->opaque; + isc_md5_t *md5ctx = dctx->ctxdata.md5ctx; if (md5ctx != NULL) { isc_md5_invalidate(md5ctx); isc_mem_put(dctx->mctx, md5ctx, sizeof(isc_md5_t)); + dctx->ctxdata.md5ctx = NULL; } } else { - isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; if (sha1ctx != NULL) { isc_sha1_invalidate(sha1ctx); isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t)); + dctx->ctxdata.sha1ctx = NULL; } } - dctx->opaque = NULL; +#endif } static isc_result_t opensslrsa_adddata(dst_context_t *dctx, const isc_region_t *data) { +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; +#endif + REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || - dctx->key->key_alg == DST_ALG_RSASHA1); + dctx->key->key_alg == DST_ALG_RSASHA1 || + dctx->key->key_alg == DST_ALG_NSEC3RSASHA1); +#if USE_EVP + if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) { + return (ISC_R_FAILURE); + } +#else if (dctx->key->key_alg == DST_ALG_RSAMD5) { - isc_md5_t *md5ctx = dctx->opaque; + isc_md5_t *md5ctx = dctx->ctxdata.md5ctx; isc_md5_update(md5ctx, data->base, data->length); } else { - isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; isc_sha1_update(sha1ctx, data->base, data->length); } +#endif return (ISC_R_SUCCESS); } static isc_result_t opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { dst_key_t *key = dctx->key; - RSA *rsa = key->opaque; isc_region_t r; + unsigned int siglen = 0; +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + EVP_PKEY *pkey = key->keydata.pkey; +#else + RSA *rsa = key->keydata.rsa; /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */ unsigned char digest[ISC_SHA1_DIGESTLENGTH]; - unsigned int siglen = 0; int status; int type; unsigned int digestlen; @@ -179,22 +239,32 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { unsigned long err; const char* file; int line; +#endif REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || - dctx->key->key_alg == DST_ALG_RSASHA1); + dctx->key->key_alg == DST_ALG_RSASHA1 || + dctx->key->key_alg == DST_ALG_NSEC3RSASHA1); isc_buffer_availableregion(sig, &r); +#if USE_EVP + if (r.length < (unsigned int) EVP_PKEY_size(pkey)) + return (ISC_R_NOSPACE); + + if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey)) { + return (ISC_R_FAILURE); + } +#else if (r.length < (unsigned int) RSA_size(rsa)) return (ISC_R_NOSPACE); if (dctx->key->key_alg == DST_ALG_RSAMD5) { - isc_md5_t *md5ctx = dctx->opaque; + isc_md5_t *md5ctx = dctx->ctxdata.md5ctx; isc_md5_final(md5ctx, digest); type = NID_md5; digestlen = ISC_MD5_DIGESTLENGTH; } else { - isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; isc_sha1_final(sha1ctx, digest); type = NID_sha1; digestlen = ISC_SHA1_DIGESTLENGTH; @@ -205,11 +275,10 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { err = ERR_peek_error_line(&file, &line); if (err != 0U) { message = ERR_error_string(err, NULL); - fprintf(stderr, "%s:%s:%d\n", message, - file ? file : "", line); } return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); } +#endif isc_buffer_add(sig, siglen); @@ -219,23 +288,32 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { static isc_result_t opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { dst_key_t *key = dctx->key; - RSA *rsa = key->opaque; + int status = 0; +#if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + EVP_PKEY *pkey = key->keydata.pkey; +#else /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */ unsigned char digest[ISC_SHA1_DIGESTLENGTH]; - int status = 0; int type; unsigned int digestlen; + RSA *rsa = key->keydata.rsa; +#endif REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 || - dctx->key->key_alg == DST_ALG_RSASHA1); + dctx->key->key_alg == DST_ALG_RSASHA1 || + dctx->key->key_alg == DST_ALG_NSEC3RSASHA1); +#if USE_EVP + status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey); +#else if (dctx->key->key_alg == DST_ALG_RSAMD5) { - isc_md5_t *md5ctx = dctx->opaque; + isc_md5_t *md5ctx = dctx->ctxdata.md5ctx; isc_md5_final(md5ctx, digest); type = NID_md5; digestlen = ISC_MD5_DIGESTLENGTH; } else { - isc_sha1_t *sha1ctx = dctx->opaque; + isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx; isc_sha1_final(sha1ctx, digest); type = NID_sha1; digestlen = ISC_SHA1_DIGESTLENGTH; @@ -246,6 +324,7 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { status = RSA_verify(type, digest, digestlen, sig->base, RSA_size(rsa), rsa); +#endif if (status != 1) return (dst__openssl_toresult(DST_R_VERIFYFAILURE)); @@ -255,10 +334,30 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) { static isc_boolean_t opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) { int status; - RSA *rsa1, *rsa2; + RSA *rsa1 = NULL, *rsa2 = NULL; +#if USE_EVP + EVP_PKEY *pkey1, *pkey2; +#endif - rsa1 = (RSA *) key1->opaque; - rsa2 = (RSA *) key2->opaque; +#if USE_EVP + pkey1 = key1->keydata.pkey; + pkey2 = key2->keydata.pkey; + /* + * The pkey reference will keep these around after + * the RSA_free() call. + */ + if (pkey1 != NULL) { + rsa1 = EVP_PKEY_get1_RSA(pkey1); + RSA_free(rsa1); + } + if (pkey2 != NULL) { + rsa2 = EVP_PKEY_get1_RSA(pkey2); + RSA_free(rsa2); + } +#else + rsa1 = key1->keydata.rsa; + rsa2 = key2->keydata.rsa; +#endif if (rsa1 == NULL && rsa2 == NULL) return (ISC_TRUE); @@ -271,6 +370,19 @@ opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) { if (status != 0) return (ISC_FALSE); +#if USE_EVP + if ((rsa1->flags & RSA_FLAG_EXT_PKEY) != 0 || + (rsa2->flags & RSA_FLAG_EXT_PKEY) != 0) { + if ((rsa1->flags & RSA_FLAG_EXT_PKEY) == 0 || + (rsa2->flags & RSA_FLAG_EXT_PKEY) == 0) + return (ISC_FALSE); + /* + * Can't compare private parameters, BTW does it make sense? + */ + return (ISC_TRUE); + } +#endif + if (rsa1->d != NULL || rsa2->d != NULL) { if (rsa1->d == NULL || rsa2->d == NULL) return (ISC_FALSE); @@ -290,9 +402,18 @@ opensslrsa_generate(dst_key_t *key, int exp) { BN_GENCB cb; RSA *rsa = RSA_new(); BIGNUM *e = BN_new(); +#if USE_EVP + EVP_PKEY *pkey = EVP_PKEY_new(); +#endif if (rsa == NULL || e == NULL) goto err; +#if USE_EVP + if (pkey == NULL) + goto err; + if (!EVP_PKEY_set1_RSA(pkey, rsa)) + goto err; +#endif if (exp == 0) { /* RSA_F4 0x10001 */ @@ -309,11 +430,21 @@ opensslrsa_generate(dst_key_t *key, int exp) { if (RSA_generate_key_ex(rsa, key->key_size, e, &cb)) { BN_free(e); SET_FLAGS(rsa); - key->opaque = rsa; +#if USE_EVP + key->keydata.pkey = pkey; + + RSA_free(rsa); +#else + key->keydata.rsa = rsa; +#endif return (ISC_R_SUCCESS); } err: +#if USE_EVP + if (pkey != NULL) + EVP_PKEY_free(pkey); +#endif if (e != NULL) BN_free(e); if (rsa != NULL) @@ -322,16 +453,36 @@ err: #else RSA *rsa; unsigned long e; +#if USE_EVP + EVP_PKEY *pkey = EVP_PKEY_new(); + + if (pkey == NULL) + return (ISC_R_NOMEMORY); +#endif if (exp == 0) e = RSA_F4; else e = 0x40000003; rsa = RSA_generate_key(key->key_size, e, NULL, NULL); - if (rsa == NULL) - return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + if (rsa == NULL) { +#if USE_EVP + EVP_PKEY_free(pkey); +#endif + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } SET_FLAGS(rsa); - key->opaque = rsa; +#if USE_EVP + if (!EVP_PKEY_set1_RSA(pkey, rsa)) { + EVP_PKEY_free(pkey); + RSA_free(rsa); + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + key->keydata.pkey = pkey; + RSA_free(rsa); +#else + key->keydata.rsa = rsa; +#endif return (ISC_R_SUCCESS); #endif @@ -339,28 +490,58 @@ err: static isc_boolean_t opensslrsa_isprivate(const dst_key_t *key) { - RSA *rsa = (RSA *) key->opaque; +#if USE_EVP + RSA *rsa = EVP_PKEY_get1_RSA(key->keydata.pkey); + INSIST(rsa != NULL); + RSA_free(rsa); + /* key->keydata.pkey still has a reference so rsa is still valid. */ +#else + RSA *rsa = key->keydata.rsa; +#endif + if (rsa != NULL && (rsa->flags & RSA_FLAG_EXT_PKEY) != 0) + return (ISC_TRUE); return (ISC_TF(rsa != NULL && rsa->d != NULL)); } static void opensslrsa_destroy(dst_key_t *key) { - RSA *rsa = key->opaque; +#if USE_EVP + EVP_PKEY *pkey = key->keydata.pkey; + EVP_PKEY_free(pkey); + key->keydata.pkey = NULL; +#else + RSA *rsa = key->keydata.rsa; RSA_free(rsa); - key->opaque = NULL; + key->keydata.rsa = NULL; +#endif } static isc_result_t opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { - RSA *rsa; isc_region_t r; unsigned int e_bytes; unsigned int mod_bytes; + isc_result_t ret; + RSA *rsa; +#if USE_EVP + EVP_PKEY *pkey; +#endif - REQUIRE(key->opaque != NULL); +#if USE_EVP + REQUIRE(key->keydata.pkey != NULL); +#else + REQUIRE(key->keydata.rsa != NULL); +#endif - rsa = (RSA *) key->opaque; +#if USE_EVP + pkey = key->keydata.pkey; + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +#else + rsa = key->keydata.rsa; +#endif isc_buffer_availableregion(data, &r); @@ -369,11 +550,11 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { if (e_bytes < 256) { /*%< key exponent is <= 2040 bits */ if (r.length < 1) - return (ISC_R_NOSPACE); + DST_RET(ISC_R_NOSPACE); isc_buffer_putuint8(data, (isc_uint8_t) e_bytes); } else { if (r.length < 3) - return (ISC_R_NOSPACE); + DST_RET(ISC_R_NOSPACE); isc_buffer_putuint8(data, 0); isc_buffer_putuint16(data, (isc_uint16_t) e_bytes); } @@ -388,7 +569,13 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) { isc_buffer_add(data, e_bytes + mod_bytes); - return (ISC_R_SUCCESS); + ret = ISC_R_SUCCESS; + err: +#if USE_EVP + if (rsa != NULL) + RSA_free(rsa); +#endif + return (ret); } static isc_result_t @@ -396,6 +583,9 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { RSA *rsa; isc_region_t r; unsigned int e_bytes; +#if USE_EVP + EVP_PKEY *pkey; +#endif isc_buffer_remainingregion(data, &r); if (r.length == 0) @@ -437,12 +627,26 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { isc_buffer_forward(data, r.length); - key->opaque = (void *) rsa; +#if USE_EVP + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + RSA_free(rsa); + return (ISC_R_NOMEMORY); + } + if (!EVP_PKEY_set1_RSA(pkey, rsa)) { + EVP_PKEY_free(pkey); + RSA_free(rsa); + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } + key->keydata.pkey = pkey; + RSA_free(rsa); +#else + key->keydata.rsa = rsa; +#endif return (ISC_R_SUCCESS); } - static isc_result_t opensslrsa_tofile(const dst_key_t *key, const char *directory) { int i; @@ -451,10 +655,17 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { unsigned char *bufs[8]; isc_result_t result; - if (key->opaque == NULL) +#if USE_EVP + if (key->keydata.pkey == NULL) return (DST_R_NULLKEY); - - rsa = (RSA *) key->opaque; + rsa = EVP_PKEY_get1_RSA(key->keydata.pkey); + if (rsa == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +#else + if (key->keydata.rsa == NULL) + return (DST_R_NULLKEY); + rsa = key->keydata.rsa; +#endif for (i = 0; i < 8; i++) { bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n)); @@ -478,45 +689,74 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { priv.elements[i].data = bufs[i]; i++; - priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT; - priv.elements[i].length = BN_num_bytes(rsa->d); - BN_bn2bin(rsa->d, bufs[i]); - priv.elements[i].data = bufs[i]; - i++; + if (rsa->d != NULL) { + priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT; + priv.elements[i].length = BN_num_bytes(rsa->d); + BN_bn2bin(rsa->d, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + } - priv.elements[i].tag = TAG_RSA_PRIME1; - priv.elements[i].length = BN_num_bytes(rsa->p); - BN_bn2bin(rsa->p, bufs[i]); - priv.elements[i].data = bufs[i]; - i++; + if (rsa->p != NULL) { + priv.elements[i].tag = TAG_RSA_PRIME1; + priv.elements[i].length = BN_num_bytes(rsa->p); + BN_bn2bin(rsa->p, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + } - priv.elements[i].tag = TAG_RSA_PRIME2; - priv.elements[i].length = BN_num_bytes(rsa->q); - BN_bn2bin(rsa->q, bufs[i]); - priv.elements[i].data = bufs[i]; - i++; + if (rsa->q != NULL) { + priv.elements[i].tag = TAG_RSA_PRIME2; + priv.elements[i].length = BN_num_bytes(rsa->q); + BN_bn2bin(rsa->q, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + } - priv.elements[i].tag = TAG_RSA_EXPONENT1; - priv.elements[i].length = BN_num_bytes(rsa->dmp1); - BN_bn2bin(rsa->dmp1, bufs[i]); - priv.elements[i].data = bufs[i]; - i++; + if (rsa->dmp1 != NULL) { + priv.elements[i].tag = TAG_RSA_EXPONENT1; + priv.elements[i].length = BN_num_bytes(rsa->dmp1); + BN_bn2bin(rsa->dmp1, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + } - priv.elements[i].tag = TAG_RSA_EXPONENT2; - priv.elements[i].length = BN_num_bytes(rsa->dmq1); - BN_bn2bin(rsa->dmq1, bufs[i]); - priv.elements[i].data = bufs[i]; - i++; + if (rsa->dmq1 != NULL) { + priv.elements[i].tag = TAG_RSA_EXPONENT2; + priv.elements[i].length = BN_num_bytes(rsa->dmq1); + BN_bn2bin(rsa->dmq1, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + } - priv.elements[i].tag = TAG_RSA_COEFFICIENT; - priv.elements[i].length = BN_num_bytes(rsa->iqmp); - BN_bn2bin(rsa->iqmp, bufs[i]); - priv.elements[i].data = bufs[i]; - i++; + if (rsa->iqmp != NULL) { + priv.elements[i].tag = TAG_RSA_COEFFICIENT; + priv.elements[i].length = BN_num_bytes(rsa->iqmp); + BN_bn2bin(rsa->iqmp, bufs[i]); + priv.elements[i].data = bufs[i]; + i++; + } + + if (key->engine != NULL) { + priv.elements[i].tag = TAG_RSA_ENGINE; + priv.elements[i].length = strlen(key->engine) + 1; + priv.elements[i].data = (unsigned char *)key->engine; + i++; + } + + if (key->label != NULL) { + priv.elements[i].tag = TAG_RSA_LABEL; + priv.elements[i].length = strlen(key->label) + 1; + priv.elements[i].data = (unsigned char *)key->label; + i++; + } priv.nelements = i; result = dst__privstruct_writefile(key, &priv, directory); fail: +#if USE_EVP + RSA_free(rsa); +#endif for (i = 0; i < 8; i++) { if (bufs[i] == NULL) break; @@ -531,26 +771,94 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { isc_result_t ret; int i; RSA *rsa = NULL; + ENGINE *e = NULL; isc_mem_t *mctx = key->mctx; -#define DST_RET(a) {ret = a; goto err;} + const char *name = NULL, *label = NULL; + EVP_PKEY *pkey = NULL; /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) return (ret); + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_RSA_ENGINE: + name = (char *)priv.elements[i].data; + break; + case TAG_RSA_LABEL: + label = (char *)priv.elements[i].data; + break; + default: + break; + } + } + /* + * Is this key is stored in a HSM? + * See if we can fetch it. + */ + if (name != NULL || label != NULL) { + INSIST(name != NULL); + INSIST(label != NULL); + e = dst__openssl_getengine(name); + if (e == NULL) + DST_RET(DST_R_NOENGINE); + pkey = ENGINE_load_private_key(e, label, NULL, NULL); + if (pkey == NULL) { + ERR_print_errors_fp(stderr); + DST_RET(ISC_R_FAILURE); + } + key->engine = isc_mem_strdup(key->mctx, name); + if (key->engine == NULL) + DST_RET(ISC_R_NOMEMORY); + key->label = isc_mem_strdup(key->mctx, label); + if (key->label == NULL) + DST_RET(ISC_R_NOMEMORY); + key->key_size = EVP_PKEY_bits(pkey); +#if USE_EVP + key->keydata.pkey = pkey; +#else + key->keydata.rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + EVP_PKEY_free(pkey); +#endif + dst__privstruct_free(&priv, mctx); + return (ISC_R_SUCCESS); + } + rsa = RSA_new(); if (rsa == NULL) DST_RET(ISC_R_NOMEMORY); SET_FLAGS(rsa); - key->opaque = rsa; + +#if USE_EVP + pkey = EVP_PKEY_new(); + if (pkey == NULL) + DST_RET(ISC_R_NOMEMORY); + if (!EVP_PKEY_set1_RSA(pkey, rsa)) { + DST_RET(ISC_R_FAILURE); + } + key->keydata.pkey = pkey; +#else + key->keydata.rsa = rsa; +#endif for (i = 0; i < priv.nelements; i++) { BIGNUM *bn; - bn = BN_bin2bn(priv.elements[i].data, - priv.elements[i].length, NULL); - if (bn == NULL) - DST_RET(ISC_R_NOMEMORY); + switch (priv.elements[i].tag) { + case TAG_RSA_ENGINE: + continue; + case TAG_RSA_LABEL: + continue; + case TAG_RSA_PIN: + continue; + default: + bn = BN_bin2bn(priv.elements[i].data, + priv.elements[i].length, NULL); + if (bn == NULL) + DST_RET(ISC_R_NOMEMORY); + } switch (priv.elements[i].tag) { case TAG_RSA_MODULUS: @@ -582,16 +890,64 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { dst__privstruct_free(&priv, mctx); key->key_size = BN_num_bits(rsa->n); +#if USE_EVP + RSA_free(rsa); +#endif return (ISC_R_SUCCESS); err: +#if USE_EVP + if (pkey != NULL) + EVP_PKEY_free(pkey); +#endif + if (rsa != NULL) + RSA_free(rsa); opensslrsa_destroy(key); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); return (ret); } +static isc_result_t +opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + const char *pin) +{ + ENGINE *e = NULL; + isc_result_t ret; + EVP_PKEY *pkey = NULL; + + UNUSED(pin); + + e = dst__openssl_getengine(engine); + if (e == NULL) + DST_RET(DST_R_NOENGINE); + pkey = ENGINE_load_private_key(e, label, NULL, NULL); + if (pkey == NULL) + DST_RET(ISC_R_NOMEMORY); + key->engine = isc_mem_strdup(key->mctx, label); + if (key->engine == NULL) + DST_RET(ISC_R_NOMEMORY); + key->label = isc_mem_strdup(key->mctx, label); + if (key->label == NULL) + DST_RET(ISC_R_NOMEMORY); + key->key_size = EVP_PKEY_bits(pkey); +#if USE_EVP + key->keydata.pkey = pkey; +#else + key->keydata.rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + if (key->keydata.rsa == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +#endif + return (ISC_R_SUCCESS); + + err: + if (pkey != NULL) + EVP_PKEY_free(pkey); + return (ret); +} + static dst_func_t opensslrsa_functions = { opensslrsa_createctx, opensslrsa_destroyctx, @@ -609,6 +965,7 @@ static dst_func_t opensslrsa_functions = { opensslrsa_tofile, opensslrsa_parse, NULL, /*%< cleanup */ + opensslrsa_fromlabel, }; isc_result_t diff --git a/lib/dns/order.c b/lib/dns/order.c index 1d216b7..853b001 100644 --- a/lib/dns/order.c +++ b/lib/dns/order.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: order.c,v 1.5.18.3 2005/07/12 01:22:21 marka Exp $ */ +/* $Id: order.c,v 1.10 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/peer.c b/lib/dns/peer.c index 7d878b5..12474cb 100644 --- a/lib/dns/peer.c +++ b/lib/dns/peer.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: peer.c,v 1.19.18.8 2006/02/28 03:10:48 marka Exp $ */ +/* $Id: peer.c,v 1.31 2008/04/03 06:09:04 tbox Exp $ */ /*! \file */ @@ -42,6 +42,7 @@ #define SUPPORT_EDNS_BIT 5 #define SERVER_UDPSIZE_BIT 6 #define SERVER_MAXUDP_BIT 7 +#define REQUEST_NSID_BIT 8 static void peerlist_delete(dns_peerlist_t **list); @@ -146,7 +147,7 @@ dns_peerlist_addpeer(dns_peerlist_t *peers, dns_peer_t *peer) { ISC_LIST_INSERTBEFORE(peers->elements, p, peer, next); else ISC_LIST_APPEND(peers->elements, peer, next); - + } isc_result_t @@ -213,7 +214,7 @@ dns_peer_new(isc_mem_t *mem, isc_netaddr_t *addr, dns_peer_t **peerptr) { isc_result_t dns_peer_newprefix(isc_mem_t *mem, isc_netaddr_t *addr, unsigned int prefixlen, dns_peer_t **peerptr) -{ +{ dns_peer_t *peer; REQUIRE(peerptr != NULL); @@ -416,6 +417,32 @@ dns_peer_getsupportedns(dns_peer_t *peer, isc_boolean_t *retval) { } isc_result_t +dns_peer_setrequestnsid(dns_peer_t *peer, isc_boolean_t newval) { + isc_boolean_t existed; + + REQUIRE(DNS_PEER_VALID(peer)); + + existed = DNS_BIT_CHECK(REQUEST_NSID_BIT, &peer->bitflags); + + peer->request_nsid = newval; + DNS_BIT_SET(REQUEST_NSID_BIT, &peer->bitflags); + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_getrequestnsid(dns_peer_t *peer, isc_boolean_t *retval) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(retval != NULL); + + if (DNS_BIT_CHECK(REQUEST_NSID_BIT, &peer->bitflags)) { + *retval = peer->request_nsid; + return (ISC_R_SUCCESS); + } else + return (ISC_R_NOTFOUND); +} + +isc_result_t dns_peer_settransfers(dns_peer_t *peer, isc_uint32_t newval) { isc_boolean_t existed; @@ -544,7 +571,7 @@ dns_peer_settransfersource(dns_peer_t *peer, } if (transfer_source != NULL) { peer->transfer_source = isc_mem_get(peer->mem, - sizeof(*peer->transfer_source)); + sizeof(*peer->transfer_source)); if (peer->transfer_source == NULL) return (ISC_R_NOMEMORY); @@ -577,7 +604,7 @@ dns_peer_setnotifysource(dns_peer_t *peer, } if (notify_source != NULL) { peer->notify_source = isc_mem_get(peer->mem, - sizeof(*peer->notify_source)); + sizeof(*peer->notify_source)); if (peer->notify_source == NULL) return (ISC_R_NOMEMORY); @@ -608,7 +635,7 @@ dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source) { } if (query_source != NULL) { peer->query_source = isc_mem_get(peer->mem, - sizeof(*peer->query_source)); + sizeof(*peer->query_source)); if (peer->query_source == NULL) return (ISC_R_NOMEMORY); @@ -649,11 +676,11 @@ dns_peer_getudpsize(dns_peer_t *peer, isc_uint16_t *udpsize) { REQUIRE(udpsize != NULL); if (DNS_BIT_CHECK(SERVER_UDPSIZE_BIT, &peer->bitflags)) { - *udpsize = peer->udpsize; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } + *udpsize = peer->udpsize; + return (ISC_R_SUCCESS); + } else { + return (ISC_R_NOTFOUND); + } } isc_result_t @@ -677,9 +704,9 @@ dns_peer_getmaxudp(dns_peer_t *peer, isc_uint16_t *maxudp) { REQUIRE(maxudp != NULL); if (DNS_BIT_CHECK(SERVER_MAXUDP_BIT, &peer->bitflags)) { - *maxudp = peer->maxudp; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } + *maxudp = peer->maxudp; + return (ISC_R_SUCCESS); + } else { + return (ISC_R_NOTFOUND); + } } diff --git a/lib/dns/portlist.c b/lib/dns/portlist.c index 7e76171..5bc89f4 100644 --- a/lib/dns/portlist.c +++ b/lib/dns/portlist.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: portlist.c,v 1.6.18.5 2006/08/25 05:25:51 marka Exp $ */ +/* $Id: portlist.c,v 1.13 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index 4d3ca3a..ff8b3a3 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbt.c,v 1.128.18.10 2008/03/31 13:32:59 fdupont Exp $ */ +/* $Id: rbt.c,v 1.142.50.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -37,36 +37,37 @@ #define DNS_NAME_USEINLINE 1 #include <dns/fixedname.h> +#include <dns/log.h> #include <dns/rbt.h> #include <dns/result.h> -#define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+') -#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC) +#define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+') +#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC) /* * XXXDCL Since parent pointers were added in again, I could remove all of the * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode, * _lastnode. This would involve pretty major change to the API. */ -#define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-') -#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC) +#define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-') +#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC) -#define RBT_HASH_SIZE 64 +#define RBT_HASH_SIZE 64 #ifdef RBT_MEM_TEST #undef RBT_HASH_SIZE -#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */ +#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */ #endif struct dns_rbt { - unsigned int magic; - isc_mem_t * mctx; - dns_rbtnode_t * root; - void (*data_deleter)(void *, void *); - void * deleter_arg; - unsigned int nodecount; - unsigned int hashsize; - dns_rbtnode_t ** hashtable; + unsigned int magic; + isc_mem_t * mctx; + dns_rbtnode_t * root; + void (*data_deleter)(void *, void *); + void * deleter_arg; + unsigned int nodecount; + unsigned int hashsize; + dns_rbtnode_t ** hashtable; }; #define RED 0 @@ -75,51 +76,51 @@ struct dns_rbt { /*% * Elements of the rbtnode structure. */ -#define PARENT(node) ((node)->parent) -#define LEFT(node) ((node)->left) -#define RIGHT(node) ((node)->right) -#define DOWN(node) ((node)->down) -#define DATA(node) ((node)->data) -#define HASHNEXT(node) ((node)->hashnext) -#define HASHVAL(node) ((node)->hashval) -#define COLOR(node) ((node)->color) -#define NAMELEN(node) ((node)->namelen) -#define OFFSETLEN(node) ((node)->offsetlen) -#define ATTRS(node) ((node)->attributes) -#define PADBYTES(node) ((node)->padbytes) -#define IS_ROOT(node) ISC_TF((node)->is_root == 1) -#define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1) +#define PARENT(node) ((node)->parent) +#define LEFT(node) ((node)->left) +#define RIGHT(node) ((node)->right) +#define DOWN(node) ((node)->down) +#define DATA(node) ((node)->data) +#define HASHNEXT(node) ((node)->hashnext) +#define HASHVAL(node) ((node)->hashval) +#define COLOR(node) ((node)->color) +#define NAMELEN(node) ((node)->namelen) +#define OFFSETLEN(node) ((node)->offsetlen) +#define ATTRS(node) ((node)->attributes) +#define PADBYTES(node) ((node)->padbytes) +#define IS_ROOT(node) ISC_TF((node)->is_root == 1) +#define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1) /*% * Structure elements from the rbtdb.c, not * used as part of the rbt.c algorithms. */ -#define DIRTY(node) ((node)->dirty) -#define WILD(node) ((node)->wild) -#define LOCKNUM(node) ((node)->locknum) +#define DIRTY(node) ((node)->dirty) +#define WILD(node) ((node)->wild) +#define LOCKNUM(node) ((node)->locknum) /*% * The variable length stuff stored after the node. */ -#define NAME(node) ((unsigned char *)((node) + 1)) -#define OFFSETS(node) (NAME(node) + NAMELEN(node)) +#define NAME(node) ((unsigned char *)((node) + 1)) +#define OFFSETS(node) (NAME(node) + NAMELEN(node)) -#define NODE_SIZE(node) (sizeof(*node) + \ +#define NODE_SIZE(node) (sizeof(*node) + \ NAMELEN(node) + OFFSETLEN(node) + PADBYTES(node)) /*% * Color management. */ -#define IS_RED(node) ((node) != NULL && (node)->color == RED) -#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK) -#define MAKE_RED(node) ((node)->color = RED) -#define MAKE_BLACK(node) ((node)->color = BLACK) +#define IS_RED(node) ((node) != NULL && (node)->color == RED) +#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK) +#define MAKE_RED(node) ((node)->color = RED) +#define MAKE_BLACK(node) ((node)->color = BLACK) /*% * Chain management. * * The "ancestors" member of chains were removed, with their job now - * being wholy handled by parent pointers (which didn't exist, because + * being wholly handled by parent pointers (which didn't exist, because * of memory concerns, when chains were first implemented). */ #define ADD_LEVEL(chain, node) \ @@ -244,6 +245,7 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *), rbt->nodecount = 0; rbt->hashtable = NULL; rbt->hashsize = 0; + #ifdef DNS_RBT_USEHASH result = inithash(rbt); if (result != ISC_R_SUCCESS) { @@ -251,6 +253,7 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *), return (result); } #endif + rbt->magic = RBT_MAGIC; *rbtp = rbt; @@ -524,6 +527,7 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { * current node. */ new_current->is_root = current->is_root; + new_current->nsec3 = current->nsec3; PARENT(new_current) = PARENT(current); LEFT(new_current) = LEFT(current); RIGHT(new_current) = RIGHT(current); @@ -1142,7 +1146,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname, NULL); if (result2 == ISC_R_SUCCESS || result2 == DNS_R_NEWORIGIN) - ; /* Nothing. */ + ; /* Nothing. */ else if (result2 == ISC_R_NOMORE) /* * There is no predecessor. @@ -1274,8 +1278,7 @@ dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse) == ISC_R_SUCCESS); else { if (DATA(node) != NULL && rbt->data_deleter != NULL) - rbt->data_deleter(DATA(node), - rbt->deleter_arg); + rbt->data_deleter(DATA(node), rbt->deleter_arg); DATA(node) = NULL; /* @@ -1436,11 +1439,14 @@ create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) { HASHVAL(node) = 0; #endif + ISC_LINK_INIT(node, deadlink); + LOCKNUM(node) = 0; WILD(node) = 0; DIRTY(node) = 0; dns_rbtnode_refinit(node, 0); node->find_callback = 0; + node->nsec3 = 0; MAKE_BLACK(node); @@ -1451,9 +1457,9 @@ create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) { * and the name's offsets table. * * XXX RTH - * The offsets table could be made smaller by eliminating the - * first offset, which is always 0. This requires changes to - * lib/dns/name.c. + * The offsets table could be made smaller by eliminating the + * first offset, which is always 0. This requires changes to + * lib/dns/name.c. */ NAMELEN(node) = region.length; PADBYTES(node) = 0; @@ -1934,7 +1940,7 @@ dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) { } else { /* * Child is parent's right child. - * Everything is doen the same as above, + * Everything is done the same as above, * except mirrored. */ sibling = LEFT(parent); @@ -2027,6 +2033,7 @@ dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) { #if DNS_RBT_USEMAGIC node->magic = 0; #endif + isc_mem_put(rbt->mctx, node, NODE_SIZE(node)); rbt->nodecount--; return (result); @@ -2076,6 +2083,7 @@ dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, DOWN(parent) = RIGHT(node); } else parent = RIGHT(node); + isc_mem_put(rbt->mctx, node, NODE_SIZE(node)); rbt->nodecount--; node = parent; @@ -2354,6 +2362,113 @@ dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name, } isc_result_t +dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin) +{ + dns_rbtnode_t *current, *successor; + isc_result_t result = ISC_R_SUCCESS; + isc_boolean_t new_origin = ISC_FALSE; + + REQUIRE(VALID_CHAIN(chain) && chain->end != NULL); + + successor = NULL; + + current = chain->end; + + if (DOWN(current) != NULL) { + /* + * Don't declare an origin change when the new origin is "." + * at the second level tree, because "." is already declared + * as the origin for the top level tree. + */ + if (chain->level_count > 0 || + OFFSETLEN(current) > 1) + new_origin = ISC_TRUE; + + ADD_LEVEL(chain, current); + current = DOWN(current); + + while (LEFT(current) != NULL) + current = LEFT(current); + + successor = current; + } + + if (successor != NULL) { + chain->end = successor; + + /* + * It is not necessary to use dns_rbtnodechain_current like + * the other functions because this function will never + * find a node in the topmost level. This is because the + * root level will never be more than one name, and everything + * in the megatree is a successor to that node, down at + * the second level or below. + */ + + if (name != NULL) + NODENAME(chain->end, name); + + if (new_origin) { + if (origin != NULL) + result = chain_name(chain, origin, ISC_FALSE); + + if (result == ISC_R_SUCCESS) + result = DNS_R_NEWORIGIN; + + } else + result = ISC_R_SUCCESS; + + } else + result = ISC_R_NOMORE; + + return (result); +} + +isc_result_t +dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) { + dns_rbtnode_t *current, *previous, *successor; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_CHAIN(chain) && chain->end != NULL); + + successor = NULL; + + current = chain->end; + + if (RIGHT(current) == NULL) { + while (! IS_ROOT(current)) { + previous = current; + current = PARENT(current); + + if (LEFT(current) == previous) { + successor = current; + break; + } + } + } else { + current = RIGHT(current); + + while (LEFT(current) != NULL) + current = LEFT(current); + + successor = current; + } + + if (successor != NULL) { + chain->end = successor; + + if (name != NULL) + NODENAME(chain->end, name); + + result = ISC_R_SUCCESS; + } else + result = ISC_R_NOMORE; + + return (result); +} + +isc_result_t dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, dns_name_t *origin) { @@ -2398,7 +2513,7 @@ dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, * reached without having traversed any left links, ascend one * level and look for either a right link off the point of * ascent, or search for a left link upward again, repeating - * ascents until either case is true. + * ascends until either case is true. */ do { while (! IS_ROOT(current)) { diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 462a718..9741c15 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.196.18.53 2008/01/31 23:46:05 tbox Exp $ */ +/* $Id: rbtdb.c,v 1.270.12.6 2009/05/06 23:34:30 jinmei Exp $ */ /*! \file */ @@ -25,13 +25,18 @@ #include <config.h> +/* #define inline */ + #include <isc/event.h> +#include <isc/heap.h> #include <isc/mem.h> -#include <isc/print.h> #include <isc/mutex.h> +#include <isc/platform.h> +#include <isc/print.h> #include <isc/random.h> #include <isc/refcount.h> #include <isc/rwlock.h> +#include <isc/serial.h> #include <isc/string.h> #include <isc/task.h> #include <isc/time.h> @@ -45,12 +50,16 @@ #include <dns/lib.h> #include <dns/log.h> #include <dns/masterdump.h> +#include <dns/nsec.h> +#include <dns/nsec3.h> #include <dns/rbt.h> #include <dns/rdata.h> #include <dns/rdataset.h> #include <dns/rdatasetiter.h> #include <dns/rdataslab.h> +#include <dns/rdatastruct.h> #include <dns/result.h> +#include <dns/stats.h> #include <dns/view.h> #include <dns/zone.h> #include <dns/zonekey.h> @@ -62,20 +71,20 @@ #endif #ifdef DNS_RBTDB_VERSION64 -#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '8') +#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '8') #else -#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '4') +#define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '4') #endif /*% * Note that "impmagic" is not the first four bytes of the struct, so * ISC_MAGIC_VALID cannot be used. */ -#define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \ +#define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \ (rbtdb)->common.impmagic == RBTDB_MAGIC) #ifdef DNS_RBTDB_VERSION64 -typedef isc_uint64_t rbtdb_serial_t; +typedef isc_uint64_t rbtdb_serial_t; /*% * Make casting easier in symbolic debuggers by using different names * for the 64 bit version. @@ -84,17 +93,19 @@ typedef isc_uint64_t rbtdb_serial_t; #define rdatasetheader_t rdatasetheader64_t #define rbtdb_version_t rbtdb_version64_t #else -typedef isc_uint32_t rbtdb_serial_t; +typedef isc_uint32_t rbtdb_serial_t; #endif -typedef isc_uint32_t rbtdb_rdatatype_t; +typedef isc_uint32_t rbtdb_rdatatype_t; -#define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF)) -#define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16)) -#define RBTDB_RDATATYPE_VALUE(b, e) (((e) << 16) | (b)) +#define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF)) +#define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16)) +#define RBTDB_RDATATYPE_VALUE(b, e) ((rbtdb_rdatatype_t)((e) << 16) | (b)) #define RBTDB_RDATATYPE_SIGNSEC \ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec) +#define RBTDB_RDATATYPE_SIGNSEC3 \ + RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec3) #define RBTDB_RDATATYPE_SIGNS \ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns) #define RBTDB_RDATATYPE_SIGCNAME \ @@ -119,15 +130,15 @@ typedef isc_uint32_t rbtdb_rdatatype_t; #endif #if DNS_RBTDB_USERWLOCK -#define RBTDB_INITLOCK(l) isc_rwlock_init((l), 0, 0) -#define RBTDB_DESTROYLOCK(l) isc_rwlock_destroy(l) -#define RBTDB_LOCK(l, t) RWLOCK((l), (t)) -#define RBTDB_UNLOCK(l, t) RWUNLOCK((l), (t)) +#define RBTDB_INITLOCK(l) isc_rwlock_init((l), 0, 0) +#define RBTDB_DESTROYLOCK(l) isc_rwlock_destroy(l) +#define RBTDB_LOCK(l, t) RWLOCK((l), (t)) +#define RBTDB_UNLOCK(l, t) RWUNLOCK((l), (t)) #else -#define RBTDB_INITLOCK(l) isc_mutex_init(l) -#define RBTDB_DESTROYLOCK(l) DESTROYLOCK(l) -#define RBTDB_LOCK(l, t) LOCK(l) -#define RBTDB_UNLOCK(l, t) UNLOCK(l) +#define RBTDB_INITLOCK(l) isc_mutex_init(l) +#define RBTDB_DESTROYLOCK(l) DESTROYLOCK(l) +#define RBTDB_LOCK(l, t) LOCK(l) +#define RBTDB_UNLOCK(l, t) UNLOCK(l) #endif /* @@ -152,47 +163,53 @@ typedef isc_uint32_t rbtdb_rdatatype_t; #if defined(ISC_RWLOCK_USEATOMIC) && defined(DNS_RBT_USEISCREFCOUNT) typedef isc_rwlock_t nodelock_t; -#define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0) -#define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l) -#define NODE_LOCK(l, t) RWLOCK((l), (t)) -#define NODE_UNLOCK(l, t) RWUNLOCK((l), (t)) -#define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l) - -#define NODE_STRONGLOCK(l) ((void)0) -#define NODE_STRONGUNLOCK(l) ((void)0) -#define NODE_WEAKLOCK(l, t) NODE_LOCK(l, t) -#define NODE_WEAKUNLOCK(l, t) NODE_UNLOCK(l, t) -#define NODE_WEAKDOWNGRADE(l) isc_rwlock_downgrade(l) +#define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0) +#define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l) +#define NODE_LOCK(l, t) RWLOCK((l), (t)) +#define NODE_UNLOCK(l, t) RWUNLOCK((l), (t)) +#define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l) + +#define NODE_STRONGLOCK(l) ((void)0) +#define NODE_STRONGUNLOCK(l) ((void)0) +#define NODE_WEAKLOCK(l, t) NODE_LOCK(l, t) +#define NODE_WEAKUNLOCK(l, t) NODE_UNLOCK(l, t) +#define NODE_WEAKDOWNGRADE(l) isc_rwlock_downgrade(l) #else typedef isc_mutex_t nodelock_t; -#define NODE_INITLOCK(l) isc_mutex_init(l) -#define NODE_DESTROYLOCK(l) DESTROYLOCK(l) -#define NODE_LOCK(l, t) LOCK(l) -#define NODE_UNLOCK(l, t) UNLOCK(l) -#define NODE_TRYUPGRADE(l) ISC_R_SUCCESS - -#define NODE_STRONGLOCK(l) LOCK(l) -#define NODE_STRONGUNLOCK(l) UNLOCK(l) -#define NODE_WEAKLOCK(l, t) ((void)0) -#define NODE_WEAKUNLOCK(l, t) ((void)0) -#define NODE_WEAKDOWNGRADE(l) ((void)0) +#define NODE_INITLOCK(l) isc_mutex_init(l) +#define NODE_DESTROYLOCK(l) DESTROYLOCK(l) +#define NODE_LOCK(l, t) LOCK(l) +#define NODE_UNLOCK(l, t) UNLOCK(l) +#define NODE_TRYUPGRADE(l) ISC_R_SUCCESS + +#define NODE_STRONGLOCK(l) LOCK(l) +#define NODE_STRONGUNLOCK(l) UNLOCK(l) +#define NODE_WEAKLOCK(l, t) ((void)0) +#define NODE_WEAKUNLOCK(l, t) ((void)0) +#define NODE_WEAKDOWNGRADE(l) ((void)0) #endif -#ifndef DNS_RDATASET_FIXED -#define DNS_RDATASET_FIXED 1 +/*% + * Whether to rate-limit updating the LRU to avoid possible thread contention. + * Our performance measurement has shown the cost is marginal, so it's defined + * to be 0 by default either with or without threads. + */ +#ifndef DNS_RBTDB_LIMITLRUUPDATE +#define DNS_RBTDB_LIMITLRUUPDATE 0 #endif /* - * Allow clients with a virtual time of upto 5 minutes in the past to see + * Allow clients with a virtual time of up to 5 minutes in the past to see * records that would have otherwise have expired. */ #define RBTDB_VIRTUAL 300 struct noqname { - dns_name_t name; - void * nsec; - void * nsecsig; + dns_name_t name; + void * neg; + void * negsig; + dns_rdatatype_t type; }; typedef struct acachectl acachectl_t; @@ -201,18 +218,19 @@ typedef struct rdatasetheader { /*% * Locked by the owning node's lock. */ - rbtdb_serial_t serial; - dns_ttl_t ttl; - rbtdb_rdatatype_t type; - isc_uint16_t attributes; - dns_trust_t trust; - struct noqname *noqname; + rbtdb_serial_t serial; + dns_ttl_t rdh_ttl; + rbtdb_rdatatype_t type; + isc_uint16_t attributes; + dns_trust_t trust; + struct noqname *noqname; + struct noqname *closest; /*%< * We don't use the LIST macros, because the LIST structure has * both head and tail pointers, and is doubly linked. */ - struct rdatasetheader *next; + struct rdatasetheader *next; /*%< * If this is the top header for an rdataset, 'next' points * to the top header for the next rdataset (i.e., the next type). @@ -220,13 +238,13 @@ typedef struct rdatasetheader { * at this header. */ - struct rdatasetheader *down; + struct rdatasetheader *down; /*%< * Points to the header for the next older version of * this rdataset. */ - isc_uint32_t count; + isc_uint32_t count; /*%< * Monotonously increased every time this rdataset is bound so that * it is used as the base of the starting point in DNS responses @@ -235,27 +253,56 @@ typedef struct rdatasetheader { * performance reasons. */ - acachectl_t *additional_auth; - acachectl_t *additional_glue; + acachectl_t *additional_auth; + acachectl_t *additional_glue; + + dns_rbtnode_t *node; + isc_stdtime_t last_used; + ISC_LINK(struct rdatasetheader) lru_link; + /*%< + * Used for LRU-based cache management. We should probably make + * these cache-DB specific. We might also make it a pointer and + * ensure only the top header has a valid link to save memory. + * The linked-list is locked by the rbtdb->lrulock. + */ + + /* + * It's possible this should not be here anymore, but instead + * referenced from the bucket's heap directly. + */ +#if 0 + isc_heap_t *heap; +#endif + unsigned int heap_index; + /*%< + * Used for TTL-based cache cleaning. + */ + isc_stdtime_t resign; } rdatasetheader_t; -#define RDATASET_ATTR_NONEXISTENT 0x0001 -#define RDATASET_ATTR_STALE 0x0002 -#define RDATASET_ATTR_IGNORE 0x0004 -#define RDATASET_ATTR_RETAIN 0x0008 -#define RDATASET_ATTR_NXDOMAIN 0x0010 +typedef ISC_LIST(rdatasetheader_t) rdatasetheaderlist_t; +typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t; + +#define RDATASET_ATTR_NONEXISTENT 0x0001 +#define RDATASET_ATTR_STALE 0x0002 +#define RDATASET_ATTR_IGNORE 0x0004 +#define RDATASET_ATTR_RETAIN 0x0008 +#define RDATASET_ATTR_NXDOMAIN 0x0010 +#define RDATASET_ATTR_RESIGN 0x0020 +#define RDATASET_ATTR_STATCOUNT 0x0040 +#define RDATASET_ATTR_OPTOUT 0x0080 typedef struct acache_cbarg { - dns_rdatasetadditional_t type; - unsigned int count; - dns_db_t *db; - dns_dbnode_t *node; - rdatasetheader_t *header; + dns_rdatasetadditional_t type; + unsigned int count; + dns_db_t *db; + dns_dbnode_t *node; + rdatasetheader_t *header; } acache_cbarg_t; struct acachectl { - dns_acacheentry_t *entry; - acache_cbarg_t *cbarg; + dns_acacheentry_t *entry; + acache_cbarg_t *cbarg; }; /* @@ -266,7 +313,7 @@ struct acachectl { * expired. */ -#undef IGNORE /* WIN32 winbase.h defines this. */ +#undef IGNORE /* WIN32 winbase.h defines this. */ #define EXISTS(header) \ (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0) @@ -278,106 +325,164 @@ struct acachectl { (((header)->attributes & RDATASET_ATTR_RETAIN) != 0) #define NXDOMAIN(header) \ (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0) +#define RESIGN(header) \ + (((header)->attributes & RDATASET_ATTR_RESIGN) != 0) +#define OPTOUT(header) \ + (((header)->attributes & RDATASET_ATTR_OPTOUT) != 0) + +#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ -#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ -#define DEFAULT_CACHE_NODE_LOCK_COUNT 1009 /*%< Should be prime. */ +/*% + * Number of buckets for cache DB entries (locks, LRU lists, TTL heaps). + * There is a tradeoff issue about configuring this value: if this is too + * small, it may cause heavier contention between threads; if this is too large, + * LRU purge algorithm won't work well (entries tend to be purged prematurely). + * The default value should work well for most environments, but this can + * also be configurable at compilation time via the + * DNS_RBTDB_CACHE_NODE_LOCK_COUNT variable. This value must be larger than + * 1 due to the assumption of overmem_purge(). + */ +#ifdef DNS_RBTDB_CACHE_NODE_LOCK_COUNT +#if DNS_RBTDB_CACHE_NODE_LOCK_COUNT <= 1 +#error "DNS_RBTDB_CACHE_NODE_LOCK_COUNT must be larger than 1" +#else +#define DEFAULT_CACHE_NODE_LOCK_COUNT DNS_RBTDB_CACHE_NODE_LOCK_COUNT +#endif +#else +#define DEFAULT_CACHE_NODE_LOCK_COUNT 16 +#endif /* DNS_RBTDB_CACHE_NODE_LOCK_COUNT */ typedef struct { - nodelock_t lock; + nodelock_t lock; /* Protected in the refcount routines. */ - isc_refcount_t references; + isc_refcount_t references; /* Locked by lock. */ - isc_boolean_t exiting; + isc_boolean_t exiting; } rbtdb_nodelock_t; typedef struct rbtdb_changed { - dns_rbtnode_t * node; - isc_boolean_t dirty; - ISC_LINK(struct rbtdb_changed) link; + dns_rbtnode_t * node; + isc_boolean_t dirty; + ISC_LINK(struct rbtdb_changed) link; } rbtdb_changed_t; -typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t; +typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t; + +typedef enum { + dns_db_insecure, + dns_db_partial, + dns_db_secure +} dns_db_secure_t; typedef struct rbtdb_version { /* Not locked */ - rbtdb_serial_t serial; + rbtdb_serial_t serial; /* * Protected in the refcount routines. * XXXJT: should we change the lock policy based on the refcount * performance? */ - isc_refcount_t references; + isc_refcount_t references; /* Locked by database lock. */ - isc_boolean_t writer; - isc_boolean_t commit_ok; - rbtdb_changedlist_t changed_list; - ISC_LINK(struct rbtdb_version) link; + isc_boolean_t writer; + isc_boolean_t commit_ok; + rbtdb_changedlist_t changed_list; + rdatasetheaderlist_t resigned_list; + ISC_LINK(struct rbtdb_version) link; + dns_db_secure_t secure; + isc_boolean_t havensec3; + /* NSEC3 parameters */ + dns_hash_t hash; + isc_uint8_t flags; + isc_uint16_t iterations; + isc_uint8_t salt_length; + unsigned char salt[NSEC3_MAX_HASH_LENGTH]; } rbtdb_version_t; -typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t; +typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t; typedef struct { /* Unlocked. */ - dns_db_t common; + dns_db_t common; #if DNS_RBTDB_USERWLOCK - isc_rwlock_t lock; + isc_rwlock_t lock; #else - isc_mutex_t lock; + isc_mutex_t lock; #endif - isc_rwlock_t tree_lock; - unsigned int node_lock_count; - rbtdb_nodelock_t * node_locks; - dns_rbtnode_t * origin_node; + isc_rwlock_t tree_lock; + unsigned int node_lock_count; + rbtdb_nodelock_t * node_locks; + dns_rbtnode_t * origin_node; + dns_stats_t * rrsetstats; /* cache DB only */ /* Locked by lock. */ - unsigned int active; - isc_refcount_t references; - unsigned int attributes; - rbtdb_serial_t current_serial; - rbtdb_serial_t least_serial; - rbtdb_serial_t next_serial; - rbtdb_version_t * current_version; - rbtdb_version_t * future_version; - rbtdb_versionlist_t open_versions; - isc_boolean_t overmem; - isc_task_t * task; - dns_dbnode_t *soanode; - dns_dbnode_t *nsnode; + unsigned int active; + isc_refcount_t references; + unsigned int attributes; + rbtdb_serial_t current_serial; + rbtdb_serial_t least_serial; + rbtdb_serial_t next_serial; + rbtdb_version_t * current_version; + rbtdb_version_t * future_version; + rbtdb_versionlist_t open_versions; + isc_boolean_t overmem; + isc_task_t * task; + dns_dbnode_t *soanode; + dns_dbnode_t *nsnode; + + /* + * This is a linked list used to implement the LRU cache. There will + * be node_lock_count linked lists here. Nodes in bucket 1 will be + * placed on the linked list rdatasets[1]. + */ + rdatasetheaderlist_t *rdatasets; + + /*% + * Temporary storage for stale cache nodes and dynamically deleted + * nodes that await being cleaned up. + */ + rbtnodelist_t *deadnodes; + + /* + * Heaps. Each of these is used for TTL based expiry. + */ + isc_heap_t **heaps; + /* Locked by tree_lock. */ - dns_rbt_t * tree; - isc_boolean_t secure; + dns_rbt_t * tree; + dns_rbt_t * nsec3; /* Unlocked */ - unsigned int quantum; + unsigned int quantum; } dns_rbtdb_t; -#define RBTDB_ATTR_LOADED 0x01 -#define RBTDB_ATTR_LOADING 0x02 +#define RBTDB_ATTR_LOADED 0x01 +#define RBTDB_ATTR_LOADING 0x02 /*% * Search Context */ typedef struct { - dns_rbtdb_t * rbtdb; - rbtdb_version_t * rbtversion; - rbtdb_serial_t serial; - unsigned int options; - dns_rbtnodechain_t chain; - isc_boolean_t copy_name; - isc_boolean_t need_cleanup; - isc_boolean_t wild; - dns_rbtnode_t * zonecut; - rdatasetheader_t * zonecut_rdataset; - rdatasetheader_t * zonecut_sigrdataset; - dns_fixedname_t zonecut_name; - isc_stdtime_t now; + dns_rbtdb_t * rbtdb; + rbtdb_version_t * rbtversion; + rbtdb_serial_t serial; + unsigned int options; + dns_rbtnodechain_t chain; + isc_boolean_t copy_name; + isc_boolean_t need_cleanup; + isc_boolean_t wild; + dns_rbtnode_t * zonecut; + rdatasetheader_t * zonecut_rdataset; + rdatasetheader_t * zonecut_sigrdataset; + dns_fixedname_t zonecut_name; + isc_stdtime_t now; } rbtdb_search_t; /*% * Load Context */ typedef struct { - dns_rbtdb_t * rbtdb; - isc_stdtime_t now; + dns_rbtdb_t * rbtdb; + isc_stdtime_t now; } rbtdb_load_t; static void rdataset_disassociate(dns_rdataset_t *rdataset); @@ -388,8 +493,12 @@ static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target); static unsigned int rdataset_count(dns_rdataset_t *rdataset); static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, - dns_rdataset_t *nsecsig); + dns_rdataset_t *neg, + dns_rdataset_t *negsig); +static isc_result_t rdataset_getclosest(dns_rdataset_t *rdataset, + dns_name_t *name, + dns_rdataset_t *neg, + dns_rdataset_t *negsig); static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype, @@ -414,6 +523,17 @@ static isc_result_t rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype); +static inline isc_boolean_t need_headerupdate(rdatasetheader_t *header, + isc_stdtime_t now); +static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_stdtime_t now); +static void expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_boolean_t tree_locked); +static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, + isc_stdtime_t now, isc_boolean_t tree_locked); +static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx, + rdatasetheader_t *newheader); +static void prune_tree(isc_task_t *task, isc_event_t *event); static dns_rdatasetmethods_t rdataset_methods = { rdataset_disassociate, @@ -424,6 +544,8 @@ static dns_rdatasetmethods_t rdataset_methods = { rdataset_count, NULL, rdataset_getnoqname, + NULL, + rdataset_getclosest, rdataset_getadditional, rdataset_setadditional, rdataset_putadditional @@ -443,22 +565,22 @@ static dns_rdatasetitermethods_t rdatasetiter_methods = { }; typedef struct rbtdb_rdatasetiter { - dns_rdatasetiter_t common; - rdatasetheader_t * current; + dns_rdatasetiter_t common; + rdatasetheader_t * current; } rbtdb_rdatasetiter_t; -static void dbiterator_destroy(dns_dbiterator_t **iteratorp); -static isc_result_t dbiterator_first(dns_dbiterator_t *iterator); -static isc_result_t dbiterator_last(dns_dbiterator_t *iterator); -static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator, +static void dbiterator_destroy(dns_dbiterator_t **iteratorp); +static isc_result_t dbiterator_first(dns_dbiterator_t *iterator); +static isc_result_t dbiterator_last(dns_dbiterator_t *iterator); +static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name); -static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator); -static isc_result_t dbiterator_next(dns_dbiterator_t *iterator); -static isc_result_t dbiterator_current(dns_dbiterator_t *iterator, +static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator); +static isc_result_t dbiterator_next(dns_dbiterator_t *iterator); +static isc_result_t dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, dns_name_t *name); -static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator); -static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator, +static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator); +static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name); static dns_dbiteratormethods_t dbiterator_methods = { @@ -479,17 +601,21 @@ static dns_dbiteratormethods_t dbiterator_methods = { * If 'paused' is ISC_TRUE, then the tree lock is not being held. */ typedef struct rbtdb_dbiterator { - dns_dbiterator_t common; - isc_boolean_t paused; - isc_boolean_t new_origin; - isc_rwlocktype_t tree_locked; - isc_result_t result; - dns_fixedname_t name; - dns_fixedname_t origin; - dns_rbtnodechain_t chain; - dns_rbtnode_t *node; - dns_rbtnode_t *deletions[DELETION_BATCH_MAX]; - int delete; + dns_dbiterator_t common; + isc_boolean_t paused; + isc_boolean_t new_origin; + isc_rwlocktype_t tree_locked; + isc_result_t result; + dns_fixedname_t name; + dns_fixedname_t origin; + dns_rbtnodechain_t chain; + dns_rbtnodechain_t nsec3chain; + dns_rbtnodechain_t *current; + dns_rbtnode_t *node; + dns_rbtnode_t *deletions[DELETION_BATCH_MAX]; + int delete; + isc_boolean_t nsec3only; + isc_boolean_t nonsec3; } rbtdb_dbiterator_t; @@ -498,17 +624,20 @@ typedef struct rbtdb_dbiterator { static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event); +static void overmem(dns_db_t *db, isc_boolean_t overmem); +static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, + isc_boolean_t *nsec3createflag); /*% * 'init_count' is used to initialize 'newheader->count' which inturn * is used to determine where in the cycle rrset-order cyclic starts. - * We don't lock this as we don't care about simultanious updates. + * We don't lock this as we don't care about simultaneous updates. * * Note: - * Both init_count and header->count can be ISC_UINT32_MAX. + * Both init_count and header->count can be ISC_UINT32_MAX. * The count on the returned rdataset however can't be as - * that indicates that the database does not implement cyclic - * processing. + * that indicates that the database does not implement cyclic + * processing. */ static unsigned int init_count; @@ -518,12 +647,12 @@ static unsigned int init_count; * If a routine is going to lock more than one lock in this module, then * the locking must be done in the following order: * - * Tree Lock + * Tree Lock * - * Node Lock (Only one from the set may be locked at one time by - * any caller) + * Node Lock (Only one from the set may be locked at one time by + * any caller) * - * Database Lock + * Database Lock * * Failure to follow this hierarchy can result in deadlock. */ @@ -531,11 +660,7 @@ static unsigned int init_count; /* * Deleting Nodes * - * Currently there is no deletion of nodes from the database, except when - * the database is being destroyed. - * - * If node deletion is added in the future, then for zone databases the node - * for the origin of the zone MUST NOT be deleted. + * For zone databases the node for the origin of the zone MUST NOT be deleted. */ @@ -563,6 +688,96 @@ free_rbtdb_callback(isc_task_t *task, isc_event_t *event) { free_rbtdb(rbtdb, ISC_TRUE, event); } +static void +update_rrsetstats(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_boolean_t increment) +{ + dns_rdatastatstype_t statattributes = 0; + dns_rdatastatstype_t base = 0; + dns_rdatastatstype_t type; + + /* At the moment we count statistics only for cache DB */ + INSIST(IS_CACHE(rbtdb)); + + if (NXDOMAIN(header)) + statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN; + else if (RBTDB_RDATATYPE_BASE(header->type) == 0) { + statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET; + base = RBTDB_RDATATYPE_EXT(header->type); + } else + base = RBTDB_RDATATYPE_BASE(header->type); + + type = DNS_RDATASTATSTYPE_VALUE(base, statattributes); + if (increment) + dns_rdatasetstats_increment(rbtdb->rrsetstats, type); + else + dns_rdatasetstats_decrement(rbtdb->rrsetstats, type); +} + +static void +set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) { + int idx; + isc_heap_t *heap; + dns_ttl_t oldttl; + + oldttl = header->rdh_ttl; + header->rdh_ttl = newttl; + + if (!IS_CACHE(rbtdb)) + return; + + /* + * It's possible the rbtdb is not a cache. If this is the case, + * we will not have a heap, and we move on. If we do, though, + * we might need to adjust things. + */ + if (header->heap_index == 0 || newttl == oldttl) + return; + idx = header->node->locknum; + if (rbtdb->heaps == NULL || rbtdb->heaps[idx] == NULL) + return; + heap = rbtdb->heaps[idx]; + + if (newttl < oldttl) + isc_heap_increased(heap, header->heap_index); + else + isc_heap_decreased(heap, header->heap_index); +} + +/*% + * These functions allow the heap code to rank the priority of each + * element. It returns ISC_TRUE if v1 happens "sooner" than v2. + */ +static isc_boolean_t +ttl_sooner(void *v1, void *v2) { + rdatasetheader_t *h1 = v1; + rdatasetheader_t *h2 = v2; + + if (h1->rdh_ttl < h2->rdh_ttl) + return (ISC_TRUE); + return (ISC_FALSE); +} + +static isc_boolean_t +resign_sooner(void *v1, void *v2) { + rdatasetheader_t *h1 = v1; + rdatasetheader_t *h2 = v2; + + if (h1->resign < h2->resign) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/*% + * This function sets the heap index into the header. + */ +static void +set_index(void *what, unsigned int index) { + rdatasetheader_t *h = what; + + h->heap_index = index; +} + /*% * Work out how many nodes can be deleted in the time between two * requests to the nameserver. Smooth the resulting number and use it @@ -571,7 +786,7 @@ free_rbtdb_callback(isc_task_t *task, isc_event_t *event) { */ static unsigned int adjust_quantum(unsigned int old, isc_time_t *start) { - unsigned int pps = dns_pps; /* packets per second */ + unsigned int pps = dns_pps; /* packets per second */ unsigned int interval; isc_uint64_t usecs; isc_time_t end; @@ -581,7 +796,7 @@ adjust_quantum(unsigned int old, isc_time_t *start) { pps = 100; isc_time_now(&end); - interval = 1000000 / pps; /* interval in usec */ + interval = 1000000 / pps; /* interval in usec */ if (interval == 0) interval = 1; usecs = isc_time_microdiff(&end, start); @@ -619,6 +834,9 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { char buf[DNS_NAME_FORMATSIZE]; isc_time_t start; + if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) + overmem((dns_db_t *)rbtdb, (isc_boolean_t)-1); + REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions)); REQUIRE(rbtdb->future_version == NULL); @@ -633,6 +851,21 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { isc_mem_put(rbtdb->common.mctx, rbtdb->current_version, sizeof(rbtdb_version_t)); } + + /* + * We assume the number of remaining dead nodes is reasonably small; + * the overhead of unlinking all nodes here should be negligible. + */ + for (i = 0; i < rbtdb->node_lock_count; i++) { + dns_rbtnode_t *node; + + node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); + while (node != NULL) { + ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink); + node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); + } + } + if (event == NULL) rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0; again: @@ -658,6 +891,30 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { } INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL); } + + if (rbtdb->nsec3 != NULL) { + isc_time_now(&start); + result = dns_rbt_destroy2(&rbtdb->nsec3, rbtdb->quantum); + if (result == ISC_R_QUOTA) { + INSIST(rbtdb->task != NULL); + if (rbtdb->quantum != 0) + rbtdb->quantum = adjust_quantum(rbtdb->quantum, + &start); + if (event == NULL) + event = isc_event_allocate(rbtdb->common.mctx, + NULL, + DNS_EVENT_FREESTORAGE, + free_rbtdb_callback, + rbtdb, + sizeof(isc_event_t)); + if (event == NULL) + goto again; + isc_task_send(rbtdb->task, &event); + return; + } + INSIST(result == ISC_R_SUCCESS && rbtdb->nsec3 == NULL); + } + if (event != NULL) isc_event_free(&event); if (log) { @@ -676,12 +933,47 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { isc_refcount_destroy(&rbtdb->node_locks[i].references); NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock); } + + /* + * Clean up LRU / re-signing order lists. + */ + if (rbtdb->rdatasets != NULL) { + for (i = 0; i < rbtdb->node_lock_count; i++) + INSIST(ISC_LIST_EMPTY(rbtdb->rdatasets[i])); + isc_mem_put(rbtdb->common.mctx, rbtdb->rdatasets, + rbtdb->node_lock_count * + sizeof(rdatasetheaderlist_t)); + } + /* + * Clean up dead node buckets. + */ + if (rbtdb->deadnodes != NULL) { + for (i = 0; i < rbtdb->node_lock_count; i++) + INSIST(ISC_LIST_EMPTY(rbtdb->deadnodes[i])); + isc_mem_put(rbtdb->common.mctx, rbtdb->deadnodes, + rbtdb->node_lock_count * sizeof(rbtnodelist_t)); + } + /* + * Clean up heap objects. + */ + if (rbtdb->heaps != NULL) { + for (i = 0; i < rbtdb->node_lock_count; i++) + isc_heap_destroy(&rbtdb->heaps[i]); + isc_mem_put(rbtdb->common.mctx, rbtdb->heaps, + rbtdb->node_lock_count * + sizeof(isc_heap_t *)); + } + + if (rbtdb->rrsetstats != NULL) + dns_stats_detach(&rbtdb->rrsetstats); + isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks, rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t)); isc_rwlock_destroy(&rbtdb->tree_lock); isc_refcount_destroy(&rbtdb->references); if (rbtdb->task != NULL) isc_task_detach(&rbtdb->task); + RBTDB_DESTROYLOCK(&rbtdb->lock); rbtdb->common.magic = 0; rbtdb->common.impmagic = 0; @@ -788,6 +1080,7 @@ allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial, version->writer = writer; version->commit_ok = ISC_FALSE; ISC_LIST_INIT(version->changed_list); + ISC_LIST_INIT(version->resigned_list); ISC_LINK_INIT(version, link); return (version); @@ -803,11 +1096,29 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) { REQUIRE(rbtdb->future_version == NULL); RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write); - RUNTIME_CHECK(rbtdb->next_serial != 0); /* XXX Error? */ + RUNTIME_CHECK(rbtdb->next_serial != 0); /* XXX Error? */ version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1, ISC_TRUE); if (version != NULL) { version->commit_ok = ISC_TRUE; + version->secure = rbtdb->current_version->secure; + version->havensec3 = rbtdb->current_version->havensec3; + if (version->havensec3) { + version->flags = rbtdb->current_version->flags; + version->iterations = + rbtdb->current_version->iterations; + version->hash = rbtdb->current_version->hash; + version->salt_length = + rbtdb->current_version->salt_length; + memcpy(version->salt, rbtdb->current_version->salt, + version->salt_length); + } else { + version->flags = 0; + version->iterations = 0; + version->hash = 0; + version->salt_length = 0; + memset(version->salt, 0, sizeof(version->salt)); + } rbtdb->next_serial++; rbtdb->future_version = version; } @@ -875,7 +1186,7 @@ free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header, { unsigned int count; unsigned int i; - unsigned char *raw; /* RDATASLAB */ + unsigned char *raw; /* RDATASLAB */ /* * The caller must be holding the corresponding node lock. @@ -903,22 +1214,69 @@ free_noqname(isc_mem_t *mctx, struct noqname **noqname) { if (dns_name_dynamic(&(*noqname)->name)) dns_name_free(&(*noqname)->name, mctx); - if ((*noqname)->nsec != NULL) - isc_mem_put(mctx, (*noqname)->nsec, - dns_rdataslab_size((*noqname)->nsec, 0)); - if ((*noqname)->nsecsig != NULL) - isc_mem_put(mctx, (*noqname)->nsecsig, - dns_rdataslab_size((*noqname)->nsecsig, 0)); + if ((*noqname)->neg != NULL) + isc_mem_put(mctx, (*noqname)->neg, + dns_rdataslab_size((*noqname)->neg, 0)); + if ((*noqname)->negsig != NULL) + isc_mem_put(mctx, (*noqname)->negsig, + dns_rdataslab_size((*noqname)->negsig, 0)); isc_mem_put(mctx, *noqname, sizeof(**noqname)); *noqname = NULL; } static inline void -free_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) { +init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h) +{ + ISC_LINK_INIT(h, lru_link); + h->heap_index = 0; + +#if TRACE_HEADER + if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) + fprintf(stderr, "initialized header: %p\n", h); +#else + UNUSED(rbtdb); +#endif +} + +static inline rdatasetheader_t * +new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx) +{ + rdatasetheader_t *h; + + h = isc_mem_get(mctx, sizeof(*h)); + if (h == NULL) + return (NULL); + +#if TRACE_HEADER + if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) + fprintf(stderr, "allocated header: %p\n", h); +#endif + init_rdataset(rbtdb, h); + return (h); +} + +static inline void +free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset) +{ unsigned int size; + int idx; + + if (EXISTS(rdataset) && + (rdataset->attributes & RDATASET_ATTR_STATCOUNT) != 0) { + update_rrsetstats(rbtdb, rdataset, ISC_FALSE); + } + + idx = rdataset->node->locknum; + if (ISC_LINK_LINKED(rdataset, lru_link)) + ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link); + if (rdataset->heap_index != 0) + isc_heap_delete(rbtdb->heaps[idx], rdataset->heap_index); + rdataset->heap_index = 0; if (rdataset->noqname != NULL) free_noqname(mctx, &rdataset->noqname); + if (rdataset->closest != NULL) + free_noqname(mctx, &rdataset->closest); free_acachearray(mctx, rdataset, rdataset->additional_auth); free_acachearray(mctx, rdataset, rdataset->additional_glue); @@ -964,12 +1322,13 @@ rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) { } static inline void -clean_stale_headers(isc_mem_t *mctx, rdatasetheader_t *top) { +clean_stale_headers(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *top) +{ rdatasetheader_t *d, *down_next; for (d = top->down; d != NULL; d = down_next) { down_next = d->down; - free_rdataset(mctx, d); + free_rdataset(rbtdb, mctx, d); } top->down = NULL; } @@ -986,7 +1345,7 @@ clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { top_prev = NULL; for (current = node->data; current != NULL; current = top_next) { top_next = current->next; - clean_stale_headers(mctx, current); + clean_stale_headers(rbtdb, mctx, current); /* * If current is nonexistent or stale, we can clean it up. */ @@ -996,7 +1355,7 @@ clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { top_prev->next = current->next; else node->data = current->next; - free_rdataset(mctx, current); + free_rdataset(rbtdb, mctx, current); } else top_prev = current; } @@ -1037,7 +1396,7 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, if (down_next != NULL) down_next->next = dparent; dparent->down = down_next; - free_rdataset(mctx, dcurrent); + free_rdataset(rbtdb, mctx, dcurrent); } else dparent = dcurrent; } @@ -1053,7 +1412,7 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, top_prev->next = current->next; else node->data = current->next; - free_rdataset(mctx, current); + free_rdataset(rbtdb, mctx, current); /* * current no longer exists, so we can * just continue with the loop. @@ -1069,7 +1428,7 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, else node->data = down_next; down_next->next = top_next; - free_rdataset(mctx, current); + free_rdataset(rbtdb, mctx, current); current = down_next; } } @@ -1096,7 +1455,7 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, do { down_next = dcurrent->down; INSIST(dcurrent->serial <= least_serial); - free_rdataset(mctx, dcurrent); + free_rdataset(rbtdb, mctx, dcurrent); dcurrent = down_next; } while (dcurrent != NULL); dparent->down = NULL; @@ -1120,7 +1479,7 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, top_prev->next = current->next; else node->data = current->next; - free_rdataset(mctx, current); + free_rdataset(rbtdb, mctx, current); } else top_prev = current; } @@ -1129,6 +1488,49 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, node->dirty = 0; } +/*% + * Clean up dead nodes. These are nodes which have no references, and + * have no data. They are dead but we could not or chose not to delete + * them when we deleted all the data at that node because we did not want + * to wait for the tree write lock. + * + * The caller must hold a tree write lock and bucketnum'th node (write) lock. + */ +static void +cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) { + dns_rbtnode_t *node; + isc_result_t result; + int count = 10; /* XXXJT: should be adjustable */ + + node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); + while (node != NULL && count > 0) { + ISC_LIST_UNLINK(rbtdb->deadnodes[bucketnum], node, deadlink); + + /* + * Since we're holding a tree write lock, it should be + * impossible for this node to be referenced by others. + */ + INSIST(dns_rbtnode_refcurrent(node) == 0 && + node->data == NULL); + + INSIST(!ISC_LINK_LINKED(node, deadlink)); + if (node->nsec3) + result = dns_rbt_deletenode(rbtdb->nsec3, node, + ISC_FALSE); + else + result = dns_rbt_deletenode(rbtdb->tree, node, + ISC_FALSE); + if (result != ISC_R_SUCCESS) + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, + "cleanup_dead_nodes: " + "dns_rbt_deletenode: %s", + isc_result_totext(result)); + node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); + count--; + } +} + /* * Caller must be holding the node lock if its reference must be protected * by the lock. @@ -1139,7 +1541,7 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { isc_refcount_t *lockref; dns_rbtnode_refincrement0(node, &noderefs); - if (noderefs == 1) { /* this is the first reference to the node */ + if (noderefs == 1) { /* this is the first reference to the node */ lockref = &rbtdb->node_locks[node->locknum].references; isc_refcount_increment0(lockref, &lockrefs); INSIST(lockrefs != 0); @@ -1148,6 +1550,49 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { } /* + * This function is assumed to be called when a node is newly referenced + * and can be in the deadnode list. In that case the node must be retrieved + * from the list because it is going to be used. In addition, if the caller + * happens to hold a write lock on the tree, it's a good chance to purge dead + * nodes. + * Note: while a new reference is gained in multiple places, there are only very + * few cases where the node can be in the deadnode list (only empty nodes can + * have been added to the list). + */ +static inline void +reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + isc_rwlocktype_t treelocktype) +{ + isc_boolean_t need_relock = ISC_FALSE; + + NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); + new_reference(rbtdb, node); + + NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_read); + if (ISC_LINK_LINKED(node, deadlink)) + need_relock = ISC_TRUE; + else if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) && + treelocktype == isc_rwlocktype_write) + need_relock = ISC_TRUE; + NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_read); + if (need_relock) { + NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_write); + if (ISC_LINK_LINKED(node, deadlink)) + ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], + node, deadlink); + if (treelocktype == isc_rwlocktype_write) + cleanup_dead_nodes(rbtdb, node->locknum); + NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_write); + } + + NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); +} + +/* * Caller must be holding the node lock; either the "strong", read or write * lock. Note that the lock must be held even when node references are * atomically modified; in that case the decrement operation itself does not @@ -1160,14 +1605,17 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { static isc_boolean_t decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rbtdb_serial_t least_serial, - isc_rwlocktype_t nlock, isc_rwlocktype_t tlock) + isc_rwlocktype_t nlock, isc_rwlocktype_t tlock, + isc_boolean_t pruning) { isc_result_t result; isc_boolean_t write_locked; rbtdb_nodelock_t *nodelock; unsigned int refs, nrefs; + int bucket = node->locknum; + isc_boolean_t no_reference; - nodelock = &rbtdb->node_locks[node->locknum]; + nodelock = &rbtdb->node_locks[bucket]; /* Handle easy and typical case first. */ if (!node->dirty && (node->data != NULL || node->down != NULL)) { @@ -1226,7 +1674,9 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } /* - * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY. + * Attempt to switch to a write lock on the tree. If this fails, + * we will add this node to a linked list of nodes in this locking + * bucket which we will free later. */ if (tlock != isc_rwlocktype_write) { /* @@ -1246,6 +1696,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } else write_locked = ISC_TRUE; + no_reference = ISC_TRUE; if (write_locked && dns_rbtnode_refcurrent(node) == 0) { /* * We can now delete the node if the reference counter is @@ -1254,26 +1705,97 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, * current thread locks the tree (e.g., in findnode()). */ - if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) { - char printname[DNS_NAME_FORMATSIZE]; + /* + * If this node is the only one in the level it's in, deleting + * this node may recursively make its parent the only node in + * the parent level; if so, and if no one is currently using + * the parent node, this is almost the only opportunity to + * clean it up. But the recursive cleanup is not that trivial + * since the child and parent may be in different lock buckets, + * which would cause a lock order reversal problem. To avoid + * the trouble, we'll dispatch a separate event for batch + * cleaning. We need to check whether we're deleting the node + * as a result of pruning to avoid infinite dispatching. + * Note: pruning happens only when a task has been set for the + * rbtdb. If the user of the rbtdb chooses not to set a task, + * it's their responsibility to purge stale leaves (e.g. by + * periodic walk-through). + */ + if (!pruning && node->parent != NULL && + node->parent->down == node && node->left == NULL && + node->right == NULL && rbtdb->task != NULL) { + isc_event_t *ev; + dns_db_t *db; + + ev = isc_event_allocate(rbtdb->common.mctx, NULL, + DNS_EVENT_RBTPRUNE, + prune_tree, node, + sizeof(isc_event_t)); + if (ev != NULL) { + new_reference(rbtdb, node); + db = NULL; + attach((dns_db_t *)rbtdb, &db); + ev->ev_sender = db; + isc_task_send(rbtdb->task, &ev); + no_reference = ISC_FALSE; + } else { + /* + * XXX: this is a weird situation. We could + * ignore this error case, but then the stale + * node will unlikely be purged except via a + * rare condition such as manual cleanup. So + * we queue it in the deadnodes list, hoping + * the memory shortage is temporary and the node + * will be deleted later. + */ + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_INFO, + "decrement_reference: failed to " + "allocate pruning event"); + INSIST(!ISC_LINK_LINKED(node, deadlink)); + ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, + deadlink); + } + } else { + if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) { + char printname[DNS_NAME_FORMATSIZE]; + + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_DEBUG(1), + "decrement_reference: " + "delete from rbt: %p %s", + node, + dns_rbt_formatnodename(node, + printname, + sizeof(printname))); + } - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), - "decrement_reference: " - "delete from rbt: %p %s", - node, - dns_rbt_formatnodename(node, printname, - sizeof(printname))); + INSIST(!ISC_LINK_LINKED(node, deadlink)); + if (node->nsec3) + result = dns_rbt_deletenode(rbtdb->nsec3, node, + ISC_FALSE); + else + result = dns_rbt_deletenode(rbtdb->tree, node, + ISC_FALSE); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, + "decrement_reference: " + "dns_rbt_deletenode: %s", + isc_result_totext(result)); + } } - - result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE); - if (result != ISC_R_SUCCESS) - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, - "decrement_reference: " - "dns_rbt_deletenode: %s", - isc_result_totext(result)); - } + } else if (dns_rbtnode_refcurrent(node) == 0) { + INSIST(!ISC_LINK_LINKED(node, deadlink)); + ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink); + } else + no_reference = ISC_FALSE; /* Restore the lock? */ if (nlock == isc_rwlocktype_read) @@ -1290,7 +1812,71 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, if (write_locked) isc_rwlock_downgrade(&rbtdb->tree_lock); - return (ISC_TRUE); + return (no_reference); +} + +/* + * Prune the tree by recursively cleaning-up single leaves. In the worst + * case, the number of iteration is the number of tree levels, which is at + * most the maximum number of domain name labels, i.e, 127. In practice, this + * should be much smaller (only a few times), and even the worst case would be + * acceptable for a single event. + */ +static void +prune_tree(isc_task_t *task, isc_event_t *event) { + dns_rbtdb_t *rbtdb = event->ev_sender; + dns_rbtnode_t *node = event->ev_arg; + dns_rbtnode_t *parent; + unsigned int locknum; + + UNUSED(task); + + isc_event_free(&event); + + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + locknum = node->locknum; + NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); + do { + parent = node->parent; + decrement_reference(rbtdb, node, 0, isc_rwlocktype_write, + isc_rwlocktype_write, ISC_TRUE); + + if (parent != NULL && parent->down == NULL) { + /* + * node was the only down child of the parent and has + * just been removed. We'll then need to examine the + * parent. Keep the lock if possible; otherwise, + * release the old lock and acquire one for the parent. + */ + if (parent->locknum != locknum) { + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + locknum = parent->locknum; + NODE_LOCK(&rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + } + + /* + * We need to gain a reference to the node before + * decrementing it in the next iteration. In addition, + * if the node is in the dead-nodes list, extract it + * from the list beforehand as we do in + * reactivate_node(). + */ + new_reference(rbtdb, parent); + if (ISC_LINK_LINKED(parent, deadlink)) { + ISC_LIST_UNLINK(rbtdb->deadnodes[locknum], + parent, deadlink); + } + } else + parent = NULL; + + node = parent; + } while (node != NULL); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + + detach((dns_db_t **)&rbtdb); } static inline void @@ -1337,17 +1923,20 @@ cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) { } } -static isc_boolean_t -iszonesecure(dns_db_t *db, dns_dbnode_t *origin) { +static void +iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) { dns_rdataset_t keyset; dns_rdataset_t nsecset, signsecset; + dns_rdata_t rdata = DNS_RDATA_INIT; isc_boolean_t haszonekey = ISC_FALSE; isc_boolean_t hasnsec = ISC_FALSE; + isc_boolean_t hasoptbit = ISC_FALSE; + isc_boolean_t nsec3createflag = ISC_FALSE; isc_result_t result; dns_rdataset_init(&keyset); - result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0, - 0, &keyset, NULL); + result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey, + 0, 0, &keyset, NULL); if (result == ISC_R_SUCCESS) { dns_rdata_t keyrdata = DNS_RDATA_INIT; result = dns_rdataset_first(&keyset); @@ -1361,21 +1950,153 @@ iszonesecure(dns_db_t *db, dns_dbnode_t *origin) { } dns_rdataset_disassociate(&keyset); } - if (!haszonekey) - return (ISC_FALSE); + if (!haszonekey) { + version->secure = dns_db_insecure; + version->havensec3 = ISC_FALSE; + return; + } dns_rdataset_init(&nsecset); dns_rdataset_init(&signsecset); - result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0, - 0, &nsecset, &signsecset); + result = dns_db_findrdataset(db, origin, version, dns_rdatatype_nsec, + 0, 0, &nsecset, &signsecset); if (result == ISC_R_SUCCESS) { if (dns_rdataset_isassociated(&signsecset)) { hasnsec = ISC_TRUE; + result = dns_rdataset_first(&nsecset); + if (result == ISC_R_SUCCESS) { + dns_rdataset_current(&nsecset, &rdata); + hasoptbit = dns_nsec_typepresent(&rdata, + dns_rdatatype_opt); + } dns_rdataset_disassociate(&signsecset); } dns_rdataset_disassociate(&nsecset); } - return (hasnsec); + + setnsec3parameters(db, version, &nsec3createflag); + + /* + * Do we have a valid NSEC/NSEC3 chain? + */ + if (version->havensec3 || (hasnsec && !hasoptbit)) + version->secure = dns_db_secure; + /* + * Do we have a NSEC/NSEC3 chain under creation? + */ + else if (hasoptbit || nsec3createflag) + version->secure = dns_db_partial; + else + version->secure = dns_db_insecure; +} + +/*%< + * Walk the origin node looking for NSEC3PARAM records. + * Cache the nsec3 parameters. + */ +static void +setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, + isc_boolean_t *nsec3createflag) +{ + dns_rbtnode_t *node; + dns_rdata_nsec3param_t nsec3param; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_region_t region; + isc_result_t result; + rdatasetheader_t *header, *header_next; + unsigned char *raw; /* RDATASLAB */ + unsigned int count, length; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + version->havensec3 = ISC_FALSE; + node = rbtdb->origin_node; + NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock), + isc_rwlocktype_read); + for (header = node->data; + header != NULL; + header = header_next) { + header_next = header->next; + do { + if (header->serial <= version->serial && + !IGNORE(header)) { + if (NONEXISTENT(header)) + header = NULL; + break; + } else + header = header->down; + } while (header != NULL); + + if (header != NULL && + header->type == dns_rdatatype_nsec3param) { + /* + * Find A NSEC3PARAM with a supported algorithm. + */ + raw = (unsigned char *)header + sizeof(*header); + count = raw[0] * 256 + raw[1]; /* count */ +#if DNS_RDATASET_FIXED + raw += count * 4 + 2; +#else + raw += 2; +#endif + while (count-- > 0U) { + length = raw[0] * 256 + raw[1]; +#if DNS_RDATASET_FIXED + raw += 4; +#else + raw += 2; +#endif + region.base = raw; + region.length = length; + raw += length; + dns_rdata_fromregion(&rdata, + rbtdb->common.rdclass, + dns_rdatatype_nsec3param, + ®ion); + result = dns_rdata_tostruct(&rdata, + &nsec3param, + NULL); + INSIST(result == ISC_R_SUCCESS); + dns_rdata_reset(&rdata); + + if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && + !dns_nsec3_supportedhash(nsec3param.hash)) + continue; + +#ifdef RFC5155_STRICT + if (nsec3param.flags != 0) + continue; +#else + if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) + != 0) + *nsec3createflag = ISC_TRUE; + if ((nsec3param.flags & ~DNS_NSEC3FLAG_OPTOUT) + != 0) + continue; +#endif + + INSIST(nsec3param.salt_length <= + sizeof(version->salt)); + memcpy(version->salt, nsec3param.salt, + nsec3param.salt_length); + version->hash = nsec3param.hash; + version->salt_length = nsec3param.salt_length; + version->iterations = nsec3param.iterations; + version->flags = nsec3param.flags; + version->havensec3 = ISC_TRUE; + /* + * Look for a better algorithm than the + * unknown test algorithm. + */ + if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) + goto unlock; + } + } + } + unlock: + NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), + isc_rwlocktype_read); + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); } static void @@ -1384,10 +2105,12 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { rbtdb_version_t *version, *cleanup_version, *least_greater; isc_boolean_t rollback = ISC_FALSE; rbtdb_changedlist_t cleanup_list; + rdatasetheaderlist_t resigned_list; rbtdb_changed_t *changed, *next_changed; rbtdb_serial_t serial, least_serial; dns_rbtnode_t *rbtnode; unsigned int refs; + rdatasetheader_t *header; isc_boolean_t writer; REQUIRE(VALID_RBTDB(rbtdb)); @@ -1395,9 +2118,10 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { cleanup_version = NULL; ISC_LIST_INIT(cleanup_list); + ISC_LIST_INIT(resigned_list); isc_refcount_decrement(&version->references, &refs); - if (refs > 0) { /* typical and easy case first */ + if (refs > 0) { /* typical and easy case first */ if (commit) { RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read); INSIST(!version->writer); @@ -1484,12 +2208,16 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { INSIST(cur_ref == 1); PREPEND(rbtdb->open_versions, rbtdb->current_version, link); + resigned_list = version->resigned_list; + ISC_LIST_INIT(version->resigned_list); } else { /* * We're rolling back this transaction. */ cleanup_list = version->changed_list; ISC_LIST_INIT(version->changed_list); + resigned_list = version->resigned_list; + ISC_LIST_INIT(version->resigned_list); rollback = ISC_TRUE; cleanup_version = version; rbtdb->future_version = NULL; @@ -1542,7 +2270,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { * Update the zone's secure status. */ if (writer && commit && !IS_CACHE(rbtdb)) - rbtdb->secure = iszonesecure(db, rbtdb->origin_node); + iszonesecure(db, version, rbtdb->origin_node); if (cleanup_version != NULL) { INSIST(EMPTY(cleanup_version->changed_list)); @@ -1550,7 +2278,35 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { sizeof(*cleanup_version)); } + /* + * Commit/rollback re-signed headers. + */ + for (header = HEAD(resigned_list); + header != NULL; + header = HEAD(resigned_list)) { + ISC_LIST_UNLINK(resigned_list, header, lru_link); + if (rollback) { + nodelock_t *lock; + lock = &rbtdb->node_locks[header->node->locknum].lock; + NODE_LOCK(lock, isc_rwlocktype_write); + resign_insert(rbtdb, header->node->locknum, header); + NODE_UNLOCK(lock, isc_rwlocktype_write); + } + decrement_reference(rbtdb, header->node, least_serial, + isc_rwlocktype_write, isc_rwlocktype_none, + ISC_FALSE); + } + if (!EMPTY(cleanup_list)) { + /* + * We acquire a tree write lock here in order to make sure + * that stale nodes will be removed in decrement_reference(). + * If we didn't have the lock, those nodes could miss the + * chance to be removed until the server stops. The write lock + * is expensive, but this event should be rare enough to justify + * the cost. + */ + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); for (changed = HEAD(cleanup_list); changed != NULL; changed = next_changed) { @@ -1561,19 +2317,27 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { lock = &rbtdb->node_locks[rbtnode->locknum].lock; NODE_LOCK(lock, isc_rwlocktype_write); + /* + * This is a good opportunity to purge any dead nodes, + * so use it. + */ + cleanup_dead_nodes(rbtdb, rbtnode->locknum); + if (rollback) rollback_node(rbtnode, serial); decrement_reference(rbtdb, rbtnode, least_serial, isc_rwlocktype_write, - isc_rwlocktype_none); + isc_rwlocktype_write, ISC_FALSE); + NODE_UNLOCK(lock, isc_rwlocktype_write); isc_mem_put(rbtdb->common.mctx, changed, sizeof(*changed)); } + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); } - end: + end: *versionp = NULL; } @@ -1606,6 +2370,7 @@ add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) { result = dns_rbt_addnode(rbtdb->tree, &foundname, &node); if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) return (result); + node->nsec3 = 0; node->find_callback = 1; node->wild = 1; return (ISC_R_SUCCESS); @@ -1623,7 +2388,7 @@ add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) { l = dns_name_countlabels(&rbtdb->common.origin); i = l + 1; while (i < n) { - dns_rbtnode_t *node = NULL; /* dummy */ + dns_rbtnode_t *node = NULL; /* dummy */ dns_name_getlabelsequence(name, n - i, i, &foundname); if (dns_name_iswildcard(&foundname)) { result = add_wildcard_magic(rbtdb, &foundname); @@ -1633,6 +2398,7 @@ add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) { &node); if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) return (result); + node->nsec3 = 0; } i++; } @@ -1678,6 +2444,7 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, node->locknum = dns_name_hash(&nodename, ISC_TRUE) % rbtdb->node_lock_count; #endif + node->nsec3 = 0; add_empty_wildcards(rbtdb, name); if (dns_name_iswildcard(name)) { @@ -1692,6 +2459,60 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, return (result); } } + reactivate_node(rbtdb, node, locktype); + RWUNLOCK(&rbtdb->tree_lock, locktype); + + *nodep = (dns_dbnode_t *)node; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create, + dns_dbnode_t **nodep) +{ + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + dns_rbtnode_t *node = NULL; + dns_name_t nodename; + isc_result_t result; + isc_rwlocktype_t locktype = isc_rwlocktype_read; + + REQUIRE(VALID_RBTDB(rbtdb)); + + dns_name_init(&nodename, NULL); + RWLOCK(&rbtdb->tree_lock, locktype); + result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, &node, NULL, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + if (result != ISC_R_SUCCESS) { + RWUNLOCK(&rbtdb->tree_lock, locktype); + if (!create) { + if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + return (result); + } + /* + * It would be nice to try to upgrade the lock instead of + * unlocking then relocking. + */ + locktype = isc_rwlocktype_write; + RWLOCK(&rbtdb->tree_lock, locktype); + node = NULL; + result = dns_rbt_addnode(rbtdb->nsec3, name, &node); + if (result == ISC_R_SUCCESS) { + dns_rbt_namefromnode(node, &nodename); +#ifdef DNS_RBT_USEHASH + node->locknum = node->hashval % rbtdb->node_lock_count; +#else + node->locknum = dns_name_hash(&nodename, ISC_TRUE) % + rbtdb->node_lock_count; +#endif + node->nsec3 = 1U; + } else if (result != ISC_R_EXISTS) { + RWUNLOCK(&rbtdb->tree_lock, locktype); + return (result); + } + } else + INSIST(node->nsec3); NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); new_reference(rbtdb, node); NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); @@ -1846,7 +2667,7 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdatasetheader_t *header, isc_stdtime_t now, dns_rdataset_t *rdataset) { - unsigned char *raw; /* RDATASLAB */ + unsigned char *raw; /* RDATASLAB */ /* * Caller must be holding the node reader lock. @@ -1861,16 +2682,18 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, new_reference(rbtdb, node); - INSIST(rdataset->methods == NULL); /* We must be disassociated. */ + INSIST(rdataset->methods == NULL); /* We must be disassociated. */ rdataset->methods = &rdataset_methods; rdataset->rdclass = rbtdb->common.rdclass; rdataset->type = RBTDB_RDATATYPE_BASE(header->type); rdataset->covers = RBTDB_RDATATYPE_EXT(header->type); - rdataset->ttl = header->ttl - now; + rdataset->ttl = header->rdh_ttl - now; rdataset->trust = header->trust; if (NXDOMAIN(header)) rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN; + if (OPTOUT(header)) + rdataset->attributes |= DNS_RDATASETATTR_OPTOUT; rdataset->private1 = rbtdb; rdataset->private2 = node; raw = (unsigned char *)header + sizeof(*header); @@ -1891,6 +2714,18 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdataset->private6 = header->noqname; if (rdataset->private6 != NULL) rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; + rdataset->private7 = header->closest; + if (rdataset->private7 != NULL) + rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; + + /* + * Copy out re-signing information. + */ + if (RESIGN(header)) { + rdataset->attributes |= DNS_RDATASETATTR_RESIGN; + rdataset->resign = header->resign; + } else + rdataset->resign = 0; } static inline isc_result_t @@ -1954,7 +2789,7 @@ static inline isc_boolean_t valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type, dns_rbtnode_t *node) { - unsigned char *raw; /* RDATASLAB */ + unsigned char *raw; /* RDATASLAB */ unsigned int count, size; dns_name_t ns_name; isc_boolean_t valid = ISC_FALSE; @@ -2338,10 +3173,55 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep, return (result); } +static isc_boolean_t +matchparams(rdatasetheader_t *header, rbtdb_search_t *search) +{ + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec3_t nsec3; + unsigned char *raw; /* RDATASLAB */ + unsigned int rdlen, count; + isc_region_t region; + isc_result_t result; + + REQUIRE(header->type == dns_rdatatype_nsec3); + + raw = (unsigned char *)header + sizeof(*header); + count = raw[0] * 256 + raw[1]; /* count */ +#if DNS_RDATASET_FIXED + raw += count * 4 + 2; +#else + raw += 2; +#endif + while (count-- > 0) { + rdlen = raw[0] * 256 + raw[1]; +#if DNS_RDATASET_FIXED + raw += 4; +#else + raw += 2; +#endif + region.base = raw; + region.length = rdlen; + dns_rdata_fromregion(&rdata, search->rbtdb->common.rdclass, + dns_rdatatype_nsec3, ®ion); + raw += rdlen; + result = dns_rdata_tostruct(&rdata, &nsec3, NULL); + INSIST(result == ISC_R_SUCCESS); + if (nsec3.hash == search->rbtversion->hash && + nsec3.iterations == search->rbtversion->iterations && + nsec3.salt_length == search->rbtversion->salt_length && + memcmp(nsec3.salt, search->rbtversion->salt, + nsec3.salt_length) == 0) + return (ISC_TRUE); + dns_rdata_reset(&rdata); + } + return (ISC_FALSE); +} + static inline isc_result_t find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset, isc_boolean_t need_sig) + dns_rdataset_t *sigrdataset, dns_rbt_t *tree, + dns_db_secure_t secure) { dns_rbtnode_t *node; rdatasetheader_t *header, *header_next, *found, *foundsig; @@ -2349,7 +3229,22 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, isc_result_t result; dns_fixedname_t fname, forigin; dns_name_t *name, *origin; + dns_rdatatype_t type; + rbtdb_rdatatype_t sigtype; + isc_boolean_t wraps; + isc_boolean_t need_sig = ISC_TF(secure == dns_db_secure); + if (tree == search->rbtdb->nsec3) { + type = dns_rdatatype_nsec3; + sigtype = RBTDB_RDATATYPE_SIGNSEC3; + wraps = ISC_TRUE; + } else { + type = dns_rdatatype_nsec; + sigtype = RBTDB_RDATATYPE_SIGNSEC; + wraps = ISC_FALSE; + } + + again: do { node = NULL; dns_fixedname_init(&fname); @@ -2391,12 +3286,11 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, * active rdataset at this node. */ empty_node = ISC_FALSE; - if (header->type == dns_rdatatype_nsec) { + if (header->type == type) { found = header; if (foundsig != NULL) break; - } else if (header->type == - RBTDB_RDATATYPE_SIGNSEC) { + } else if (header->type == sigtype) { foundsig = header; if (found != NULL) break; @@ -2404,11 +3298,19 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, } } if (!empty_node) { - if (found != NULL && - (foundsig != NULL || !need_sig)) + if (found != NULL && search->rbtversion->havensec3 && + found->type == dns_rdatatype_nsec3 && + !matchparams(found, search)) { + empty_node = ISC_TRUE; + found = NULL; + foundsig = NULL; + result = dns_rbtnodechain_prev(&search->chain, + NULL, NULL); + } else if (found != NULL && + (foundsig != NULL || !need_sig)) { /* - * We've found the right NSEC record. + * We've found the right NSEC/NSEC3 record. * * Note: for this to really be the right * NSEC record, it's essential that the NSEC @@ -2465,6 +3367,15 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, isc_rwlocktype_read); } while (empty_node && result == ISC_R_SUCCESS); + if (result == ISC_R_NOMORE && wraps) { + result = dns_rbtnodechain_last(&search->chain, tree, + NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { + wraps = ISC_FALSE; + goto again; + } + } + /* * If the result is ISC_R_NOMORE, then we got to the beginning of * the database and didn't find a NSEC record. This shouldn't @@ -2497,7 +3408,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, isc_boolean_t active; dns_rbtnodechain_t chain; nodelock_t *lock; - + dns_rbt_t *tree; search.rbtdb = (dns_rbtdb_t *)db; @@ -2540,7 +3451,9 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * encounter a callback node, zone_zonecut_callback() will search the * rdatasets at the zone cut for active DNAME or NS rdatasets. */ - result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node, + tree = (options & DNS_DBFIND_FORCENSEC3) != 0 ? search.rbtdb->nsec3 : + search.rbtdb->tree; + result = dns_rbt_findnode(tree, name, foundname, &node, &search.chain, DNS_RBTFIND_EMPTYDATA, zone_zonecut_callback, &search); @@ -2578,12 +3491,14 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * If we're here, then the name does not exist, is not * beneath a zonecut, and there's no matching wildcard. */ - if (search.rbtdb->secure || - (search.options & DNS_DBFIND_FORCENSEC) != 0) + if ((search.rbtversion->secure == dns_db_secure && + !search.rbtversion->havensec3) || + (search.options & DNS_DBFIND_FORCENSEC) != 0 || + (search.options & DNS_DBFIND_FORCENSEC3) != 0) { result = find_closest_nsec(&search, nodep, foundname, - rdataset, sigrdataset, - search.rbtdb->secure); + rdataset, sigrdataset, tree, + search.rbtversion->secure); if (result == ISC_R_SUCCESS) result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN; @@ -2704,6 +3619,14 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, break; } + + /* + * If the NSEC3 record doesn't match the chain + * we are using behave as if it isn't here. + */ + if (header->type == dns_rdatatype_nsec3 && + !matchparams(header, &search)) + goto partial_match; /* * If we found a type we were looking for, * remember it. @@ -2748,14 +3671,16 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, */ if (!maybe_zonecut && found != NULL) break; - } else if (header->type == dns_rdatatype_nsec) { + } else if (header->type == dns_rdatatype_nsec && + !search.rbtversion->havensec3) { /* * Remember a NSEC rdataset even if we're * not specifically looking for it, because * we might need it later. */ nsecheader = header; - } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) { + } else if (header->type == RBTDB_RDATATYPE_SIGNSEC && + !search.rbtversion->havensec3) { /* * If we need the NSEC rdataset, we'll also * need its signature. @@ -2807,7 +3732,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * The desired type doesn't exist. */ result = DNS_R_NXRRSET; - if (search.rbtdb->secure && + if (search.rbtversion->secure == dns_db_secure && + !search.rbtversion->havensec3 && (nsecheader == NULL || nsecsig == NULL)) { /* * The zone is secure but there's no NSEC, @@ -2822,7 +3748,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, NODE_UNLOCK(lock, isc_rwlocktype_read); result = find_closest_nsec(&search, nodep, foundname, rdataset, sigrdataset, - search.rbtdb->secure); + search.rbtdb->tree, + search.rbtversion->secure); if (result == ISC_R_SUCCESS) result = DNS_R_EMPTYWILD; goto tree_exit; @@ -2841,7 +3768,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, new_reference(search.rbtdb, node); *nodep = node; } - if (search.rbtdb->secure || + if ((search.rbtversion->secure == dns_db_secure && + !search.rbtversion->havensec3) || (search.options & DNS_DBFIND_FORCENSEC) != 0) { bind_rdataset(search.rbtdb, node, nsecheader, @@ -2882,6 +3810,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * validated updates. */ if (type == dns_rdatatype_nsec || + type == dns_rdatatype_nsec3 || type == dns_rdatatype_key) result = ISC_R_SUCCESS; else if (type == dns_rdatatype_any) @@ -2948,7 +3877,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, NODE_LOCK(lock, isc_rwlocktype_read); decrement_reference(search.rbtdb, node, 0, - isc_rwlocktype_read, isc_rwlocktype_none); + isc_rwlocktype_read, isc_rwlocktype_none, + ISC_FALSE); NODE_UNLOCK(lock, isc_rwlocktype_read); } @@ -3010,7 +3940,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (header->ttl <= search->now) { + if (header->rdh_ttl <= search->now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right @@ -3018,7 +3948,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { * the node as dirty, so it will get cleaned * up later. */ - if ((header->ttl <= search->now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl <= search->now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -3044,13 +3974,16 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { * stale headers first. */ mctx = search->rbtdb->common.mctx; - clean_stale_headers(mctx, header); + clean_stale_headers(search->rbtdb, + mctx, + header); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; - free_rdataset(mctx, header); + free_rdataset(search->rbtdb, mctx, + header); } else { header->attributes |= RDATASET_ATTR_STALE; @@ -3079,6 +4012,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { * search->zonecut_rdataset will still be valid later. */ new_reference(search->rbtdb, node); + INSIST(!ISC_LINK_LINKED(node, deadlink)); search->zonecut = node; search->zonecut_rdataset = dname_header; search->zonecut_sigrdataset = sigdname_header; @@ -3130,7 +4064,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, header != NULL; header = header_next) { header_next = header->next; - if (header->ttl <= search->now) { + if (header->rdh_ttl <= search->now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right @@ -3138,7 +4072,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, * the node as dirty, so it will get cleaned * up later. */ - if ((header->ttl <= search->now - + if ((header->rdh_ttl <= search->now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { @@ -3153,14 +4087,17 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, isc_mem_t *m; m = search->rbtdb->common.mctx; - clean_stale_headers(m, header); + clean_stale_headers( + search->rbtdb, + m, header); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; - free_rdataset(m, header); + free_rdataset(rbtdb, m, + header); } else { header->attributes |= RDATASET_ATTR_STALE; @@ -3229,6 +4166,23 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, if (foundsig != NULL) bind_rdataset(search->rbtdb, node, foundsig, search->now, sigrdataset); + if (need_headerupdate(found, search->now) || + (foundsig != NULL && + need_headerupdate(foundsig, search->now))) { + if (locktype != isc_rwlocktype_write) { + NODE_UNLOCK(lock, locktype); + NODE_LOCK(lock, isc_rwlocktype_write); + locktype = isc_rwlocktype_write; + } + if (need_headerupdate(found, search->now)) + update_header(search->rbtdb, found, + search->now); + if (foundsig != NULL && + need_headerupdate(foundsig, search->now)) { + update_header(search->rbtdb, foundsig, + search->now); + } + } } node_exit: @@ -3286,7 +4240,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, header != NULL; header = header_next) { header_next = header->next; - if (header->ttl <= now) { + if (header->rdh_ttl <= now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right @@ -3294,7 +4248,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, * node as dirty, so it will get cleaned up * later. */ - if ((header->ttl <= now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -3308,13 +4262,16 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, isc_mem_t *m; m = search->rbtdb->common.mctx; - clean_stale_headers(m, header); + clean_stale_headers( + search->rbtdb, + m, header); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; - free_rdataset(m, header); + free_rdataset(search->rbtdb, m, + header); } else { header->attributes |= RDATASET_ATTR_STALE; @@ -3377,6 +4334,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *found, *nsheader; rdatasetheader_t *foundsig, *nssig, *cnamesig; + rdatasetheader_t *update, *updatesig; rbtdb_rdatatype_t sigtype, negtype; UNUSED(version); @@ -3399,6 +4357,8 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, dns_fixedname_init(&search.zonecut_name); dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx); search.now = now; + update = NULL; + updatesig = NULL; RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); @@ -3462,14 +4422,14 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (header->ttl <= now) { + if (header->rdh_ttl <= now) { /* * This rdataset is stale. If no one else is using the * node, we can clean it up right now, otherwise we * mark it as stale, and the node as dirty, so it will * get cleaned up later. */ - if ((header->ttl <= now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -3482,13 +4442,15 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, isc_mem_t *mctx; mctx = search.rbtdb->common.mctx; - clean_stale_headers(mctx, header); + clean_stale_headers(search.rbtdb, mctx, + header); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; - free_rdataset(mctx, header); + free_rdataset(search.rbtdb, mctx, + header); } else { header->attributes |= RDATASET_ATTR_STALE; @@ -3595,13 +4557,19 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, if (nsheader != NULL) { if (nodep != NULL) { new_reference(search.rbtdb, node); + INSIST(!ISC_LINK_LINKED(node, deadlink)); *nodep = node; } bind_rdataset(search.rbtdb, node, nsheader, search.now, rdataset); - if (nssig != NULL) + if (need_headerupdate(nsheader, search.now)) + update = nsheader; + if (nssig != NULL) { bind_rdataset(search.rbtdb, node, nssig, search.now, sigrdataset); + if (need_headerupdate(nssig, search.now)) + updatesig = nssig; + } result = DNS_R_DELEGATION; goto node_exit; } @@ -3619,6 +4587,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, if (nodep != NULL) { new_reference(search.rbtdb, node); + INSIST(!ISC_LINK_LINKED(node, deadlink)); *nodep = node; } @@ -3650,12 +4619,28 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, result == DNS_R_NCACHENXRRSET) { bind_rdataset(search.rbtdb, node, found, search.now, rdataset); - if (foundsig != NULL) + if (need_headerupdate(found, search.now)) + update = found; + if (foundsig != NULL) { bind_rdataset(search.rbtdb, node, foundsig, search.now, sigrdataset); + if (need_headerupdate(foundsig, search.now)) + updatesig = foundsig; + } } node_exit: + if ((update != NULL || updatesig != NULL) && + locktype != isc_rwlocktype_write) { + NODE_UNLOCK(lock, locktype); + NODE_LOCK(lock, isc_rwlocktype_write); + locktype = isc_rwlocktype_write; + } + if (update != NULL && need_headerupdate(update, search.now)) + update_header(search.rbtdb, update, search.now); + if (updatesig != NULL && need_headerupdate(updatesig, search.now)) + update_header(search.rbtdb, updatesig, search.now); + NODE_UNLOCK(lock, locktype); tree_exit: @@ -3671,7 +4656,8 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, NODE_LOCK(lock, isc_rwlocktype_read); decrement_reference(search.rbtdb, node, 0, - isc_rwlocktype_read, isc_rwlocktype_none); + isc_rwlocktype_read, isc_rwlocktype_none, + ISC_FALSE); NODE_UNLOCK(lock, isc_rwlocktype_read); } @@ -3745,14 +4731,14 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (header->ttl <= now) { + if (header->rdh_ttl <= now) { /* * This rdataset is stale. If no one else is using the * node, we can clean it up right now, otherwise we * mark it as stale, and the node as dirty, so it will * get cleaned up later. */ - if ((header->ttl <= now - RBTDB_VIRTUAL) && + if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -3765,13 +4751,15 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, isc_mem_t *mctx; mctx = search.rbtdb->common.mctx; - clean_stale_headers(mctx, header); + clean_stale_headers(search.rbtdb, mctx, + header); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; - free_rdataset(mctx, header); + free_rdataset(search.rbtdb, mctx, + header); } else { header->attributes |= RDATASET_ATTR_STALE; @@ -3814,6 +4802,7 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, if (nodep != NULL) { new_reference(search.rbtdb, node); + INSIST(!ISC_LINK_LINKED(node, deadlink)); *nodep = node; } @@ -3822,6 +4811,21 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, bind_rdataset(search.rbtdb, node, foundsig, search.now, sigrdataset); + if (need_headerupdate(found, search.now) || + (foundsig != NULL && need_headerupdate(foundsig, search.now))) { + if (locktype != isc_rwlocktype_write) { + NODE_UNLOCK(lock, locktype); + NODE_LOCK(lock, isc_rwlocktype_write); + locktype = isc_rwlocktype_write; + } + if (need_headerupdate(found, search.now)) + update_header(search.rbtdb, found, search.now); + if (foundsig != NULL && + need_headerupdate(foundsig, search.now)) { + update_header(search.rbtdb, foundsig, search.now); + } + } + NODE_UNLOCK(lock, locktype); tree_exit: @@ -3871,7 +4875,7 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { NODE_LOCK(&nodelock->lock, isc_rwlocktype_read); if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, - isc_rwlocktype_none)) { + isc_rwlocktype_none, ISC_FALSE)) { if (isc_refcount_current(&nodelock->references) == 0 && nodelock->exiting) { inactive = ISC_TRUE; @@ -3938,8 +4942,8 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { /* * Note that 'log' can be true IFF rbtdb->overmem is also true. - * rbtdb->ovemem can currently only be true for cache databases - * -- hence all of the "overmem cache" log strings. + * rbtdb->overmem can currently only be true for cache + * databases -- hence all of the "overmem cache" log strings. */ log = ISC_TF(isc_log_wouldlog(dns_lctx, level)); if (log) @@ -3959,7 +4963,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { isc_rwlocktype_write); for (header = rbtnode->data; header != NULL; header = header->next) - if (header->ttl <= now - RBTDB_VIRTUAL) { + if (header->rdh_ttl <= now - RBTDB_VIRTUAL) { /* * We don't check if refcurrent(rbtnode) == 0 and try * to free like we do in cache_find(), because @@ -3974,7 +4978,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { printname); } else if (force_expire) { if (! RETAIN(header)) { - header->ttl = 0; + set_ttl(rbtdb, header, 0); header->attributes |= RDATASET_ATTR_STALE; rbtnode->dirty = 1; } else if (log) { @@ -3997,9 +5001,8 @@ static void overmem(dns_db_t *db, isc_boolean_t overmem) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; - if (IS_CACHE(rbtdb)) { + if (IS_CACHE(rbtdb)) rbtdb->overmem = overmem; - } } static void @@ -4030,11 +5033,13 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { first = ISC_FALSE; fprintf(out, "\tserial = %lu, ttl = %u, " - "trust = %u, attributes = %u\n", + "trust = %u, attributes = %u, " + "resign = %u\n", (unsigned long)current->serial, - current->ttl, + current->rdh_ttl, current->trust, - current->attributes); + current->attributes, + current->resign); current = current->down; } while (current != NULL); } @@ -4046,8 +5051,7 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { } static isc_result_t -createiterator(dns_db_t *db, isc_boolean_t relative_names, - dns_dbiterator_t **iteratorp) +createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; rbtdb_dbiterator_t *rbtdbiter; @@ -4061,7 +5065,8 @@ createiterator(dns_db_t *db, isc_boolean_t relative_names, rbtdbiter->common.methods = &dbiterator_methods; rbtdbiter->common.db = NULL; dns_db_attach(db, &rbtdbiter->common.db); - rbtdbiter->common.relative_names = relative_names; + rbtdbiter->common.relative_names = + ISC_TF((options & DNS_DB_RELATIVENAMES) != 0); rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC; rbtdbiter->common.cleaning = ISC_FALSE; rbtdbiter->paused = ISC_TRUE; @@ -4071,8 +5076,15 @@ createiterator(dns_db_t *db, isc_boolean_t relative_names, dns_fixedname_init(&rbtdbiter->origin); rbtdbiter->node = NULL; rbtdbiter->delete = 0; + rbtdbiter->nsec3only = ISC_TF((options & DNS_DB_NSEC3ONLY) != 0); + rbtdbiter->nonsec3 = ISC_TF((options & DNS_DB_NONSEC3) != 0); memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions)); dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx); + dns_rbtnodechain_init(&rbtdbiter->nsec3chain, db->mctx); + if (rbtdbiter->nsec3only) + rbtdbiter->current = &rbtdbiter->nsec3chain; + else + rbtdbiter->current = &rbtdbiter->chain; *iteratorp = (dns_dbiterator_t *)rbtdbiter; @@ -4204,8 +5216,8 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, for (header = rbtnode->data; header != NULL; header = header_next) { header_next = header->next; - if (header->ttl <= now) { - if ((header->ttl <= now - RBTDB_VIRTUAL) && + if (header->rdh_ttl <= now) { + if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) && (locktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -4355,19 +5367,15 @@ cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) { * Look for active extant "other data". * * "Other data" is any rdataset whose type is not - * KEY, RRSIG KEY, NSEC, RRSIG NSEC or RRSIG CNAME. + * KEY, NSEC, SIG or RRSIG. */ rdtype = RBTDB_RDATATYPE_BASE(header->type); - if (rdtype == dns_rdatatype_rrsig || - rdtype == dns_rdatatype_sig) - rdtype = RBTDB_RDATATYPE_EXT(header->type); - if (rdtype != dns_rdatatype_nsec && - rdtype != dns_rdatatype_key && - rdtype != dns_rdatatype_cname) { + if (rdtype != dns_rdatatype_key && + rdtype != dns_rdatatype_sig && + rdtype != dns_rdatatype_nsec && + rdtype != dns_rdatatype_rrsig) { /* - * We've found a type that isn't - * NSEC, KEY, CNAME, or one of their - * signatures. Is it active and extant? + * Is it active and extant? */ do { if (header->serial <= serial && @@ -4395,6 +5403,16 @@ cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) { } static isc_result_t +resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) { + isc_result_t result; + + INSIST(newheader->heap_index == 0); + INSIST(!ISC_LINK_LINKED(newheader, lru_link)); + result = isc_heap_insert(rbtdb->heaps[idx], newheader); + return (result); +} + +static isc_result_t add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading, dns_rdataset_t *addedrdataset, isc_stdtime_t now) @@ -4409,6 +5427,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, dns_rdatatype_t rdtype, covers; rbtdb_rdatatype_t negtype; dns_trust_t trust; + int idx; /* * Add an rdatasetheader_t to a node. @@ -4437,7 +5456,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, */ changed = add_changed(rbtdb, rbtversion, rbtnode); if (changed == NULL) { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); return (ISC_R_NOMEMORY); } } @@ -4466,7 +5485,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, for (topheader = rbtnode->data; topheader != NULL; topheader = topheader->next) { - topheader->ttl = 0; + set_ttl(rbtdb, topheader, 0); topheader->attributes |= RDATASET_ATTR_STALE; } @@ -4489,7 +5508,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, break; } if (topheader != NULL && EXISTS(topheader) && - topheader->ttl > now) { + topheader->rdh_ttl > now) { /* * Found one. */ @@ -4498,8 +5517,8 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * The NXDOMAIN/NODATA(QTYPE=ANY) * is more trusted. */ - - free_rdataset(rbtdb->common.mctx, + free_rdataset(rbtdb, + rbtdb->common.mctx, newheader); if (addedrdataset != NULL) bind_rdataset(rbtdb, rbtnode, @@ -4511,7 +5530,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * The new rdataset is better. Expire the * NXDOMAIN/NODATA(QTYPE=ANY). */ - topheader->ttl = 0; + set_ttl(rbtdb, topheader, 0); topheader->attributes |= RDATASET_ATTR_STALE; rbtnode->dirty = 1; topheader = NULL; @@ -4546,7 +5565,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Deleting an already non-existent rdataset has no effect. */ if (header_nx && newheader_nx) { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); return (DNS_R_UNCHANGED); } @@ -4555,8 +5574,8 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * has no effect, provided that the cache data isn't stale. */ if (rbtversion == NULL && trust < header->trust && - (header->ttl > now || header_nx)) { - free_rdataset(rbtdb->common.mctx, newheader); + (header->rdh_ttl > now || header_nx)) { + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); if (addedrdataset != NULL) bind_rdataset(rbtdb, rbtnode, header, now, addedrdataset); @@ -4582,9 +5601,9 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, if ((options & DNS_DBADD_EXACT) != 0) flags |= DNS_RDATASLAB_EXACT; if ((options & DNS_DBADD_EXACTTTL) != 0 && - newheader->ttl != header->ttl) + newheader->rdh_ttl != header->rdh_ttl) result = DNS_R_NOTEXACT; - else if (newheader->ttl != header->ttl) + else if (newheader->rdh_ttl != header->rdh_ttl) flags |= DNS_RDATASLAB_FORCE; if (result == ISC_R_SUCCESS) result = dns_rdataslab_merge( @@ -4604,10 +5623,16 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * alone. It will get cleaned up when * clean_zone_node() runs. */ - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, + newheader); newheader = (rdatasetheader_t *)merged; + if (loading && RESIGN(newheader) && + RESIGN(header) && + header->resign < newheader->resign) + newheader->resign = header->resign; } else { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, + newheader); return (result); } } @@ -4618,7 +5643,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Don't lower trust of existing record if the * update is forced. */ - if (IS_CACHE(rbtdb) && header->ttl > now && + if (IS_CACHE(rbtdb) && header->rdh_ttl > now && header->type == dns_rdatatype_ns && !header_nx && !newheader_nx && header->trust >= newheader->trust && @@ -4631,20 +5656,25 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Honour the new ttl if it is less than the * older one. */ - if (header->ttl > newheader->ttl) - header->ttl = newheader->ttl; + if (header->rdh_ttl > newheader->rdh_ttl) + set_ttl(rbtdb, header, newheader->rdh_ttl); if (header->noqname == NULL && newheader->noqname != NULL) { header->noqname = newheader->noqname; newheader->noqname = NULL; } - free_rdataset(rbtdb->common.mctx, newheader); + if (header->closest == NULL && + newheader->closest != NULL) { + header->closest = newheader->closest; + newheader->closest = NULL; + } + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); if (addedrdataset != NULL) bind_rdataset(rbtdb, rbtnode, header, now, addedrdataset); return (ISC_R_SUCCESS); } - if (IS_CACHE(rbtdb) && header->ttl > now && + if (IS_CACHE(rbtdb) && header->rdh_ttl > now && (header->type == dns_rdatatype_a || header->type == dns_rdatatype_aaaa) && !header_nx && !newheader_nx && @@ -4656,14 +5686,19 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Honour the new ttl if it is less than the * older one. */ - if (header->ttl > newheader->ttl) - header->ttl = newheader->ttl; + if (header->rdh_ttl > newheader->rdh_ttl) + set_ttl(rbtdb, header, newheader->rdh_ttl); if (header->noqname == NULL && newheader->noqname != NULL) { header->noqname = newheader->noqname; newheader->noqname = NULL; } - free_rdataset(rbtdb->common.mctx, newheader); + if (header->closest == NULL && + newheader->closest != NULL) { + header->closest = newheader->closest; + newheader->closest = NULL; + } + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); if (addedrdataset != NULL) bind_rdataset(rbtdb, rbtnode, header, now, addedrdataset); @@ -4684,7 +5719,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * loading, we MUST clean up 'header' now. */ newheader->down = NULL; - free_rdataset(rbtdb->common.mctx, header); + free_rdataset(rbtdb, rbtdb->common.mctx, header); } else { newheader->down = topheader; topheader->next = newheader; @@ -4692,9 +5727,23 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, if (changed != NULL) changed->dirty = ISC_TRUE; if (rbtversion == NULL) { - header->ttl = 0; + set_ttl(rbtdb, header, 0); header->attributes |= RDATASET_ATTR_STALE; } + idx = newheader->node->locknum; + if (IS_CACHE(rbtdb)) { + ISC_LIST_PREPEND(rbtdb->rdatasets[idx], + newheader, lru_link); + /* + * XXXMLG We don't check the return value + * here. If it fails, we will not do TTL + * based expiry on this node. However, we + * will do it on the LRU side, so memory + * will not leak... for long. + */ + isc_heap_insert(rbtdb->heaps[idx], newheader); + } else if (RESIGN(newheader)) + resign_insert(rbtdb, idx, newheader); } } else { /* @@ -4706,7 +5755,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * If we're trying to delete the type, don't bother. */ if (newheader_nx) { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); return (DNS_R_UNCHANGED); } @@ -4740,6 +5789,14 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, newheader->down = NULL; rbtnode->data = newheader; } + idx = newheader->node->locknum; + if (IS_CACHE(rbtdb)) { + ISC_LIST_PREPEND(rbtdb->rdatasets[idx], + newheader, lru_link); + isc_heap_insert(rbtdb->heaps[idx], newheader); + } else if (RESIGN(newheader)) { + resign_insert(rbtdb, idx, newheader); + } } /* @@ -4778,15 +5835,15 @@ addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader, struct noqname *noqname; isc_mem_t *mctx = rbtdb->common.mctx; dns_name_t name; - dns_rdataset_t nsec, nsecsig; + dns_rdataset_t neg, negsig; isc_result_t result; isc_region_t r; dns_name_init(&name, NULL); - dns_rdataset_init(&nsec); - dns_rdataset_init(&nsecsig); + dns_rdataset_init(&neg); + dns_rdataset_init(&negsig); - result = dns_rdataset_getnoqname(rdataset, &name, &nsec, &nsecsig); + result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig); RUNTIME_CHECK(result == ISC_R_SUCCESS); noqname = isc_mem_get(mctx, sizeof(*noqname)); @@ -4795,31 +5852,84 @@ addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader, goto cleanup; } dns_name_init(&noqname->name, NULL); - noqname->nsec = NULL; - noqname->nsecsig = NULL; + noqname->neg = NULL; + noqname->negsig = NULL; + noqname->type = neg.type; result = dns_name_dup(&name, mctx, &noqname->name); if (result != ISC_R_SUCCESS) goto cleanup; - result = dns_rdataslab_fromrdataset(&nsec, mctx, &r, 0); + result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0); if (result != ISC_R_SUCCESS) goto cleanup; - noqname->nsec = r.base; - result = dns_rdataslab_fromrdataset(&nsecsig, mctx, &r, 0); + noqname->neg = r.base; + result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0); if (result != ISC_R_SUCCESS) goto cleanup; - noqname->nsecsig = r.base; - dns_rdataset_disassociate(&nsec); - dns_rdataset_disassociate(&nsecsig); + noqname->negsig = r.base; + dns_rdataset_disassociate(&neg); + dns_rdataset_disassociate(&negsig); newheader->noqname = noqname; return (ISC_R_SUCCESS); cleanup: - dns_rdataset_disassociate(&nsec); - dns_rdataset_disassociate(&nsecsig); + dns_rdataset_disassociate(&neg); + dns_rdataset_disassociate(&negsig); free_noqname(mctx, &noqname); return(result); } +static inline isc_result_t +addclosest(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader, + dns_rdataset_t *rdataset) +{ + struct noqname *closest; + isc_mem_t *mctx = rbtdb->common.mctx; + dns_name_t name; + dns_rdataset_t neg, negsig; + isc_result_t result; + isc_region_t r; + + dns_name_init(&name, NULL); + dns_rdataset_init(&neg); + dns_rdataset_init(&negsig); + + result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + closest = isc_mem_get(mctx, sizeof(*closest)); + if (closest == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + dns_name_init(&closest->name, NULL); + closest->neg = NULL; + closest->negsig = NULL; + closest->type = neg.type; + result = dns_name_dup(&name, mctx, &closest->name); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0); + if (result != ISC_R_SUCCESS) + goto cleanup; + closest->neg = r.base; + result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0); + if (result != ISC_R_SUCCESS) + goto cleanup; + closest->negsig = r.base; + dns_rdataset_disassociate(&neg); + dns_rdataset_disassociate(&negsig); + newheader->closest = closest; + return (ISC_R_SUCCESS); + + cleanup: + dns_rdataset_disassociate(&neg); + dns_rdataset_disassociate(&negsig); + free_noqname(mctx, &closest); + return(result); +} + +static dns_dbmethods_t zone_methods; + static isc_result_t addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, @@ -4830,11 +5940,21 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rbtdb_version_t *rbtversion = version; isc_region_t region; rdatasetheader_t *newheader; + rdatasetheader_t *header; isc_result_t result; isc_boolean_t delegating; + isc_boolean_t tree_locked = ISC_FALSE; REQUIRE(VALID_RBTDB(rbtdb)); + if (rbtdb->common.methods == &zone_methods) + REQUIRE(((rbtnode->nsec3 && + (rdataset->type == dns_rdatatype_nsec3 || + rdataset->covers == dns_rdatatype_nsec3)) || + (!rbtnode->nsec3 && + rdataset->type != dns_rdatatype_nsec3 && + rdataset->covers != dns_rdatatype_nsec3))); + if (rbtversion == NULL) { if (now == 0) isc_stdtime_get(&now); @@ -4848,26 +5968,48 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, return (result); newheader = (rdatasetheader_t *)region.base; - newheader->ttl = rdataset->ttl + now; + init_rdataset(rbtdb, newheader); + set_ttl(rbtdb, newheader, rdataset->ttl + now); newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type, rdataset->covers); newheader->attributes = 0; newheader->noqname = NULL; + newheader->closest = NULL; newheader->count = init_count++; newheader->trust = rdataset->trust; newheader->additional_auth = NULL; newheader->additional_glue = NULL; + newheader->last_used = now; + newheader->node = rbtnode; if (rbtversion != NULL) { newheader->serial = rbtversion->serial; now = 0; + + if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { + newheader->attributes |= RDATASET_ATTR_RESIGN; + newheader->resign = rdataset->resign; + } else + newheader->resign = 0; } else { newheader->serial = 1; + newheader->resign = 0; if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) newheader->attributes |= RDATASET_ATTR_NXDOMAIN; + if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0) + newheader->attributes |= RDATASET_ATTR_OPTOUT; if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) { result = addnoqname(rbtdb, newheader, rdataset); if (result != ISC_R_SUCCESS) { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, + newheader); + return (result); + } + } + if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) { + result = addclosest(rbtdb, newheader, rdataset); + if (result != ISC_R_SUCCESS) { + free_rdataset(rbtdb, rbtdb->common.mctx, + newheader); return (result); } } @@ -4876,18 +6018,54 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, /* * If we're adding a delegation type (e.g. NS or DNAME for a zone, * just DNAME for the cache), then we need to set the callback bit - * on the node, and to do that we must be holding an exclusive lock - * on the tree. + * on the node. */ - if (delegating_type(rbtdb, rbtnode, rdataset->type)) { + if (delegating_type(rbtdb, rbtnode, rdataset->type)) delegating = ISC_TRUE; - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - } else + else delegating = ISC_FALSE; + /* + * If we're adding a delegation type or the DB is a cache in an overmem + * state, hold an exclusive lock on the tree. In the latter case + * the lock does not necessarily have to be acquired but it will help + * purge stale entries more effectively. + */ + if (delegating || (IS_CACHE(rbtdb) && rbtdb->overmem)) { + tree_locked = ISC_TRUE; + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + } + + if (IS_CACHE(rbtdb) && rbtdb->overmem) + overmem_purge(rbtdb, rbtnode->locknum, now, tree_locked); + NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); + if (rbtdb->rrsetstats != NULL) { + newheader->attributes |= RDATASET_ATTR_STATCOUNT; + update_rrsetstats(rbtdb, newheader, ISC_TRUE); + } + + if (IS_CACHE(rbtdb)) { + if (tree_locked) + cleanup_dead_nodes(rbtdb, rbtnode->locknum); + + header = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1); + if (header && header->rdh_ttl <= now - RBTDB_VIRTUAL) + expire_header(rbtdb, header, tree_locked); + + /* + * If we've been holding a write lock on the tree just for + * cleaning, we can release it now. However, we still need the + * node lock. + */ + if (tree_locked && !delegating) { + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + tree_locked = ISC_FALSE; + } + } + result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE, addedrdataset, now); if (result == ISC_R_SUCCESS && delegating) @@ -4896,15 +6074,15 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); - if (delegating) + if (tree_locked) RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); /* * Update the zone's secure status. If version is non-NULL - * this is defered until closeversion() is called. + * this is deferred until closeversion() is called. */ if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb)) - rbtdb->secure = iszonesecure(db, rbtdb->origin_node); + iszonesecure(db, version, rbtdb->origin_node); return (result); } @@ -4925,29 +6103,46 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, REQUIRE(VALID_RBTDB(rbtdb)); + if (rbtdb->common.methods == &zone_methods) + REQUIRE(((rbtnode->nsec3 && + (rdataset->type == dns_rdatatype_nsec3 || + rdataset->covers == dns_rdatatype_nsec3)) || + (!rbtnode->nsec3 && + rdataset->type != dns_rdatatype_nsec3 && + rdataset->covers != dns_rdatatype_nsec3))); + result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, ®ion, sizeof(rdatasetheader_t)); if (result != ISC_R_SUCCESS) return (result); newheader = (rdatasetheader_t *)region.base; - newheader->ttl = rdataset->ttl; + init_rdataset(rbtdb, newheader); + set_ttl(rbtdb, newheader, rdataset->ttl); newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type, rdataset->covers); newheader->attributes = 0; newheader->serial = rbtversion->serial; newheader->trust = 0; newheader->noqname = NULL; + newheader->closest = NULL; newheader->count = init_count++; newheader->additional_auth = NULL; newheader->additional_glue = NULL; + newheader->last_used = 0; + newheader->node = rbtnode; + if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { + newheader->attributes |= RDATASET_ATTR_RESIGN; + newheader->resign = rdataset->resign; + } else + newheader->resign = 0; NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); changed = add_changed(rbtdb, rbtversion, rbtnode); if (changed == NULL) { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); return (ISC_R_NOMEMORY); @@ -4975,7 +6170,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, result = ISC_R_SUCCESS; if ((options & DNS_DBSUB_EXACT) != 0) { flags |= DNS_RDATASLAB_EXACT; - if (newheader->ttl != header->ttl) + if (newheader->rdh_ttl != header->rdh_ttl) result = DNS_R_NOTEXACT; } if (result == ISC_R_SUCCESS) @@ -4988,8 +6183,9 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, (dns_rdatatype_t)header->type, flags, &subresult); if (result == ISC_R_SUCCESS) { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); newheader = (rdatasetheader_t *)subresult; + init_rdataset(rbtdb, newheader); /* * We have to set the serial since the rdataslab * subtraction routine copies the reserved portion of @@ -5008,24 +6204,27 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * This subtraction would remove all of the rdata; * add a nonexistent header instead. */ - free_rdataset(rbtdb->common.mctx, newheader); - newheader = isc_mem_get(rbtdb->common.mctx, - sizeof(*newheader)); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); + newheader = new_rdataset(rbtdb, rbtdb->common.mctx); if (newheader == NULL) { result = ISC_R_NOMEMORY; goto unlock; } - newheader->ttl = 0; + set_ttl(rbtdb, newheader, 0); newheader->type = topheader->type; newheader->attributes = RDATASET_ATTR_NONEXISTENT; newheader->trust = 0; newheader->serial = rbtversion->serial; newheader->noqname = NULL; + newheader->closest = NULL; newheader->count = 0; newheader->additional_auth = NULL; newheader->additional_glue = NULL; + newheader->node = rbtnode; + newheader->resign = 0; + newheader->last_used = 0; } else { - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); goto unlock; } @@ -5048,7 +6247,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * The rdataset doesn't exist, so we don't need to do anything * to satisfy the deletion request. */ - free_rdataset(rbtdb->common.mctx, newheader); + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); if ((options & DNS_DBSUB_EXACT) != 0) result = DNS_R_NOTEXACT; else @@ -5064,10 +6263,10 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, /* * Update the zone's secure status. If version is non-NULL - * this is defered until closeversion() is called. + * this is deferred until closeversion() is called. */ if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb)) - rbtdb->secure = iszonesecure(db, rbtdb->origin_node); + iszonesecure(db, rbtdb->current_version, rbtdb->origin_node); return (result); } @@ -5089,14 +6288,15 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, if (type == dns_rdatatype_rrsig && covers == 0) return (ISC_R_NOTIMPLEMENTED); - newheader = isc_mem_get(rbtdb->common.mctx, sizeof(*newheader)); + newheader = new_rdataset(rbtdb, rbtdb->common.mctx); if (newheader == NULL) return (ISC_R_NOMEMORY); - newheader->ttl = 0; + set_ttl(rbtdb, newheader, 0); newheader->type = RBTDB_RDATATYPE_VALUE(type, covers); newheader->attributes = RDATASET_ATTR_NONEXISTENT; newheader->trust = 0; newheader->noqname = NULL; + newheader->closest = NULL; newheader->additional_auth = NULL; newheader->additional_glue = NULL; if (rbtversion != NULL) @@ -5104,6 +6304,8 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, else newheader->serial = 0; newheader->count = 0; + newheader->last_used = 0; + newheader->node = rbtnode; NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); @@ -5116,10 +6318,10 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, /* * Update the zone's secure status. If version is non-NULL - * this is defered until closeversion() is called. + * this is deferred until closeversion() is called. */ if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb)) - rbtdb->secure = iszonesecure(db, rbtdb->origin_node); + iszonesecure(db, rbtdb->current_version, rbtdb->origin_node); return (result); } @@ -5147,7 +6349,9 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin)) return (DNS_R_NOTZONETOP); - add_empty_wildcards(rbtdb, name); + if (rdataset->type != dns_rdatatype_nsec3 && + rdataset->covers != dns_rdatatype_nsec3) + add_empty_wildcards(rbtdb, name); if (dns_name_iswildcard(name)) { /* @@ -5155,13 +6359,27 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { */ if (rdataset->type == dns_rdatatype_ns) return (DNS_R_INVALIDNS); + /* + * NSEC3 record owners cannot legally be wild cards. + */ + if (rdataset->type == dns_rdatatype_nsec3) + return (DNS_R_INVALIDNSEC3); result = add_wildcard_magic(rbtdb, name); if (result != ISC_R_SUCCESS) return (result); } node = NULL; - result = dns_rbt_addnode(rbtdb->tree, name, &node); + if (rdataset->type == dns_rdatatype_nsec3 || + rdataset->covers == dns_rdatatype_nsec3) { + result = dns_rbt_addnode(rbtdb->nsec3, name, &node); + if (result == ISC_R_SUCCESS) + node->nsec3 = 1; + } else { + result = dns_rbt_addnode(rbtdb->tree, name, &node); + if (result == ISC_R_SUCCESS) + node->nsec3 = 0; + } if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) return (result); if (result != ISC_R_EXISTS) { @@ -5182,16 +6400,26 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { if (result != ISC_R_SUCCESS) return (result); newheader = (rdatasetheader_t *)region.base; - newheader->ttl = rdataset->ttl + loadctx->now; /* XXX overflow check */ + init_rdataset(rbtdb, newheader); + set_ttl(rbtdb, newheader, + rdataset->ttl + loadctx->now); /* XXX overflow check */ newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type, rdataset->covers); newheader->attributes = 0; newheader->trust = rdataset->trust; newheader->serial = 1; newheader->noqname = NULL; + newheader->closest = NULL; newheader->count = init_count++; newheader->additional_auth = NULL; newheader->additional_glue = NULL; + newheader->last_used = 0; + newheader->node = node; + if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { + newheader->attributes |= RDATASET_ATTR_RESIGN; + newheader->resign = rdataset->resign; + } else + newheader->resign = 0; result = add(rbtdb, node, rbtdb->current_version, newheader, DNS_DBADD_MERGE, ISC_TRUE, NULL, 0); @@ -5262,7 +6490,7 @@ endload(dns_db_t *db, dns_dbload_t **dbloadp) { * zone key, we consider the zone secure. */ if (! IS_CACHE(rbtdb)) - rbtdb->secure = iszonesecure(db, rbtdb->origin_node); + iszonesecure(db, rbtdb->current_version, rbtdb->origin_node); *dbloadp = NULL; @@ -5292,7 +6520,7 @@ delete_callback(void *data, void *arg) { for (current = data; current != NULL; current = next) { next = current->next; - free_rdataset(rbtdb->common.mctx, current); + free_rdataset(rbtdb, rbtdb->common.mctx, current); } } @@ -5306,12 +6534,28 @@ issecure(dns_db_t *db) { REQUIRE(VALID_RBTDB(rbtdb)); RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - secure = rbtdb->secure; + secure = ISC_TF(rbtdb->current_version->secure == dns_db_secure); RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); return (secure); } +static isc_boolean_t +isdnssec(dns_db_t *db) { + dns_rbtdb_t *rbtdb; + isc_boolean_t dnssec; + + rbtdb = (dns_rbtdb_t *)db; + + REQUIRE(VALID_RBTDB(rbtdb)); + + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + dnssec = ISC_TF(rbtdb->current_version->secure != dns_db_insecure); + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + + return (dnssec); +} + static unsigned int nodecount(dns_db_t *db) { dns_rbtdb_t *rbtdb; @@ -5368,13 +6612,180 @@ getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { *nodep = rbtdb->origin_node; } else { - INSIST(!IS_CACHE(rbtdb)); + INSIST(IS_CACHE(rbtdb)); result = ISC_R_NOTFOUND; } return (result); } +static isc_result_t +getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash, + isc_uint8_t *flags, isc_uint16_t *iterations, + unsigned char *salt, size_t *salt_length) +{ + dns_rbtdb_t *rbtdb; + isc_result_t result = ISC_R_NOTFOUND; + rbtdb_version_t *rbtversion = version; + + rbtdb = (dns_rbtdb_t *)db; + + REQUIRE(VALID_RBTDB(rbtdb)); + + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + + if (rbtversion == NULL) + rbtversion = rbtdb->current_version; + + if (rbtversion->havensec3) { + if (hash != NULL) + *hash = rbtversion->hash; + if (salt != NULL && salt_length != 0) { + REQUIRE(*salt_length > rbtversion->salt_length); + memcpy(salt, rbtversion->salt, rbtversion->salt_length); + } + if (salt_length != NULL) + *salt_length = rbtversion->salt_length; + if (iterations != NULL) + *iterations = rbtversion->iterations; + if (flags != NULL) + *flags = rbtversion->flags; + result = ISC_R_SUCCESS; + } + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + + return (result); +} + +static isc_result_t +setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + isc_stdtime_t oldresign; + isc_result_t result = ISC_R_SUCCESS; + rdatasetheader_t *header; + + REQUIRE(VALID_RBTDB(rbtdb)); + REQUIRE(!IS_CACHE(rbtdb)); + REQUIRE(rdataset != NULL); + + header = rdataset->private3; + header--; + + NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock, + isc_rwlocktype_write); + + oldresign = header->resign; + header->resign = resign; + if (header->heap_index != 0) { + INSIST(RESIGN(header)); + if (resign == 0) { + isc_heap_delete(rbtdb->heaps[header->node->locknum], + header->heap_index); + header->heap_index = 0; + } else if (resign < oldresign) + isc_heap_increased(rbtdb->heaps[header->node->locknum], + header->heap_index); + else + isc_heap_decreased(rbtdb->heaps[header->node->locknum], + header->heap_index); + } else if (resign && header->heap_index == 0) { + header->attributes |= RDATASET_ATTR_RESIGN; + result = resign_insert(rbtdb, header->node->locknum, header); + } + NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock, + isc_rwlocktype_write); + return (result); +} + +static isc_result_t +getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, + dns_name_t *foundname) +{ + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + rdatasetheader_t *header = NULL, *this; + unsigned int i; + isc_result_t result = ISC_R_NOTFOUND; + + REQUIRE(VALID_RBTDB(rbtdb)); + + RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read); + + for (i = 0; i < rbtdb->node_lock_count; i++) { + this = isc_heap_element(rbtdb->heaps[i], 1); + if (this == NULL) + continue; + if (header == NULL) + header = this; + else if (isc_serial_lt(this->resign, header->resign)) + header = this; + } + + if (header == NULL) + goto unlock; + + NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock, + isc_rwlocktype_read); + + bind_rdataset(rbtdb, header->node, header, 0, rdataset); + + if (foundname != NULL) + dns_rbt_fullnamefromnode(header->node, foundname); + + NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock, + isc_rwlocktype_read); + + result = ISC_R_SUCCESS; + + unlock: + RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read); + + return (result); +} + +static void +resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) +{ + rbtdb_version_t *rbtversion = (rbtdb_version_t *)version; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + dns_rbtnode_t *node; + rdatasetheader_t *header; + + REQUIRE(VALID_RBTDB(rbtdb)); + REQUIRE(rdataset != NULL); + REQUIRE(rbtdb->future_version == rbtversion); + REQUIRE(rbtversion->writer); + + node = rdataset->private2; + header = rdataset->private3; + header--; + + RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read); + NODE_LOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_write); + /* + * Delete from heap and save to re-signed list so that it can + * be restored if we backout of this change. + */ + new_reference(rbtdb, node); + isc_heap_delete(rbtdb->heaps[node->locknum], header->heap_index); + header->heap_index = 0; + ISC_LIST_APPEND(rbtversion->resigned_list, header, lru_link); + + NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_write); + RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read); +} + +static dns_stats_t * +getrrsetstats(dns_db_t *db) { + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + + REQUIRE(VALID_RBTDB(rbtdb)); + REQUIRE(IS_CACHE(rbtdb)); /* current restriction */ + + return (rbtdb->rrsetstats); +} + static dns_dbmethods_t zone_methods = { attach, detach, @@ -5403,7 +6814,15 @@ static dns_dbmethods_t zone_methods = { ispersistent, overmem, settask, - getoriginnode + getoriginnode, + NULL, + getnsec3parameters, + findnsec3node, + setsigningtime, + getsigningtime, + resigned, + isdnssec, + NULL }; static dns_dbmethods_t cache_methods = { @@ -5434,7 +6853,15 @@ static dns_dbmethods_t cache_methods = { ispersistent, overmem, settask, - getoriginnode + getoriginnode, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + isdnssec, + getrrsetstats }; isc_result_t @@ -5451,6 +6878,7 @@ dns_rbtdb_create isc_result_t result; int i; dns_name_t name; + isc_boolean_t (*sooner)(void *, void *); /* Keep the compiler happy. */ UNUSED(argc); @@ -5483,11 +6911,20 @@ dns_rbtdb_create if (result != ISC_R_SUCCESS) goto cleanup_lock; + /* + * Initialize node_lock_count in a generic way to support future + * extension which allows the user to specify this value on creation. + * Note that when specified for a cache DB it must be larger than 1 + * as commented with the definition of DEFAULT_CACHE_NODE_LOCK_COUNT. + */ if (rbtdb->node_lock_count == 0) { if (IS_CACHE(rbtdb)) rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT; else rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT; + } else if (rbtdb->node_lock_count < 2 && IS_CACHE(rbtdb)) { + result = ISC_R_RANGE; + goto cleanup_tree_lock; } INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH)); rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count * @@ -5497,6 +6934,53 @@ dns_rbtdb_create goto cleanup_tree_lock; } + rbtdb->rrsetstats = NULL; + if (IS_CACHE(rbtdb)) { + result = dns_rdatasetstats_create(mctx, &rbtdb->rrsetstats); + if (result != ISC_R_SUCCESS) + goto cleanup_node_locks; + rbtdb->rdatasets = isc_mem_get(mctx, rbtdb->node_lock_count * + sizeof(rdatasetheaderlist_t)); + if (rbtdb->rdatasets == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_rrsetstats; + } + for (i = 0; i < (int)rbtdb->node_lock_count; i++) + ISC_LIST_INIT(rbtdb->rdatasets[i]); + } else + rbtdb->rdatasets = NULL; + + /* + * Create the heaps. + */ + rbtdb->heaps = isc_mem_get(mctx, rbtdb->node_lock_count * + sizeof(isc_heap_t *)); + if (rbtdb->heaps == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_rdatasets; + } + for (i = 0; i < (int)rbtdb->node_lock_count; i++) + rbtdb->heaps[i] = NULL; + sooner = IS_CACHE(rbtdb) ? ttl_sooner : resign_sooner; + for (i = 0; i < (int)rbtdb->node_lock_count; i++) { + result = isc_heap_create(mctx, sooner, set_index, 0, + &rbtdb->heaps[i]); + if (result != ISC_R_SUCCESS) + goto cleanup_heaps; + } + + /* + * Create deadnode lists. + */ + rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count * + sizeof(rbtnodelist_t)); + if (rbtdb->deadnodes == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_heaps; + } + for (i = 0; i < (int)rbtdb->node_lock_count; i++) + ISC_LIST_INIT(rbtdb->deadnodes[i]); + rbtdb->active = rbtdb->node_lock_count; for (i = 0; i < (int)(rbtdb->node_lock_count); i++) { @@ -5512,7 +6996,7 @@ dns_rbtdb_create isc_refcount_decrement(&rbtdb->node_locks[i].references, NULL); isc_refcount_destroy(&rbtdb->node_locks[i].references); } - goto cleanup_node_locks; + goto cleanup_deadnodes; } rbtdb->node_locks[i].exiting = ISC_FALSE; } @@ -5525,7 +7009,7 @@ dns_rbtdb_create isc_mem_attach(mctx, &rbtdb->common.mctx); /* - * Must be initalized before free_rbtdb() is called. + * Must be initialized before free_rbtdb() is called. */ isc_ondestroy_init(&rbtdb->common.ondest); @@ -5539,13 +7023,20 @@ dns_rbtdb_create } /* - * Make the Red-Black Tree. + * Make the Red-Black Trees. */ result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree); if (result != ISC_R_SUCCESS) { free_rbtdb(rbtdb, ISC_FALSE, NULL); return (result); } + + result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec3); + if (result != ISC_R_SUCCESS) { + free_rbtdb(rbtdb, ISC_FALSE, NULL); + return (result); + } + /* * In order to set the node callback bit correctly in zone databases, * we need to know if the node has the origin name of the zone. @@ -5568,6 +7059,7 @@ dns_rbtdb_create free_rbtdb(rbtdb, ISC_FALSE, NULL); return (result); } + rbtdb->origin_node->nsec3 = 0; /* * We need to give the origin node the right locknum. */ @@ -5593,7 +7085,6 @@ dns_rbtdb_create return (result); } rbtdb->attributes = 0; - rbtdb->secure = ISC_FALSE; rbtdb->overmem = ISC_FALSE; rbtdb->task = NULL; @@ -5610,6 +7101,14 @@ dns_rbtdb_create free_rbtdb(rbtdb, ISC_FALSE, NULL); return (ISC_R_NOMEMORY); } + rbtdb->current_version->secure = dns_db_insecure; + rbtdb->current_version->havensec3 = ISC_FALSE; + rbtdb->current_version->flags = 0; + rbtdb->current_version->iterations = 0; + rbtdb->current_version->hash = 0; + rbtdb->current_version->salt_length = 0; + memset(rbtdb->current_version->salt, 0, + sizeof(rbtdb->current_version->salt)); rbtdb->future_version = NULL; ISC_LIST_INIT(rbtdb->open_versions); /* @@ -5625,6 +7124,27 @@ dns_rbtdb_create return (ISC_R_SUCCESS); + cleanup_deadnodes: + isc_mem_put(mctx, rbtdb->deadnodes, + rbtdb->node_lock_count * sizeof(rbtnodelist_t)); + + cleanup_heaps: + if (rbtdb->heaps != NULL) { + for (i = 0 ; i < (int)rbtdb->node_lock_count ; i++) + if (rbtdb->heaps[i] != NULL) + isc_heap_destroy(&rbtdb->heaps[i]); + isc_mem_put(mctx, rbtdb->heaps, + rbtdb->node_lock_count * sizeof(isc_heap_t *)); + } + + cleanup_rdatasets: + if (rbtdb->rdatasets != NULL) + isc_mem_put(mctx, rbtdb->rdatasets, rbtdb->node_lock_count * + sizeof(rdatasetheaderlist_t)); + cleanup_rrsetstats: + if (rbtdb->rrsetstats != NULL) + dns_stats_detach(&rbtdb->rrsetstats); + cleanup_node_locks: isc_mem_put(mctx, rbtdb->node_locks, rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t)); @@ -5655,7 +7175,7 @@ rdataset_disassociate(dns_rdataset_t *rdataset) { static isc_result_t rdataset_first(dns_rdataset_t *rdataset) { - unsigned char *raw = rdataset->private3; /* RDATASLAB */ + unsigned char *raw = rdataset->private3; /* RDATASLAB */ unsigned int count; count = raw[0] * 256 + raw[1]; @@ -5691,7 +7211,7 @@ static isc_result_t rdataset_next(dns_rdataset_t *rdataset) { unsigned int count; unsigned int length; - unsigned char *raw; /* RDATASLAB */ + unsigned char *raw; /* RDATASLAB */ count = rdataset->privateuint4; if (count == 0) @@ -5710,9 +7230,9 @@ rdataset_next(dns_rdataset_t *rdataset) { raw += length; #if DNS_RDATASET_FIXED } - rdataset->private5 = raw + 4; /* length(2) + order(2) */ + rdataset->private5 = raw + 4; /* length(2) + order(2) */ #else - rdataset->private5 = raw + 2; /* length(2) */ + rdataset->private5 = raw + 2; /* length(2) */ #endif return (ISC_R_SUCCESS); @@ -5720,11 +7240,13 @@ rdataset_next(dns_rdataset_t *rdataset) { static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { - unsigned char *raw = rdataset->private5; /* RDATASLAB */ + unsigned char *raw = rdataset->private5; /* RDATASLAB */ #if DNS_RDATASET_FIXED unsigned int offset; #endif + unsigned int length; isc_region_t r; + unsigned int flags = 0; REQUIRE(raw != NULL); @@ -5740,15 +7262,22 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { raw += offset; } #endif - r.length = raw[0] * 256 + raw[1]; - + length = raw[0] * 256 + raw[1]; #if DNS_RDATASET_FIXED raw += 4; #else raw += 2; #endif + if (rdataset->type == dns_rdatatype_rrsig) { + if (*raw & DNS_RDATASLAB_OFFLINE) + flags |= DNS_RDATA_OFFLINE; + length--; + raw++; + } + r.length = length; r.base = raw; dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); + rdata->flags |= flags; } static void @@ -5769,7 +7298,7 @@ rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { static unsigned int rdataset_count(dns_rdataset_t *rdataset) { - unsigned char *raw = rdataset->private3; /* RDATASLAB */ + unsigned char *raw = rdataset->private3; /* RDATASLAB */ unsigned int count; count = raw[0] * 256 + raw[1]; @@ -5790,37 +7319,85 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, attachnode(db, node, &cloned_node); nsec->methods = &rdataset_methods; nsec->rdclass = db->rdclass; - nsec->type = dns_rdatatype_nsec; + nsec->type = noqname->type; nsec->covers = 0; nsec->ttl = rdataset->ttl; nsec->trust = rdataset->trust; nsec->private1 = rdataset->private1; nsec->private2 = rdataset->private2; - nsec->private3 = noqname->nsec; + nsec->private3 = noqname->neg; nsec->privateuint4 = 0; nsec->private5 = NULL; nsec->private6 = NULL; + nsec->private7 = NULL; cloned_node = NULL; attachnode(db, node, &cloned_node); nsecsig->methods = &rdataset_methods; nsecsig->rdclass = db->rdclass; nsecsig->type = dns_rdatatype_rrsig; - nsecsig->covers = dns_rdatatype_nsec; + nsecsig->covers = noqname->type; nsecsig->ttl = rdataset->ttl; nsecsig->trust = rdataset->trust; nsecsig->private1 = rdataset->private1; nsecsig->private2 = rdataset->private2; - nsecsig->private3 = noqname->nsecsig; + nsecsig->private3 = noqname->negsig; nsecsig->privateuint4 = 0; nsecsig->private5 = NULL; nsec->private6 = NULL; + nsec->private7 = NULL; dns_name_clone(&noqname->name, name); return (ISC_R_SUCCESS); } +static isc_result_t +rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *nsec, dns_rdataset_t *nsecsig) +{ + dns_db_t *db = rdataset->private1; + dns_dbnode_t *node = rdataset->private2; + dns_dbnode_t *cloned_node; + struct noqname *closest = rdataset->private7; + + cloned_node = NULL; + attachnode(db, node, &cloned_node); + nsec->methods = &rdataset_methods; + nsec->rdclass = db->rdclass; + nsec->type = closest->type; + nsec->covers = 0; + nsec->ttl = rdataset->ttl; + nsec->trust = rdataset->trust; + nsec->private1 = rdataset->private1; + nsec->private2 = rdataset->private2; + nsec->private3 = closest->neg; + nsec->privateuint4 = 0; + nsec->private5 = NULL; + nsec->private6 = NULL; + nsec->private7 = NULL; + + cloned_node = NULL; + attachnode(db, node, &cloned_node); + nsecsig->methods = &rdataset_methods; + nsecsig->rdclass = db->rdclass; + nsecsig->type = dns_rdatatype_rrsig; + nsecsig->covers = closest->type; + nsecsig->ttl = rdataset->ttl; + nsecsig->trust = rdataset->trust; + nsecsig->private1 = rdataset->private1; + nsecsig->private2 = rdataset->private2; + nsecsig->private3 = closest->negsig; + nsecsig->privateuint4 = 0; + nsecsig->private5 = NULL; + nsec->private6 = NULL; + nsec->private7 = NULL; + + dns_name_clone(&closest->name, name); + + return (ISC_R_SUCCESS); +} + /* * Rdataset Iterator Methods */ @@ -5871,13 +7448,13 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) { * record? Or is it too old in the cache? * * Note: unlike everywhere else, we - * check for now > header->ttl instead - * of now >= header->ttl. This allows + * check for now > header->rdh_ttl instead + * of now >= header->rdh_ttl. This allows * ANY and RRSIG queries for 0 TTL * rdatasets to work. */ if (NONEXISTENT(header) || - (now != 0 && now > header->ttl)) + (now != 0 && now > header->rdh_ttl)) header = NULL; break; } else @@ -5953,7 +7530,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { */ if ((header->attributes & RDATASET_ATTR_NONEXISTENT) != 0 || - (now != 0 && now > header->ttl)) + (now != 0 && now > header->rdh_ttl)) header = NULL; break; } else @@ -6009,9 +7586,7 @@ reference_iter_node(rbtdb_dbiterator_t *rbtdbiter) { return; INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none); - NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); - new_reference(rbtdb, node); - NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); + reactivate_node(rbtdb, node, rbtdbiter->tree_locked); } static inline void @@ -6026,7 +7601,7 @@ dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) { lock = &rbtdb->node_locks[node->locknum].lock; NODE_LOCK(lock, isc_rwlocktype_read); decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, - rbtdbiter->tree_locked); + rbtdbiter->tree_locked, ISC_FALSE); NODE_UNLOCK(lock, isc_rwlocktype_read); rbtdbiter->node = NULL; @@ -6067,7 +7642,7 @@ flush_deletions(rbtdb_dbiterator_t *rbtdbiter) { NODE_LOCK(lock, isc_rwlocktype_read); decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, - rbtdbiter->tree_locked); + rbtdbiter->tree_locked, ISC_FALSE); NODE_UNLOCK(lock, isc_rwlocktype_read); } @@ -6117,6 +7692,7 @@ dbiterator_destroy(dns_dbiterator_t **iteratorp) { dns_db_detach(&rbtdbiter->common.db); dns_rbtnodechain_reset(&rbtdbiter->chain); + dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter)); dns_db_detach(&db); @@ -6142,12 +7718,25 @@ dbiterator_first(dns_dbiterator_t *iterator) { name = dns_fixedname_name(&rbtdbiter->name); origin = dns_fixedname_name(&rbtdbiter->origin); dns_rbtnodechain_reset(&rbtdbiter->chain); + dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); - result = dns_rbtnodechain_first(&rbtdbiter->chain, rbtdb->tree, name, - origin); - + if (rbtdbiter->nsec3only) { + rbtdbiter->current = &rbtdbiter->nsec3chain; + result = dns_rbtnodechain_first(rbtdbiter->current, + rbtdb->nsec3, name, origin); + } else { + rbtdbiter->current = &rbtdbiter->chain; + result = dns_rbtnodechain_first(rbtdbiter->current, + rbtdb->tree, name, origin); + if (!rbtdbiter->nonsec3 && result == ISC_R_NOTFOUND) { + rbtdbiter->current = &rbtdbiter->nsec3chain; + result = dns_rbtnodechain_first(rbtdbiter->current, + rbtdb->nsec3, name, + origin); + } + } if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { - result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL, + result = dns_rbtnodechain_current(rbtdbiter->current, NULL, NULL, &rbtdbiter->node); if (result == ISC_R_SUCCESS) { rbtdbiter->new_origin = ISC_TRUE; @@ -6182,11 +7771,21 @@ dbiterator_last(dns_dbiterator_t *iterator) { name = dns_fixedname_name(&rbtdbiter->name); origin = dns_fixedname_name(&rbtdbiter->origin); dns_rbtnodechain_reset(&rbtdbiter->chain); + dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); - result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name, - origin); + result = ISC_R_NOTFOUND; + if (rbtdbiter->nsec3only && !rbtdbiter->nonsec3) { + rbtdbiter->current = &rbtdbiter->nsec3chain; + result = dns_rbtnodechain_last(rbtdbiter->current, + rbtdb->nsec3, name, origin); + } + if (!rbtdbiter->nsec3only && result == ISC_R_NOTFOUND) { + rbtdbiter->current = &rbtdbiter->chain; + result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree, + name, origin); + } if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { - result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL, + result = dns_rbtnodechain_current(rbtdbiter->current, NULL, NULL, &rbtdbiter->node); if (result == ISC_R_SUCCESS) { rbtdbiter->new_origin = ISC_TRUE; @@ -6210,6 +7809,7 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) { dns_name_t *iname, *origin; if (rbtdbiter->result != ISC_R_SUCCESS && + rbtdbiter->result != ISC_R_NOTFOUND && rbtdbiter->result != ISC_R_NOMORE) return (rbtdbiter->result); @@ -6221,22 +7821,74 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) { iname = dns_fixedname_name(&rbtdbiter->name); origin = dns_fixedname_name(&rbtdbiter->origin); dns_rbtnodechain_reset(&rbtdbiter->chain); + dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); + + if (rbtdbiter->nsec3only) { + rbtdbiter->current = &rbtdbiter->nsec3chain; + result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, + &rbtdbiter->node, + rbtdbiter->current, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + } else if (rbtdbiter->nonsec3) { + rbtdbiter->current = &rbtdbiter->chain; + result = dns_rbt_findnode(rbtdb->tree, name, NULL, + &rbtdbiter->node, + rbtdbiter->current, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + } else { + /* + * Stay on main chain if not found on either chain. + */ + rbtdbiter->current = &rbtdbiter->chain; + result = dns_rbt_findnode(rbtdb->tree, name, NULL, + &rbtdbiter->node, + rbtdbiter->current, + DNS_RBTFIND_EMPTYDATA, NULL, NULL); + if (result == DNS_R_PARTIALMATCH) { + dns_rbtnode_t *node = NULL; + result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, + &node, &rbtdbiter->nsec3chain, + DNS_RBTFIND_EMPTYDATA, + NULL, NULL); + if (result == ISC_R_SUCCESS) { + rbtdbiter->node = node; + rbtdbiter->current = &rbtdbiter->nsec3chain; + } + } + } - result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node, - &rbtdbiter->chain, DNS_RBTFIND_EMPTYDATA, - NULL, NULL); +#if 1 if (result == ISC_R_SUCCESS) { - result = dns_rbtnodechain_current(&rbtdbiter->chain, iname, + result = dns_rbtnodechain_current(rbtdbiter->current, iname, origin, NULL); if (result == ISC_R_SUCCESS) { rbtdbiter->new_origin = ISC_TRUE; reference_iter_node(rbtdbiter); } - - } else if (result == DNS_R_PARTIALMATCH) + } else if (result == DNS_R_PARTIALMATCH) { result = ISC_R_NOTFOUND; + rbtdbiter->node = NULL; + } rbtdbiter->result = result; +#else + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { + isc_result_t tresult; + tresult = dns_rbtnodechain_current(rbtdbiter->current, iname, + origin, NULL); + if (tresult == ISC_R_SUCCESS) { + rbtdbiter->new_origin = ISC_TRUE; + reference_iter_node(rbtdbiter); + } else { + result = tresult; + rbtdbiter->node = NULL; + } + } else + rbtdbiter->node = NULL; + + rbtdbiter->result = (result == DNS_R_PARTIALMATCH) ? + ISC_R_SUCCESS : result; +#endif return (result); } @@ -6246,6 +7898,7 @@ dbiterator_prev(dns_dbiterator_t *iterator) { isc_result_t result; rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; dns_name_t *name, *origin; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; REQUIRE(rbtdbiter->node != NULL); @@ -6257,13 +7910,23 @@ dbiterator_prev(dns_dbiterator_t *iterator) { name = dns_fixedname_name(&rbtdbiter->name); origin = dns_fixedname_name(&rbtdbiter->origin); - result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin); + result = dns_rbtnodechain_prev(rbtdbiter->current, name, origin); + if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only && + !rbtdbiter->nonsec3 && + &rbtdbiter->nsec3chain == rbtdbiter->current) { + rbtdbiter->current = &rbtdbiter->chain; + dns_rbtnodechain_reset(rbtdbiter->current); + result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree, + name, origin); + if (result == ISC_R_NOTFOUND) + result = ISC_R_NOMORE; + } dereference_iter_node(rbtdbiter); if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN); - result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL, + result = dns_rbtnodechain_current(rbtdbiter->current, NULL, NULL, &rbtdbiter->node); } @@ -6280,6 +7943,7 @@ dbiterator_next(dns_dbiterator_t *iterator) { isc_result_t result; rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; dns_name_t *name, *origin; + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; REQUIRE(rbtdbiter->node != NULL); @@ -6291,13 +7955,22 @@ dbiterator_next(dns_dbiterator_t *iterator) { name = dns_fixedname_name(&rbtdbiter->name); origin = dns_fixedname_name(&rbtdbiter->origin); - result = dns_rbtnodechain_next(&rbtdbiter->chain, name, origin); + result = dns_rbtnodechain_next(rbtdbiter->current, name, origin); + if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only && + !rbtdbiter->nonsec3 && &rbtdbiter->chain == rbtdbiter->current) { + rbtdbiter->current = &rbtdbiter->nsec3chain; + dns_rbtnodechain_reset(rbtdbiter->current); + result = dns_rbtnodechain_first(rbtdbiter->current, + rbtdb->nsec3, name, origin); + if (result == ISC_R_NOTFOUND) + result = ISC_R_NOMORE; + } dereference_iter_node(rbtdbiter); if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN); - result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL, + result = dns_rbtnodechain_current(rbtdbiter->current, NULL, NULL, &rbtdbiter->node); } if (result == ISC_R_SUCCESS) @@ -6421,7 +8094,7 @@ rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, { dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; - unsigned char *raw = rdataset->private3; /* RDATASLAB */ + unsigned char *raw = rdataset->private3; /* RDATASLAB */ unsigned int current_count = rdataset->privateuint4; unsigned int count; rdatasetheader_t *header; @@ -6567,7 +8240,7 @@ rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, { dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; - unsigned char *raw = rdataset->private3; /* RDATASLAB */ + unsigned char *raw = rdataset->private3; /* RDATASLAB */ unsigned int current_count = rdataset->privateuint4; rdatasetheader_t *header; unsigned int total_count, count; @@ -6673,7 +8346,7 @@ rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, return (ISC_R_SUCCESS); - fail: + fail: if (newcbarg != NULL) { if (newentry != NULL) { acache_cancelentry(rbtdb->common.mctx, newentry, @@ -6696,7 +8369,7 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, { dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; - unsigned char *raw = rdataset->private3; /* RDATASLAB */ + unsigned char *raw = rdataset->private3; /* RDATASLAB */ unsigned int current_count = rdataset->privateuint4; rdatasetheader_t *header; nodelock_t *nodelock; @@ -6705,7 +8378,7 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, dns_acacheentry_t *entry; acache_cbarg_t *cbarg; - UNUSED(qtype); /* we do not use this value at least for now */ + UNUSED(qtype); /* we do not use this value at least for now */ UNUSED(acache); if (type == dns_rdatasetadditional_fromcache) @@ -6752,9 +8425,159 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, NODE_UNLOCK(nodelock, isc_rwlocktype_write); if (entry != NULL) { - acache_cancelentry(rbtdb->common.mctx, entry, &cbarg); + if (cbarg != NULL) + acache_cancelentry(rbtdb->common.mctx, entry, &cbarg); dns_acache_detachentry(&entry); } return (ISC_R_SUCCESS); } + +/*% + * Routines for LRU-based cache management. + */ + +/*% + * See if a given cache entry that is being reused needs to be updated + * in the LRU-list. From the LRU management point of view, this function is + * expected to return true for almost all cases. When used with threads, + * however, this may cause a non-negligible performance penalty because a + * writer lock will have to be acquired before updating the list. + * If DNS_RBTDB_LIMITLRUUPDATE is defined to be non 0 at compilation time, this + * function returns true if the entry has not been updated for some period of + * time. We differentiate the NS or glue address case and the others since + * experiments have shown that the former tends to be accessed relatively + * infrequently and the cost of cache miss is higher (e.g., a missing NS records + * may cause external queries at a higher level zone, involving more + * transactions). + * + * Caller must hold the node (read or write) lock. + */ +static inline isc_boolean_t +need_headerupdate(rdatasetheader_t *header, isc_stdtime_t now) { + if ((header->attributes & + (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) + return (ISC_FALSE); + +#if DNS_RBTDB_LIMITLRUUPDATE + if (header->type == dns_rdatatype_ns || + (header->trust == dns_trust_glue && + (header->type == dns_rdatatype_a || + header->type == dns_rdatatype_aaaa))) { + /* + * Glue records are updated if at least 60 seconds have passed + * since the previous update time. + */ + return (header->last_used + 60 <= now); + } + + /* Other records are updated if 5 minutes have passed. */ + return (header->last_used + 300 <= now); +#else + UNUSED(now); + + return (ISC_TRUE); +#endif +} + +/*% + * Update the timestamp of a given cache entry and move it to the head + * of the corresponding LRU list. + * + * Caller must hold the node (write) lock. + * + * Note that the we do NOT touch the heap here, as the TTL has not changed. + */ +static void +update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_stdtime_t now) +{ + INSIST(IS_CACHE(rbtdb)); + + /* To be checked: can we really assume this? XXXMLG */ + INSIST(ISC_LINK_LINKED(header, lru_link)); + + ISC_LIST_UNLINK(rbtdb->rdatasets[header->node->locknum], + header, lru_link); + header->last_used = now; + ISC_LIST_PREPEND(rbtdb->rdatasets[header->node->locknum], + header, lru_link); +} + +/*% + * Purge some expired and/or stale (i.e. unused for some period) cache entries + * under an overmem condition. To recover from this condition quickly, up to + * 2 entries will be purged. This process is triggered while adding a new + * entry, and we specifically avoid purging entries in the same LRU bucket as + * the one to which the new entry will belong. Otherwise, we might purge + * entries of the same name of different RR types while adding RRsets from a + * single response (consider the case where we're adding A and AAAA glue records + * of the same NS name). + */ +static void +overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, + isc_stdtime_t now, isc_boolean_t tree_locked) +{ + rdatasetheader_t *header, *header_prev; + unsigned int locknum; + int purgecount = 2; + + for (locknum = (locknum_start + 1) % rbtdb->node_lock_count; + locknum != locknum_start && purgecount > 0; + locknum = (locknum + 1) % rbtdb->node_lock_count) { + NODE_LOCK(&rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + + header = isc_heap_element(rbtdb->heaps[locknum], 1); + if (header && header->rdh_ttl <= now - RBTDB_VIRTUAL) { + expire_header(rbtdb, header, tree_locked); + purgecount--; + } + + for (header = ISC_LIST_TAIL(rbtdb->rdatasets[locknum]); + header != NULL && purgecount > 0; + header = header_prev) { + header_prev = ISC_LIST_PREV(header, lru_link); + /* + * Unlink the entry at this point to avoid checking it + * again even if it's currently used someone else and + * cannot be purged at this moment. This entry won't be + * referenced any more (so unlinking is safe) since the + * TTL was reset to 0. + */ + ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header, + lru_link); + expire_header(rbtdb, header, tree_locked); + purgecount--; + } + + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, + isc_rwlocktype_write); + } +} + +static void +expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_boolean_t tree_locked) +{ + set_ttl(rbtdb, header, 0); + header->attributes |= RDATASET_ATTR_STALE; + header->node->dirty = 1; + + /* + * Caller must hold the node (write) lock. + */ + + if (dns_rbtnode_refcurrent(header->node) == 0) { + /* + * If no one else is using the node, we can clean it up now. + * We first need to gain a new reference to the node to meet a + * requirement of decrement_reference(). + */ + new_reference(rbtdb, header->node); + decrement_reference(rbtdb, header->node, 0, + isc_rwlocktype_write, + tree_locked ? isc_rwlocktype_write : + isc_rwlocktype_none, ISC_FALSE); + } +} diff --git a/lib/dns/rbtdb.h b/lib/dns/rbtdb.h index f9fb50b..b024d13 100644 --- a/lib/dns/rbtdb.h +++ b/lib/dns/rbtdb.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.h,v 1.14.18.2 2005/04/29 00:16:02 marka Exp $ */ +/* $Id: rbtdb.h,v 1.18 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_RBTDB_H #define DNS_RBTDB_H 1 diff --git a/lib/dns/rbtdb64.c b/lib/dns/rbtdb64.c index 773fe91..5e325fa 100644 --- a/lib/dns/rbtdb64.c +++ b/lib/dns/rbtdb64.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb64.c,v 1.7.18.2 2005/04/29 00:16:02 marka Exp $ */ +/* $Id: rbtdb64.c,v 1.11 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/rbtdb64.h b/lib/dns/rbtdb64.h index e2de45c..fe11622 100644 --- a/lib/dns/rbtdb64.h +++ b/lib/dns/rbtdb64.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb64.h,v 1.13.18.2 2005/04/29 00:16:02 marka Exp $ */ +/* $Id: rbtdb64.h,v 1.17 2007/06/19 23:47:16 tbox Exp $ */ #ifndef DNS_RBTDB64_H #define DNS_RBTDB64_H 1 diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index f61aa35..58ade85 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rcode.c,v 1.2.18.2 2006/01/27 23:57:44 marka Exp $ */ +/* $Id: rcode.c,v 1.8 2008/09/25 04:02:38 tbox Exp $ */ #include <config.h> #include <ctype.h> @@ -66,7 +66,7 @@ #define ERCODENAMES \ /* extended rcodes */ \ { dns_rcode_badvers, "BADVERS", 0}, \ - { 0, NULL, 0 } + { 0, NULL, 0 } #define TSIGRCODENAMES \ /* extended rcodes */ \ @@ -96,8 +96,10 @@ { DNS_KEYALG_RSAMD5, "RSA", 0 }, \ { DNS_KEYALG_DH, "DH", 0 }, \ { DNS_KEYALG_DSA, "DSA", 0 }, \ + { DNS_KEYALG_NSEC3DSA, "NSEC3DSA", 0 }, \ { DNS_KEYALG_ECC, "ECC", 0 }, \ { DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \ + { DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \ { DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \ { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \ { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \ @@ -114,6 +116,10 @@ { 255, "ALL", 0 }, \ { 0, NULL, 0} +#define HASHALGNAMES \ + { 1, "SHA-1", 0 }, \ + { 0, NULL, 0 } + struct tbl { unsigned int value; const char *name; @@ -125,6 +131,7 @@ static struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES }; static struct tbl certs[] = { CERTNAMES }; static struct tbl secalgs[] = { SECALGNAMES }; static struct tbl secprotos[] = { SECPROTONAMES }; +static struct tbl hashalgs[] = { HASHALGNAMES }; static struct keyflag { const char *name; @@ -238,7 +245,7 @@ dns_mnemonic_fromtext(unsigned int *valuep, isc_textregion_t *source, static isc_result_t dns_mnemonic_totext(unsigned int value, isc_buffer_t *target, - struct tbl *table) + struct tbl *table) { int i = 0; char buf[sizeof("4294967296")]; @@ -271,7 +278,7 @@ dns_tsigrcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source) { RETERR(dns_mnemonic_fromtext(&value, source, tsigrcodes, 0xffff)); *rcodep = value; return (ISC_R_SUCCESS); -} +} isc_result_t dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) { @@ -318,6 +325,14 @@ dns_secproto_totext(dns_secproto_t secproto, isc_buffer_t *target) { } isc_result_t +dns_hashalg_fromtext(unsigned char *hashalg, isc_textregion_t *source) { + unsigned int value; + RETERR(dns_mnemonic_fromtext(&value, source, hashalgs, 0xff)); + *hashalg = value; + return (ISC_R_SUCCESS); +} + +isc_result_t dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source) { isc_result_t result; diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index 5641777..ab9df8b 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdata.c,v 1.184.18.9 2006/07/21 02:05:57 marka Exp $ */ +/* $Id: rdata.c,v 1.199.50.2 2009/02/16 23:47:15 tbox Exp $ */ /*! \file */ @@ -111,7 +111,7 @@ typedef struct dns_rdata_textctx { dns_name_t *origin; /*%< Current origin, or NULL. */ unsigned int flags; /*%< DNS_STYLEFLAG_* */ unsigned int width; /*%< Width of rdata column. */ - const char *linebreak; /*%< Line break string. */ + const char *linebreak; /*%< Line break string. */ } dns_rdata_textctx_t; static isc_result_t @@ -162,6 +162,9 @@ uint16_fromregion(isc_region_t *region); static isc_uint8_t uint8_fromregion(isc_region_t *region); +static isc_uint8_t +uint8_consume_fromregion(isc_region_t *region); + static isc_result_t mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); @@ -201,6 +204,9 @@ static void warn_badmx(isc_token_t *token, isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks); +static isc_uint16_t +uint16_consume_fromregion(isc_region_t *region); + static inline int getquad(const void *src, struct in_addr *dst, isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) @@ -269,7 +275,7 @@ dns_rdata_init(dns_rdata_t *rdata) { /* ISC_LIST_INIT(rdata->list); */ } -#if 0 +#if 1 #define DNS_RDATA_INITIALIZED(rdata) \ ((rdata)->data == NULL && (rdata)->length == 0 && \ (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \ @@ -282,8 +288,9 @@ dns_rdata_init(dns_rdata_t *rdata) { #define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE #endif #endif + #define DNS_RDATA_VALIDFLAGS(rdata) \ - (((rdata)->flags & ~DNS_RDATA_UPDATE) == 0) + (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0) void dns_rdata_reset(dns_rdata_t *rdata) { @@ -532,7 +539,7 @@ unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type, result = isc_buffer_allocate(mctx, &buf, token.value.as_ulong); if (result != ISC_R_SUCCESS) return (result); - + result = isc_hex_tobuffer(lexer, buf, (unsigned int)token.value.as_ulong); if (result != ISC_R_SUCCESS) @@ -728,7 +735,7 @@ dns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target) isc_result_t dns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin, unsigned int flags, unsigned int width, - char *linebreak, isc_buffer_t *target) + const char *linebreak, isc_buffer_t *target) { dns_rdata_textctx_t tctx; @@ -901,7 +908,7 @@ dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) { hash = ((a + n) * b) % 256; /* - * This switch block is inlined via #define, and will use "return" + * This switch block is inlined via \#define, and will use "return" * to return a result to the caller if it is a valid (known) * rdatatype name. */ @@ -1234,6 +1241,14 @@ uint32_fromregion(isc_region_t *region) { } static isc_uint16_t +uint16_consume_fromregion(isc_region_t *region) { + isc_uint16_t r = uint16_fromregion(region); + + isc_region_consume(region, 2); + return r; +} + +static isc_uint16_t uint16_fromregion(isc_region_t *region) { REQUIRE(region->length >= 2); @@ -1249,6 +1264,14 @@ uint8_fromregion(isc_region_t *region) { return (region->base[0]); } +static isc_uint8_t +uint8_consume_fromregion(isc_region_t *region) { + isc_uint8_t r = uint8_fromregion(region); + + isc_region_consume(region, 1); + return r; +} + static isc_result_t mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { isc_region_t tr; @@ -1504,16 +1527,16 @@ byte_btoa(int c, isc_buffer_t *target, struct state *state) { /* * Because some don't support u_long. */ - tmp = 32; - tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32); + tmp = 32; + tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32); } if (tmpword < 0) { - tmp = 64; - tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32); + tmp = 64; + tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32); } if (tr.length < 5) return (ISC_R_NOSPACE); - tr.base[0] = atob_digits[(tmpword / + tr.base[0] = atob_digits[(tmpword / (isc_int32_t)(85 * 85 * 85 * 85)) + tmp]; tmpword %= (isc_int32_t)(85 * 85 * 85 * 85); @@ -1596,7 +1619,7 @@ warn_badmx(isc_token_t *token, isc_lex_t *lexer, if (lexer != NULL) { file = isc_lex_getsourcename(lexer); line = isc_lex_getsourceline(lexer); - (*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", + (*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", file, line, DNS_AS_STR(*token), dns_result_totext(DNS_R_MXISADDRESS)); } @@ -1609,12 +1632,12 @@ warn_badname(dns_name_t *name, isc_lex_t *lexer, const char *file; unsigned long line; char namebuf[DNS_NAME_FORMATSIZE]; - + if (lexer != NULL) { file = isc_lex_getsourcename(lexer); line = isc_lex_getsourceline(lexer); dns_name_format(name, namebuf, sizeof(namebuf)); - (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", + (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", file, line, namebuf, dns_result_totext(DNS_R_BADNAME)); } diff --git a/lib/dns/rdata/any_255/tsig_250.c b/lib/dns/rdata/any_255/tsig_250.c index 4fdadd3..3121f78 100644 --- a/lib/dns/rdata/any_255/tsig_250.c +++ b/lib/dns/rdata/any_255/tsig_250.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsig_250.c,v 1.59.18.2 2005/03/20 22:34:32 marka Exp $ */ +/* $Id: tsig_250.c,v 1.63 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 13:39:43 PST 2000 by gson */ diff --git a/lib/dns/rdata/any_255/tsig_250.h b/lib/dns/rdata/any_255/tsig_250.h index b84a715..0c01667 100644 --- a/lib/dns/rdata/any_255/tsig_250.h +++ b/lib/dns/rdata/any_255/tsig_250.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsig_250.h,v 1.21.18.2 2005/04/29 00:16:29 marka Exp $ */ +/* $Id: tsig_250.h,v 1.25 2007/06/19 23:47:17 tbox Exp $ */ #ifndef ANY_255_TSIG_250_H #define ANY_255_TSIG_250_H 1 diff --git a/lib/dns/rdata/ch_3/a_1.c b/lib/dns/rdata/ch_3/a_1.c index 6a9b70c..78d4ecd 100644 --- a/lib/dns/rdata/ch_3/a_1.c +++ b/lib/dns/rdata/ch_3/a_1.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.c,v 1.2.2.3 2005/08/23 04:10:09 marka Exp $ */ +/* $Id: a_1.c,v 1.6 2007/06/19 23:47:17 tbox Exp $ */ /* by Bjorn.Victor@it.uu.se, 2005-05-07 */ /* Based on generic/soa_6.c and generic/mx_15.c */ diff --git a/lib/dns/rdata/ch_3/a_1.h b/lib/dns/rdata/ch_3/a_1.h index 9f67977..a279d0e 100644 --- a/lib/dns/rdata/ch_3/a_1.h +++ b/lib/dns/rdata/ch_3/a_1.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.h,v 1.2.2.2 2005/06/05 00:02:22 marka Exp $ */ +/* $Id: a_1.h,v 1.5 2007/06/19 23:47:17 tbox Exp $ */ /* by Bjorn.Victor@it.uu.se, 2005-05-07 */ /* Based on generic/mx_15.h */ diff --git a/lib/dns/rdata/generic/afsdb_18.c b/lib/dns/rdata/generic/afsdb_18.c index 24a63e6..2230efb 100644 --- a/lib/dns/rdata/generic/afsdb_18.c +++ b/lib/dns/rdata/generic/afsdb_18.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: afsdb_18.c,v 1.43.18.2 2005/04/29 00:16:30 marka Exp $ */ +/* $Id: afsdb_18.c,v 1.47 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 14:59:00 PST 2000 by explorer */ diff --git a/lib/dns/rdata/generic/afsdb_18.h b/lib/dns/rdata/generic/afsdb_18.h index 1532da1..ccccc11 100644 --- a/lib/dns/rdata/generic/afsdb_18.h +++ b/lib/dns/rdata/generic/afsdb_18.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_AFSDB_18_H #define GENERIC_AFSDB_18_H 1 -/* $Id: afsdb_18.h,v 1.16.18.2 2005/04/29 00:16:30 marka Exp $ */ +/* $Id: afsdb_18.h,v 1.20 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1183 */ diff --git a/lib/dns/rdata/generic/cert_37.c b/lib/dns/rdata/generic/cert_37.c index c6ba3a8..2c45230 100644 --- a/lib/dns/rdata/generic/cert_37.c +++ b/lib/dns/rdata/generic/cert_37.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cert_37.c,v 1.46.18.2 2005/04/29 00:16:30 marka Exp $ */ +/* $Id: cert_37.c,v 1.50 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 21:14:32 EST 2000 by tale */ diff --git a/lib/dns/rdata/generic/cert_37.h b/lib/dns/rdata/generic/cert_37.h index 2af25b7..ddfaa4f 100644 --- a/lib/dns/rdata/generic/cert_37.h +++ b/lib/dns/rdata/generic/cert_37.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cert_37.h,v 1.16.18.2 2005/04/29 00:16:31 marka Exp $ */ +/* $Id: cert_37.h,v 1.20 2007/06/19 23:47:17 tbox Exp $ */ #ifndef GENERIC_CERT_37_H #define GENERIC_CERT_37_H 1 diff --git a/lib/dns/rdata/generic/cname_5.c b/lib/dns/rdata/generic/cname_5.c index 6ea1db1..28c3d60 100644 --- a/lib/dns/rdata/generic/cname_5.c +++ b/lib/dns/rdata/generic/cname_5.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cname_5.c,v 1.45 2004/03/05 05:10:10 marka Exp $ */ +/* $Id: cname_5.c,v 1.47 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 16:48:45 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/cname_5.h b/lib/dns/rdata/generic/cname_5.h index dc24383..516f8d3 100644 --- a/lib/dns/rdata/generic/cname_5.h +++ b/lib/dns/rdata/generic/cname_5.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cname_5.h,v 1.24 2004/03/05 05:10:10 marka Exp $ */ +/* $Id: cname_5.h,v 1.26 2007/06/19 23:47:17 tbox Exp $ */ #ifndef GENERIC_CNAME_5_H #define GENERIC_CNAME_5_H 1 diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c index c0bb348..957f038 100644 --- a/lib/dns/rdata/generic/dlv_32769.c +++ b/lib/dns/rdata/generic/dlv_32769.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlv_32769.c,v 1.2.2.5 2007/08/28 07:20:06 tbox Exp $ */ +/* $Id: dlv_32769.c,v 1.6 2007/06/18 23:47:43 tbox Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ diff --git a/lib/dns/rdata/generic/dlv_32769.h b/lib/dns/rdata/generic/dlv_32769.h index bd03c73..2313c57 100644 --- a/lib/dns/rdata/generic/dlv_32769.h +++ b/lib/dns/rdata/generic/dlv_32769.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlv_32769.h,v 1.2.2.2 2006/02/19 06:50:47 marka Exp $ */ +/* $Id: dlv_32769.h,v 1.5 2007/06/19 23:47:17 tbox Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ #ifndef GENERIC_DLV_32769_H diff --git a/lib/dns/rdata/generic/dname_39.c b/lib/dns/rdata/generic/dname_39.c index ed3133c..c399f1e 100644 --- a/lib/dns/rdata/generic/dname_39.c +++ b/lib/dns/rdata/generic/dname_39.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dname_39.c,v 1.36 2004/03/05 05:10:10 marka Exp $ */ +/* $Id: dname_39.c,v 1.38 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 16:52:38 PST 2000 by explorer */ diff --git a/lib/dns/rdata/generic/dname_39.h b/lib/dns/rdata/generic/dname_39.h index 93ec709..f8aca27 100644 --- a/lib/dns/rdata/generic/dname_39.h +++ b/lib/dns/rdata/generic/dname_39.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_DNAME_39_H #define GENERIC_DNAME_39_H 1 -/* $Id: dname_39.h,v 1.17.18.2 2005/04/29 00:16:31 marka Exp $ */ +/* $Id: dname_39.h,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief per RFC2672 */ diff --git a/lib/dns/rdata/generic/dnskey_48.c b/lib/dns/rdata/generic/dnskey_48.c index 5a4e453..2e11cba 100644 --- a/lib/dns/rdata/generic/dnskey_48.c +++ b/lib/dns/rdata/generic/dnskey_48.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnskey_48.c,v 1.4.20.2 2005/04/29 00:16:31 marka Exp $ */ +/* $Id: dnskey_48.c,v 1.8 2007/06/19 23:47:17 tbox Exp $ */ /* * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. diff --git a/lib/dns/rdata/generic/dnskey_48.h b/lib/dns/rdata/generic/dnskey_48.h index 9b3d262..ce88cd1 100644 --- a/lib/dns/rdata/generic/dnskey_48.h +++ b/lib/dns/rdata/generic/dnskey_48.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_DNSKEY_48_H #define GENERIC_DNSKEY_48_H 1 -/* $Id: dnskey_48.h,v 1.3.20.2 2005/04/29 00:16:32 marka Exp $ */ +/* $Id: dnskey_48.h,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief per RFC2535 */ diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c index 212a56f..08e5d5f 100644 --- a/lib/dns/rdata/generic/ds_43.c +++ b/lib/dns/rdata/generic/ds_43.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds_43.c,v 1.7.18.5 2007/08/28 07:20:06 tbox Exp $ */ +/* $Id: ds_43.c,v 1.12 2007/06/18 23:47:43 tbox Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ diff --git a/lib/dns/rdata/generic/ds_43.h b/lib/dns/rdata/generic/ds_43.h index dae7bef..3a409a1 100644 --- a/lib/dns/rdata/generic/ds_43.h +++ b/lib/dns/rdata/generic/ds_43.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds_43.h,v 1.3.20.2 2005/04/29 00:16:32 marka Exp $ */ +/* $Id: ds_43.h,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ #ifndef GENERIC_DS_43_H #define GENERIC_DS_43_H 1 diff --git a/lib/dns/rdata/generic/gpos_27.c b/lib/dns/rdata/generic/gpos_27.c index 9b37905..18effb5 100644 --- a/lib/dns/rdata/generic/gpos_27.c +++ b/lib/dns/rdata/generic/gpos_27.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gpos_27.c,v 1.37.18.2 2005/04/29 00:16:32 marka Exp $ */ +/* $Id: gpos_27.c,v 1.41 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 16:48:45 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/gpos_27.h b/lib/dns/rdata/generic/gpos_27.h index 4949bde..f5df4fa 100644 --- a/lib/dns/rdata/generic/gpos_27.h +++ b/lib/dns/rdata/generic/gpos_27.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_GPOS_27_H #define GENERIC_GPOS_27_H 1 -/* $Id: gpos_27.h,v 1.13.18.2 2005/04/29 00:16:32 marka Exp $ */ +/* $Id: gpos_27.h,v 1.17 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief per RFC1712 */ diff --git a/lib/dns/rdata/generic/hinfo_13.c b/lib/dns/rdata/generic/hinfo_13.c index 70c433c..5321357 100644 --- a/lib/dns/rdata/generic/hinfo_13.c +++ b/lib/dns/rdata/generic/hinfo_13.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hinfo_13.c,v 1.42 2004/03/05 05:10:11 marka Exp $ */ +/* $Id: hinfo_13.c,v 1.44 2007/06/19 23:47:17 tbox Exp $ */ /* * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. diff --git a/lib/dns/rdata/generic/hinfo_13.h b/lib/dns/rdata/generic/hinfo_13.h index e542c48..66766df 100644 --- a/lib/dns/rdata/generic/hinfo_13.h +++ b/lib/dns/rdata/generic/hinfo_13.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_HINFO_13_H #define GENERIC_HINFO_13_H 1 -/* $Id: hinfo_13.h,v 1.23 2004/03/05 05:10:12 marka Exp $ */ +/* $Id: hinfo_13.h,v 1.25 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_hinfo { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/ipseckey_45.c b/lib/dns/rdata/generic/ipseckey_45.c index 3c3736e..bc2b4e8 100644 --- a/lib/dns/rdata/generic/ipseckey_45.c +++ b/lib/dns/rdata/generic/ipseckey_45.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ipseckey_45.c,v 1.2.2.1 2005/07/07 03:17:36 marka Exp $ */ +/* $Id: ipseckey_45.c,v 1.4.332.2 2009/01/18 23:47:41 tbox Exp $ */ #ifndef RDATA_GENERIC_IPSECKEY_45_C #define RDATA_GENERIC_IPSECKEY_45_C @@ -131,15 +131,15 @@ totext_ipseckey(ARGS_TOTEXT) { dns_name_init(&name, NULL); dns_name_init(&prefix, NULL); - + if (rdata->data[1] > 3U) return (ISC_R_NOTIMPLEMENTED); - if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) - RETERR(str_totext("( ", target)); + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext("( ", target)); /* - * Precendence. + * Precedence. */ dns_rdata_toregion(rdata, ®ion); num = uint8_fromregion(®ion); @@ -198,14 +198,14 @@ totext_ipseckey(ARGS_TOTEXT) { tctx->linebreak, target)); } - if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) - RETERR(str_totext(" )", target)); + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(" )", target)); return (ISC_R_SUCCESS); } static inline isc_result_t fromwire_ipseckey(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; isc_region_t region; REQUIRE(type == 45); @@ -215,7 +215,7 @@ fromwire_ipseckey(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&name, NULL); + dns_name_init(&name, NULL); isc_buffer_activeregion(source, ®ion); if (region.length < 3) diff --git a/lib/dns/rdata/generic/ipseckey_45.h b/lib/dns/rdata/generic/ipseckey_45.h index b766fa0..2a6201f 100644 --- a/lib/dns/rdata/generic/ipseckey_45.h +++ b/lib/dns/rdata/generic/ipseckey_45.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ipseckey_45.h,v 1.2.2.1 2005/07/07 03:17:36 marka Exp $ */ +/* $Id: ipseckey_45.h,v 1.4 2007/06/19 23:47:17 tbox Exp $ */ #ifndef GENERIC_IPSECKEY_45_H #define GENERIC_IPSECKEY_45_H 1 diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c index 1813759..d7333d1 100644 --- a/lib/dns/rdata/generic/isdn_20.c +++ b/lib/dns/rdata/generic/isdn_20.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: isdn_20.c,v 1.34.18.2 2005/04/29 00:16:33 marka Exp $ */ +/* $Id: isdn_20.c,v 1.38 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 16:53:11 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/isdn_20.h b/lib/dns/rdata/generic/isdn_20.h index 6a51317..a1f65ca 100644 --- a/lib/dns/rdata/generic/isdn_20.h +++ b/lib/dns/rdata/generic/isdn_20.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_ISDN_20_H #define GENERIC_ISDN_20_H 1 -/* $Id: isdn_20.h,v 1.14.18.2 2005/04/29 00:16:33 marka Exp $ */ +/* $Id: isdn_20.h,v 1.18 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1183 */ diff --git a/lib/dns/rdata/generic/key_25.c b/lib/dns/rdata/generic/key_25.c index 24dc10f..9acfe95 100644 --- a/lib/dns/rdata/generic/key_25.c +++ b/lib/dns/rdata/generic/key_25.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: key_25.c,v 1.47.18.2 2005/04/29 00:16:33 marka Exp $ */ +/* $Id: key_25.c,v 1.51 2007/06/19 23:47:17 tbox Exp $ */ /* * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. diff --git a/lib/dns/rdata/generic/key_25.h b/lib/dns/rdata/generic/key_25.h index 03400db..bcf9cb6 100644 --- a/lib/dns/rdata/generic/key_25.h +++ b/lib/dns/rdata/generic/key_25.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_KEY_25_H #define GENERIC_KEY_25_H 1 -/* $Id: key_25.h,v 1.15.18.2 2005/04/29 00:16:33 marka Exp $ */ +/* $Id: key_25.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2535 */ diff --git a/lib/dns/rdata/generic/loc_29.c b/lib/dns/rdata/generic/loc_29.c index c93ac90..a5d7f72 100644 --- a/lib/dns/rdata/generic/loc_29.c +++ b/lib/dns/rdata/generic/loc_29.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: loc_29.c,v 1.41.18.2 2005/04/29 00:16:34 marka Exp $ */ +/* $Id: loc_29.c,v 1.45.332.4 2009/02/17 05:54:12 marka Exp $ */ /* Reviewed: Wed Mar 15 18:13:09 PST 2000 by explorer */ @@ -482,16 +482,19 @@ totext_loc(ARGS_TOTEXT) { /* version = sr.base[0]; */ size = sr.base[1]; + INSIST((size&0x0f) < 10 && (size>>4) < 10); if ((size&0x0f)> 1) sprintf(sbuf, "%lum", (size>>4) * poweroften[(size&0x0f)-2]); else sprintf(sbuf, "0.%02lum", (size>>4) * poweroften[(size&0x0f)]); hp = sr.base[2]; + INSIST((hp&0x0f) < 10 && (hp>>4) < 10); if ((hp&0x0f)> 1) sprintf(hbuf, "%lum", (hp>>4) * poweroften[(hp&0x0f)-2]); else sprintf(hbuf, "0.%02lum", (hp>>4) * poweroften[(hp&0x0f)]); vp = sr.base[3]; + INSIST((vp&0x0f) < 10 && (vp>>4) < 10); if ((vp&0x0f)> 1) sprintf(vbuf, "%lum", (vp>>4) * poweroften[(vp&0x0f)-2]); else @@ -514,6 +517,7 @@ totext_loc(ARGS_TOTEXT) { m1 = (int)(latitude % 60); latitude /= 60; d1 = (int)latitude; + INSIST(latitude <= 90U); longitude = uint32_fromregion(&sr); isc_region_consume(&sr, 4); @@ -531,6 +535,7 @@ totext_loc(ARGS_TOTEXT) { m2 = (int)(longitude % 60); longitude /= 60; d2 = (int)longitude; + INSIST(longitude <= 180U); altitude = uint32_fromregion(&sr); isc_region_consume(&sr, 4); @@ -616,7 +621,7 @@ fromwire_loc(ARGS_FROMWIRE) { return (ISC_R_RANGE); /* - * Altitiude. + * Altitude. * All values possible. */ diff --git a/lib/dns/rdata/generic/loc_29.h b/lib/dns/rdata/generic/loc_29.h index d8eae16..f053c60 100644 --- a/lib/dns/rdata/generic/loc_29.h +++ b/lib/dns/rdata/generic/loc_29.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_LOC_29_H #define GENERIC_LOC_29_H 1 -/* $Id: loc_29.h,v 1.15.18.2 2005/04/29 00:16:34 marka Exp $ */ +/* $Id: loc_29.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1876 */ diff --git a/lib/dns/rdata/generic/mb_7.c b/lib/dns/rdata/generic/mb_7.c index 94c622d..fc3a7b6 100644 --- a/lib/dns/rdata/generic/mb_7.c +++ b/lib/dns/rdata/generic/mb_7.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mb_7.c,v 1.43 2004/03/05 05:10:13 marka Exp $ */ +/* $Id: mb_7.c,v 1.45 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 17:31:26 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/mb_7.h b/lib/dns/rdata/generic/mb_7.h index f6a8b35..b427ee9 100644 --- a/lib/dns/rdata/generic/mb_7.h +++ b/lib/dns/rdata/generic/mb_7.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MB_7_H #define GENERIC_MB_7_H 1 -/* $Id: mb_7.h,v 1.23.18.2 2005/04/29 00:16:34 marka Exp $ */ +/* $Id: mb_7.h,v 1.27 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_mb { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/md_3.c b/lib/dns/rdata/generic/md_3.c index 75e4970..0f8560f 100644 --- a/lib/dns/rdata/generic/md_3.c +++ b/lib/dns/rdata/generic/md_3.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: md_3.c,v 1.45 2004/03/05 05:10:13 marka Exp $ */ +/* $Id: md_3.c,v 1.47 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 17:48:20 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/md_3.h b/lib/dns/rdata/generic/md_3.h index 578ce66..ba70d18 100644 --- a/lib/dns/rdata/generic/md_3.h +++ b/lib/dns/rdata/generic/md_3.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MD_3_H #define GENERIC_MD_3_H 1 -/* $Id: md_3.h,v 1.24.18.2 2005/04/29 00:16:35 marka Exp $ */ +/* $Id: md_3.h,v 1.28 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_md { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/mf_4.c b/lib/dns/rdata/generic/mf_4.c index 362d300..dffcec2 100644 --- a/lib/dns/rdata/generic/mf_4.c +++ b/lib/dns/rdata/generic/mf_4.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mf_4.c,v 1.43 2004/03/05 05:10:14 marka Exp $ */ +/* $Id: mf_4.c,v 1.45 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 17:47:33 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/mf_4.h b/lib/dns/rdata/generic/mf_4.h index 2be0eec..32d2493 100644 --- a/lib/dns/rdata/generic/mf_4.h +++ b/lib/dns/rdata/generic/mf_4.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MF_4_H #define GENERIC_MF_4_H 1 -/* $Id: mf_4.h,v 1.22.18.2 2005/04/29 00:16:35 marka Exp $ */ +/* $Id: mf_4.h,v 1.26 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_mf { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/mg_8.c b/lib/dns/rdata/generic/mg_8.c index 602d820..e4dca1d 100644 --- a/lib/dns/rdata/generic/mg_8.c +++ b/lib/dns/rdata/generic/mg_8.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mg_8.c,v 1.41 2004/03/05 05:10:14 marka Exp $ */ +/* $Id: mg_8.c,v 1.43 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 17:49:21 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/mg_8.h b/lib/dns/rdata/generic/mg_8.h index 5679c17..8fa143a 100644 --- a/lib/dns/rdata/generic/mg_8.h +++ b/lib/dns/rdata/generic/mg_8.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MG_8_H #define GENERIC_MG_8_H 1 -/* $Id: mg_8.h,v 1.22.18.2 2005/04/29 00:16:35 marka Exp $ */ +/* $Id: mg_8.h,v 1.26 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_mg { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/minfo_14.c b/lib/dns/rdata/generic/minfo_14.c index b757480..6645bbc 100644 --- a/lib/dns/rdata/generic/minfo_14.c +++ b/lib/dns/rdata/generic/minfo_14.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: minfo_14.c,v 1.43 2004/03/05 05:10:14 marka Exp $ */ +/* $Id: minfo_14.c,v 1.45 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 17:45:32 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/minfo_14.h b/lib/dns/rdata/generic/minfo_14.h index 754fe20..76195c5 100644 --- a/lib/dns/rdata/generic/minfo_14.h +++ b/lib/dns/rdata/generic/minfo_14.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MINFO_14_H #define GENERIC_MINFO_14_H 1 -/* $Id: minfo_14.h,v 1.23.18.2 2005/04/29 00:16:35 marka Exp $ */ +/* $Id: minfo_14.h,v 1.27 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_minfo { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/mr_9.c b/lib/dns/rdata/generic/mr_9.c index ab4c6e0..289d739 100644 --- a/lib/dns/rdata/generic/mr_9.c +++ b/lib/dns/rdata/generic/mr_9.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mr_9.c,v 1.40 2004/03/05 05:10:15 marka Exp $ */ +/* $Id: mr_9.c,v 1.42 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 21:30:35 EST 2000 by tale */ diff --git a/lib/dns/rdata/generic/mr_9.h b/lib/dns/rdata/generic/mr_9.h index e255d70..3d81bdd 100644 --- a/lib/dns/rdata/generic/mr_9.h +++ b/lib/dns/rdata/generic/mr_9.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MR_9_H #define GENERIC_MR_9_H 1 -/* $Id: mr_9.h,v 1.22.18.2 2005/04/29 00:16:36 marka Exp $ */ +/* $Id: mr_9.h,v 1.26 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_mr { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/mx_15.c b/lib/dns/rdata/generic/mx_15.c index fd77ec8..086c043 100644 --- a/lib/dns/rdata/generic/mx_15.c +++ b/lib/dns/rdata/generic/mx_15.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mx_15.c,v 1.52.18.2 2005/05/20 01:10:11 marka Exp $ */ +/* $Id: mx_15.c,v 1.56 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 18:05:46 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/mx_15.h b/lib/dns/rdata/generic/mx_15.h index 4d81b90..25d5ac5 100644 --- a/lib/dns/rdata/generic/mx_15.h +++ b/lib/dns/rdata/generic/mx_15.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_MX_15_H #define GENERIC_MX_15_H 1 -/* $Id: mx_15.h,v 1.25.18.2 2005/04/29 00:16:36 marka Exp $ */ +/* $Id: mx_15.h,v 1.29 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_mx { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/ns_2.c b/lib/dns/rdata/generic/ns_2.c index 2379433..9a2ee8c 100644 --- a/lib/dns/rdata/generic/ns_2.c +++ b/lib/dns/rdata/generic/ns_2.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ns_2.c,v 1.44 2004/03/05 05:10:15 marka Exp $ */ +/* $Id: ns_2.c,v 1.46 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Wed Mar 15 18:15:00 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/ns_2.h b/lib/dns/rdata/generic/ns_2.h index ec8e771..546e71a 100644 --- a/lib/dns/rdata/generic/ns_2.h +++ b/lib/dns/rdata/generic/ns_2.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_NS_2_H #define GENERIC_NS_2_H 1 -/* $Id: ns_2.h,v 1.23.18.2 2005/04/29 00:16:37 marka Exp $ */ +/* $Id: ns_2.h,v 1.27 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_ns { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/nsec3_50.c b/lib/dns/rdata/generic/nsec3_50.c new file mode 100644 index 0000000..c5f0acb --- /dev/null +++ b/lib/dns/rdata/generic/nsec3_50.c @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2008, 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: nsec3_50.c,v 1.4.48.2 2009/01/18 23:47:41 tbox Exp $ */ + +/* + * Copyright (C) 2004 Nominet, Ltd. + * + * 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 NOMINET 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. + */ + +/* RFC 5155 */ + +#ifndef RDATA_GENERIC_NSEC3_50_C +#define RDATA_GENERIC_NSEC3_50_C + +#include <isc/iterated_hash.h> +#include <isc/base32.h> + +#define RRTYPE_NSEC3_ATTRIBUTES DNS_RDATATYPEATTR_DNSSEC + +static inline isc_result_t +fromtext_nsec3(ARGS_FROMTEXT) { + isc_token_t token; + unsigned char bm[8*1024]; /* 64k bits */ + dns_rdatatype_t covered; + int octet; + int window; + unsigned int flags; + unsigned char hashalg; + isc_buffer_t b; + + REQUIRE(type == 50); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(callbacks); + UNUSED(origin); + UNUSED(options); + + /* Hash. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion)); + RETERR(uint8_tobuffer(hashalg, target)); + + /* Flags. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + flags = token.value.as_ulong; + if (flags > 255U) + RETTOK(ISC_R_RANGE); + RETERR(uint8_tobuffer(flags, target)); + + /* Iterations. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + if (token.value.as_ulong > 0xffffU) + RETTOK(ISC_R_RANGE); + RETERR(uint16_tobuffer(token.value.as_ulong, target)); + + /* salt */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + if (token.value.as_textregion.length > (255*2)) + RETTOK(DNS_R_TEXTTOOLONG); + if (strcmp(DNS_AS_STR(token), "-") == 0) { + RETERR(uint8_tobuffer(0, target)); + } else { + RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target)); + RETERR(isc_hex_decodestring(DNS_AS_STR(token), target)); + } + + /* + * Next hash a single base32hex word. + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + isc_buffer_init(&b, bm, sizeof(bm)); + RETTOK(isc_base32hex_decodestring(DNS_AS_STR(token), &b)); + if (isc_buffer_usedlength(&b) > 0xffU) + RETTOK(ISC_R_RANGE); + RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target)); + RETERR(mem_tobuffer(target, &bm, isc_buffer_usedlength(&b))); + + memset(bm, 0, sizeof(bm)); + do { + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_string, ISC_TRUE)); + if (token.type != isc_tokentype_string) + break; + RETTOK(dns_rdatatype_fromtext(&covered, + &token.value.as_textregion)); + bm[covered/8] |= (0x80>>(covered%8)); + } while (1); + isc_lex_ungettoken(lexer, &token); + for (window = 0; window < 256 ; window++) { + /* + * Find if we have a type in this window. + */ + for (octet = 31; octet >= 0; octet--) + if (bm[window * 32 + octet] != 0) + break; + if (octet < 0) + continue; + RETERR(uint8_tobuffer(window, target)); + RETERR(uint8_tobuffer(octet + 1, target)); + RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1)); + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +totext_nsec3(ARGS_TOTEXT) { + isc_region_t sr; + unsigned int i, j, k; + unsigned int window, len; + unsigned char hash; + unsigned char flags; + char buf[sizeof("65535 ")]; + isc_uint32_t iterations; + + REQUIRE(rdata->type == 50); + REQUIRE(rdata->length != 0); + + UNUSED(tctx); + + dns_rdata_toregion(rdata, &sr); + + hash = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + flags = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + iterations = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + + sprintf(buf, "%u ", hash); + RETERR(str_totext(buf, target)); + + sprintf(buf, "%u ", flags); + RETERR(str_totext(buf, target)); + + sprintf(buf, "%u ", iterations); + RETERR(str_totext(buf, target)); + + j = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + INSIST(j <= sr.length); + + if (j != 0) { + i = sr.length; + sr.length = j; + RETERR(isc_hex_totext(&sr, 1, "", target)); + sr.length = i - j; + RETERR(str_totext(" ", target)); + } else + RETERR(str_totext("- ", target)); + + j = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + INSIST(j <= sr.length); + + i = sr.length; + sr.length = j; + RETERR(isc_base32hex_totext(&sr, 1, "", target)); + sr.length = i - j; + + for (i = 0; i < sr.length; i += len) { + INSIST(i + 2 <= sr.length); + window = sr.base[i]; + len = sr.base[i + 1]; + INSIST(len > 0 && len <= 32); + i += 2; + INSIST(i + len <= sr.length); + for (j = 0; j < len; j++) { + dns_rdatatype_t t; + if (sr.base[i + j] == 0) + continue; + for (k = 0; k < 8; k++) { + if ((sr.base[i + j] & (0x80 >> k)) == 0) + continue; + t = window * 256 + j * 8 + k; + RETERR(str_totext(" ", target)); + if (dns_rdatatype_isknown(t)) { + RETERR(dns_rdatatype_totext(t, target)); + } else { + char buf[sizeof("TYPE65535")]; + sprintf(buf, "TYPE%u", t); + RETERR(str_totext(buf, target)); + } + } + } + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_nsec3(ARGS_FROMWIRE) { + isc_region_t sr, rr; + unsigned int window, lastwindow = 0; + unsigned int len; + unsigned int saltlen, hashlen; + isc_boolean_t first = ISC_TRUE; + unsigned int i; + + REQUIRE(type == 50); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(options); + UNUSED(dctx); + + isc_buffer_activeregion(source, &sr); + rr = sr; + + /* hash(1), flags(1), iteration(2), saltlen(1) */ + if (sr.length < 5U) + RETERR(DNS_R_FORMERR); + saltlen = sr.base[4]; + isc_region_consume(&sr, 5); + + if (sr.length < saltlen) + RETERR(DNS_R_FORMERR); + isc_region_consume(&sr, saltlen); + + if (sr.length < 1U) + RETERR(DNS_R_FORMERR); + hashlen = sr.base[0]; + isc_region_consume(&sr, 1); + + if (sr.length < hashlen) + RETERR(DNS_R_FORMERR); + isc_region_consume(&sr, hashlen); + + for (i = 0; i < sr.length; i += len) { + /* + * Check for overflow. + */ + if (i + 2 > sr.length) + RETERR(DNS_R_FORMERR); + window = sr.base[i]; + len = sr.base[i + 1]; + i += 2; + /* + * Check that bitmap windows are in the correct order. + */ + if (!first && window <= lastwindow) + RETERR(DNS_R_FORMERR); + /* + * Check for legal lengths. + */ + if (len < 1 || len > 32) + RETERR(DNS_R_FORMERR); + /* + * Check for overflow. + */ + if (i + len > sr.length) + RETERR(DNS_R_FORMERR); + /* + * The last octet of the bitmap must be non zero. + */ + if (sr.base[i + len - 1] == 0) + RETERR(DNS_R_FORMERR); + lastwindow = window; + first = ISC_FALSE; + } + if (i != sr.length) + return (DNS_R_EXTRADATA); + RETERR(mem_tobuffer(target, rr.base, rr.length)); + isc_buffer_forward(source, rr.length); + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +towire_nsec3(ARGS_TOWIRE) { + isc_region_t sr; + + REQUIRE(rdata->type == 50); + REQUIRE(rdata->length != 0); + + UNUSED(cctx); + + dns_rdata_toregion(rdata, &sr); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline int +compare_nsec3(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 50); + 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_nsec3(ARGS_FROMSTRUCT) { + dns_rdata_nsec3_t *nsec3 = source; + unsigned int i, len, window, lastwindow = 0; + isc_boolean_t first = ISC_TRUE; + + REQUIRE(type == 50); + REQUIRE(source != NULL); + REQUIRE(nsec3->common.rdtype == type); + REQUIRE(nsec3->common.rdclass == rdclass); + REQUIRE(nsec3->typebits != NULL || nsec3->len == 0); + REQUIRE(nsec3->hash == dns_hash_sha1); + + UNUSED(type); + UNUSED(rdclass); + + RETERR(uint8_tobuffer(nsec3->hash, target)); + RETERR(uint8_tobuffer(nsec3->flags, target)); + RETERR(uint16_tobuffer(nsec3->iterations, target)); + RETERR(uint8_tobuffer(nsec3->salt_length, target)); + RETERR(mem_tobuffer(target, nsec3->salt, nsec3->salt_length)); + RETERR(uint8_tobuffer(nsec3->next_length, target)); + RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length)); + + /* + * Perform sanity check. + */ + for (i = 0; i < nsec3->len ; i += len) { + INSIST(i + 2 <= nsec3->len); + window = nsec3->typebits[i]; + len = nsec3->typebits[i+1]; + i += 2; + INSIST(first || window > lastwindow); + INSIST(len > 0 && len <= 32); + INSIST(i + len <= nsec3->len); + INSIST(nsec3->typebits[i + len - 1] != 0); + lastwindow = window; + first = ISC_FALSE; + } + return (mem_tobuffer(target, nsec3->typebits, nsec3->len)); +} + +static inline isc_result_t +tostruct_nsec3(ARGS_TOSTRUCT) { + isc_region_t region; + dns_rdata_nsec3_t *nsec3 = target; + + REQUIRE(rdata->type == 50); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + nsec3->common.rdclass = rdata->rdclass; + nsec3->common.rdtype = rdata->type; + ISC_LINK_INIT(&nsec3->common, link); + + region.base = rdata->data; + region.length = rdata->length; + nsec3->hash = uint8_consume_fromregion(®ion); + nsec3->flags = uint8_consume_fromregion(®ion); + nsec3->iterations = uint16_consume_fromregion(®ion); + + nsec3->salt_length = uint8_consume_fromregion(®ion); + nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length); + if (nsec3->salt == NULL) + return (ISC_R_NOMEMORY); + isc_region_consume(®ion, nsec3->salt_length); + + nsec3->next_length = uint8_consume_fromregion(®ion); + nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length); + if (nsec3->next == NULL) + goto cleanup; + isc_region_consume(®ion, nsec3->next_length); + + nsec3->len = region.length; + nsec3->typebits = mem_maybedup(mctx, region.base, region.length); + if (nsec3->typebits == NULL) + goto cleanup; + + nsec3->mctx = mctx; + return (ISC_R_SUCCESS); + + cleanup: + if (nsec3->next != NULL) + isc_mem_free(mctx, nsec3->next); + isc_mem_free(mctx, nsec3->salt); + return (ISC_R_NOMEMORY); +} + +static inline void +freestruct_nsec3(ARGS_FREESTRUCT) { + dns_rdata_nsec3_t *nsec3 = source; + + REQUIRE(source != NULL); + REQUIRE(nsec3->common.rdtype == 50); + + if (nsec3->mctx == NULL) + return; + + if (nsec3->salt != NULL) + isc_mem_free(nsec3->mctx, nsec3->salt); + if (nsec3->next != NULL) + isc_mem_free(nsec3->mctx, nsec3->next); + if (nsec3->typebits != NULL) + isc_mem_free(nsec3->mctx, nsec3->typebits); + nsec3->mctx = NULL; +} + +static inline isc_result_t +additionaldata_nsec3(ARGS_ADDLDATA) { + REQUIRE(rdata->type == 50); + + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_nsec3(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == 50); + + dns_rdata_toregion(rdata, &r); + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_nsec3(ARGS_CHECKOWNER) { + + REQUIRE(type == 50); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_nsec3(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == 50); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +#endif /* RDATA_GENERIC_NSEC3_50_C */ diff --git a/lib/dns/rdata/generic/nsec3_50.h b/lib/dns/rdata/generic/nsec3_50.h new file mode 100644 index 0000000..658dd9d --- /dev/null +++ b/lib/dns/rdata/generic/nsec3_50.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008 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_NSEC3_50_H +#define GENERIC_NSEC3_50_H 1 + +/* $Id: nsec3_50.h,v 1.4 2008/09/25 04:02:39 tbox Exp $ */ + +/*! + * \brief Per RFC 5155 */ + +#include <isc/iterated_hash.h> + +typedef struct dns_rdata_nsec3 { + dns_rdatacommon_t common; + isc_mem_t *mctx; + dns_hash_t hash; + unsigned char flags; + dns_iterations_t iterations; + unsigned char salt_length; + unsigned char next_length; + isc_uint16_t len; + unsigned char *salt; + unsigned char *next; + unsigned char *typebits; +} dns_rdata_nsec3_t; + +/* + * The corresponding NSEC3 interval is OPTOUT indicating possible + * insecure delegations. + */ +#define DNS_NSEC3FLAG_OPTOUT 0x01U + +/*% + * Non-standard, NSEC3PARAM only. + * + * Create a corresponding NSEC3 chain. + * Once the NSEC3 chain is complete this flag will be removed to signal + * that there is a complete chain. + * + * This flag is automatically set when a NSEC3PARAM record is added to + * the zone via UPDATE. + * + * NSEC3PARAM records with this flag set are supposed to be ignored by + * RFC 5155 compliant nameservers. + */ +#define DNS_NSEC3FLAG_CREATE 0x80U + +/*% + * Non-standard, NSEC3PARAM only. + * + * The corresponding NSEC3 set is to be removed once the NSEC chain + * has been generated. + * + * This flag is automatically set when the last active NSEC3PARAM record + * is removed from the zone via UPDATE. + * + * NSEC3PARAM records with this flag set are supposed to be ignored by + * RFC 5155 compliant nameservers. + */ +#define DNS_NSEC3FLAG_REMOVE 0x40U + +/*% + * Non-standard, NSEC3PARAM only. + * + * Used to identify NSEC3PARAM records added in this UPDATE request. + */ +#define DNS_NSEC3FLAG_UPDATE 0x20U + +/*% + * Non-standard, NSEC3PARAM only. + * + * Prevent the creation of a NSEC chain before the last NSEC3 chain + * is removed. This will normally only be set when the zone is + * transitioning from secure with NSEC3 chains to insecure. + */ +#define DNS_NSEC3FLAG_NONSEC 0x10U + +#endif /* GENERIC_NSEC3_50_H */ diff --git a/lib/dns/rdata/generic/nsec3param_51.c b/lib/dns/rdata/generic/nsec3param_51.c new file mode 100644 index 0000000..607ce6a --- /dev/null +++ b/lib/dns/rdata/generic/nsec3param_51.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2008, 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: nsec3param_51.c,v 1.4.48.2 2009/01/18 23:47:41 tbox Exp $ */ + +/* + * Copyright (C) 2004 Nominet, Ltd. + * + * 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 NOMINET 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. + */ + +/* RFC 5155 */ + +#ifndef RDATA_GENERIC_NSEC3PARAM_51_C +#define RDATA_GENERIC_NSEC3PARAM_51_C + +#include <isc/iterated_hash.h> +#include <isc/base32.h> + +#define RRTYPE_NSEC3PARAM_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC) + +static inline isc_result_t +fromtext_nsec3param(ARGS_FROMTEXT) { + isc_token_t token; + unsigned int flags = 0; + unsigned char hashalg; + + REQUIRE(type == 51); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(callbacks); + UNUSED(origin); + UNUSED(options); + + /* Hash. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion)); + RETERR(uint8_tobuffer(hashalg, target)); + + /* Flags. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + flags = token.value.as_ulong; + if (flags > 255U) + RETTOK(ISC_R_RANGE); + RETERR(uint8_tobuffer(flags, target)); + + /* Iterations. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + if (token.value.as_ulong > 0xffffU) + RETTOK(ISC_R_RANGE); + RETERR(uint16_tobuffer(token.value.as_ulong, target)); + + /* Salt. */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + if (token.value.as_textregion.length > (255*2)) + RETTOK(DNS_R_TEXTTOOLONG); + if (strcmp(DNS_AS_STR(token), "-") == 0) { + RETERR(uint8_tobuffer(0, target)); + } else { + RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target)); + RETERR(isc_hex_decodestring(DNS_AS_STR(token), target)); + } + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +totext_nsec3param(ARGS_TOTEXT) { + isc_region_t sr; + unsigned int i, j; + unsigned char hash; + unsigned char flags; + char buf[sizeof("65535 ")]; + isc_uint32_t iterations; + + REQUIRE(rdata->type == 51); + REQUIRE(rdata->length != 0); + + UNUSED(tctx); + + dns_rdata_toregion(rdata, &sr); + + hash = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + flags = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + iterations = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + + sprintf(buf, "%u ", hash); + RETERR(str_totext(buf, target)); + + sprintf(buf, "%u ", flags); + RETERR(str_totext(buf, target)); + + sprintf(buf, "%u ", iterations); + RETERR(str_totext(buf, target)); + + j = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + INSIST(j <= sr.length); + + if (j != 0) { + i = sr.length; + sr.length = j; + RETERR(isc_hex_totext(&sr, 1, "", target)); + sr.length = i - j; + } else + RETERR(str_totext("-", target)); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_nsec3param(ARGS_FROMWIRE) { + isc_region_t sr, rr; + unsigned int saltlen; + + REQUIRE(type == 51); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(options); + UNUSED(dctx); + + isc_buffer_activeregion(source, &sr); + rr = sr; + + /* hash(1), flags(1), iterations(2), saltlen(1) */ + if (sr.length < 5U) + RETERR(DNS_R_FORMERR); + saltlen = sr.base[4]; + isc_region_consume(&sr, 5); + + if (sr.length < saltlen) + RETERR(DNS_R_FORMERR); + isc_region_consume(&sr, saltlen); + RETERR(mem_tobuffer(target, rr.base, rr.length)); + isc_buffer_forward(source, rr.length); + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +towire_nsec3param(ARGS_TOWIRE) { + isc_region_t sr; + + REQUIRE(rdata->type == 51); + REQUIRE(rdata->length != 0); + + UNUSED(cctx); + + dns_rdata_toregion(rdata, &sr); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline int +compare_nsec3param(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 51); + 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_nsec3param(ARGS_FROMSTRUCT) { + dns_rdata_nsec3param_t *nsec3param = source; + + REQUIRE(type == 51); + REQUIRE(source != NULL); + REQUIRE(nsec3param->common.rdtype == type); + REQUIRE(nsec3param->common.rdclass == rdclass); + + UNUSED(type); + UNUSED(rdclass); + + RETERR(uint8_tobuffer(nsec3param->hash, target)); + RETERR(uint8_tobuffer(nsec3param->flags, target)); + RETERR(uint16_tobuffer(nsec3param->iterations, target)); + RETERR(uint8_tobuffer(nsec3param->salt_length, target)); + RETERR(mem_tobuffer(target, nsec3param->salt, + nsec3param->salt_length)); + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +tostruct_nsec3param(ARGS_TOSTRUCT) { + isc_region_t region; + dns_rdata_nsec3param_t *nsec3param = target; + + REQUIRE(rdata->type == 51); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + nsec3param->common.rdclass = rdata->rdclass; + nsec3param->common.rdtype = rdata->type; + ISC_LINK_INIT(&nsec3param->common, link); + + region.base = rdata->data; + region.length = rdata->length; + nsec3param->hash = uint8_consume_fromregion(®ion); + nsec3param->flags = uint8_consume_fromregion(®ion); + nsec3param->iterations = uint16_consume_fromregion(®ion); + + nsec3param->salt_length = uint8_consume_fromregion(®ion); + nsec3param->salt = mem_maybedup(mctx, region.base, + nsec3param->salt_length); + if (nsec3param->salt == NULL) + return (ISC_R_NOMEMORY); + isc_region_consume(®ion, nsec3param->salt_length); + + nsec3param->mctx = mctx; + return (ISC_R_SUCCESS); +} + +static inline void +freestruct_nsec3param(ARGS_FREESTRUCT) { + dns_rdata_nsec3param_t *nsec3param = source; + + REQUIRE(source != NULL); + REQUIRE(nsec3param->common.rdtype == 51); + + if (nsec3param->mctx == NULL) + return; + + if (nsec3param->salt != NULL) + isc_mem_free(nsec3param->mctx, nsec3param->salt); + nsec3param->mctx = NULL; +} + +static inline isc_result_t +additionaldata_nsec3param(ARGS_ADDLDATA) { + REQUIRE(rdata->type == 51); + + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_nsec3param(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == 51); + + dns_rdata_toregion(rdata, &r); + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_nsec3param(ARGS_CHECKOWNER) { + + REQUIRE(type == 51); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_nsec3param(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == 51); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +#endif /* RDATA_GENERIC_NSEC3PARAM_51_C */ diff --git a/lib/dns/rdata/generic/nsec3param_51.h b/lib/dns/rdata/generic/nsec3param_51.h new file mode 100644 index 0000000..2efd7e6 --- /dev/null +++ b/lib/dns/rdata/generic/nsec3param_51.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 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_NSEC3PARAM_51_H +#define GENERIC_NSEC3PARAM_51_H 1 + +/* $Id: nsec3param_51.h,v 1.4 2008/09/25 04:02:39 tbox Exp $ */ + +/*! + * \brief Per RFC 5155 */ + +#include <isc/iterated_hash.h> + +typedef struct dns_rdata_nsec3param { + dns_rdatacommon_t common; + isc_mem_t *mctx; + dns_hash_t hash; + unsigned char flags; /* DNS_NSEC3FLAG_* */ + dns_iterations_t iterations; + unsigned char salt_length; + unsigned char *salt; +} dns_rdata_nsec3param_t; + +#endif /* GENERIC_NSEC3PARAM_51_H */ diff --git a/lib/dns/rdata/generic/nsec_47.c b/lib/dns/rdata/generic/nsec_47.c index dd39105..7e443d9 100644 --- a/lib/dns/rdata/generic/nsec_47.c +++ b/lib/dns/rdata/generic/nsec_47.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec_47.c,v 1.7.20.2 2008/07/15 23:46:14 tbox Exp $ */ +/* $Id: nsec_47.c,v 1.11 2008/07/15 23:47:21 tbox Exp $ */ /* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/nsec_47.h b/lib/dns/rdata/generic/nsec_47.h index 5c52447..2b3c6b6 100644 --- a/lib/dns/rdata/generic/nsec_47.h +++ b/lib/dns/rdata/generic/nsec_47.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -18,7 +18,7 @@ #ifndef GENERIC_NSEC_47_H #define GENERIC_NSEC_47_H 1 -/* $Id: nsec_47.h,v 1.4.20.4 2008/07/15 23:46:14 tbox Exp $ */ +/* $Id: nsec_47.h,v 1.10 2008/07/15 23:47:21 tbox Exp $ */ /*! * \brief Per RFC 3845 */ diff --git a/lib/dns/rdata/generic/null_10.c b/lib/dns/rdata/generic/null_10.c index a6f8f9f4..00bb542 100644 --- a/lib/dns/rdata/generic/null_10.c +++ b/lib/dns/rdata/generic/null_10.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: null_10.c,v 1.40 2004/03/05 05:10:16 marka Exp $ */ +/* $Id: null_10.c,v 1.42 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 13:57:50 PST 2000 by explorer */ diff --git a/lib/dns/rdata/generic/null_10.h b/lib/dns/rdata/generic/null_10.h index 5afb1ae..ceeb018 100644 --- a/lib/dns/rdata/generic/null_10.h +++ b/lib/dns/rdata/generic/null_10.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_NULL_10_H #define GENERIC_NULL_10_H 1 -/* $Id: null_10.h,v 1.21.18.2 2005/04/29 00:16:37 marka Exp $ */ +/* $Id: null_10.h,v 1.25 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_null { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/nxt_30.c b/lib/dns/rdata/generic/nxt_30.c index b7358e0..7ffb86c 100644 --- a/lib/dns/rdata/generic/nxt_30.c +++ b/lib/dns/rdata/generic/nxt_30.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nxt_30.c,v 1.59.18.2 2005/04/29 00:16:38 marka Exp $ */ +/* $Id: nxt_30.c,v 1.63 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/nxt_30.h b/lib/dns/rdata/generic/nxt_30.h index 3700fb1..e2e8688 100644 --- a/lib/dns/rdata/generic/nxt_30.h +++ b/lib/dns/rdata/generic/nxt_30.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_NXT_30_H #define GENERIC_NXT_30_H 1 -/* $Id: nxt_30.h,v 1.21.18.2 2005/04/29 00:16:38 marka Exp $ */ +/* $Id: nxt_30.h,v 1.25 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief RFC2535 */ diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c index e8f4816..d2cfc2e 100644 --- a/lib/dns/rdata/generic/opt_41.c +++ b/lib/dns/rdata/generic/opt_41.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: opt_41.c,v 1.29.18.2 2005/04/29 00:16:38 marka Exp $ */ +/* $Id: opt_41.c,v 1.33 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */ diff --git a/lib/dns/rdata/generic/opt_41.h b/lib/dns/rdata/generic/opt_41.h index 827936e..d6539cf 100644 --- a/lib/dns/rdata/generic/opt_41.h +++ b/lib/dns/rdata/generic/opt_41.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_OPT_41_H #define GENERIC_OPT_41_H 1 -/* $Id: opt_41.h,v 1.14.18.2 2005/04/29 00:16:38 marka Exp $ */ +/* $Id: opt_41.h,v 1.18 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2671 */ diff --git a/lib/dns/rdata/generic/proforma.c b/lib/dns/rdata/generic/proforma.c index bf8b2fd..879b761 100644 --- a/lib/dns/rdata/generic/proforma.c +++ b/lib/dns/rdata/generic/proforma.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: proforma.c,v 1.34 2004/03/05 05:10:17 marka Exp $ */ +/* $Id: proforma.c,v 1.36 2007/06/19 23:47:17 tbox Exp $ */ #ifndef RDATA_GENERIC_#_#_C #define RDATA_GENERIC_#_#_C diff --git a/lib/dns/rdata/generic/proforma.h b/lib/dns/rdata/generic/proforma.h index 89d1606..e5c420a 100644 --- a/lib/dns/rdata/generic/proforma.h +++ b/lib/dns/rdata/generic/proforma.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_PROFORMA_H #define GENERIC_PROFORMA_H 1 -/* $Id: proforma.h,v 1.19.18.2 2005/04/29 00:16:39 marka Exp $ */ +/* $Id: proforma.h,v 1.23 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_# { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/ptr_12.c b/lib/dns/rdata/generic/ptr_12.c index 16d5706..fbabcbf 100644 --- a/lib/dns/rdata/generic/ptr_12.c +++ b/lib/dns/rdata/generic/ptr_12.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ptr_12.c,v 1.41 2004/03/05 05:10:17 marka Exp $ */ +/* $Id: ptr_12.c,v 1.43 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 14:05:12 PST 2000 by explorer */ diff --git a/lib/dns/rdata/generic/ptr_12.h b/lib/dns/rdata/generic/ptr_12.h index 4eb8fa7..304dcc4 100644 --- a/lib/dns/rdata/generic/ptr_12.h +++ b/lib/dns/rdata/generic/ptr_12.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_PTR_12_H #define GENERIC_PTR_12_H 1 -/* $Id: ptr_12.h,v 1.23.18.2 2005/04/29 00:16:39 marka Exp $ */ +/* $Id: ptr_12.h,v 1.27 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_ptr { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/rp_17.c b/lib/dns/rdata/generic/rp_17.c index b153643..557cb04 100644 --- a/lib/dns/rdata/generic/rp_17.c +++ b/lib/dns/rdata/generic/rp_17.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rp_17.c,v 1.38.18.2 2005/04/29 00:16:39 marka Exp $ */ +/* $Id: rp_17.c,v 1.42 2007/06/19 23:47:17 tbox Exp $ */ /* RFC1183 */ diff --git a/lib/dns/rdata/generic/rp_17.h b/lib/dns/rdata/generic/rp_17.h index 533c7e7..6223038 100644 --- a/lib/dns/rdata/generic/rp_17.h +++ b/lib/dns/rdata/generic/rp_17.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_RP_17_H #define GENERIC_RP_17_H 1 -/* $Id: rp_17.h,v 1.17.18.2 2005/04/29 00:16:39 marka Exp $ */ +/* $Id: rp_17.h,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1183 */ diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c index 6561f28..a9af4bd 100644 --- a/lib/dns/rdata/generic/rrsig_46.c +++ b/lib/dns/rdata/generic/rrsig_46.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rrsig_46.c,v 1.5.18.3 2005/04/29 00:16:39 marka Exp $ */ +/* $Id: rrsig_46.c,v 1.10 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Fri Mar 17 09:05:02 PST 2000 by gson */ diff --git a/lib/dns/rdata/generic/rrsig_46.h b/lib/dns/rdata/generic/rrsig_46.h index b8b35a2..8e8dc4e 100644 --- a/lib/dns/rdata/generic/rrsig_46.h +++ b/lib/dns/rdata/generic/rrsig_46.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_DNSSIG_46_H #define GENERIC_DNSSIG_46_H 1 -/* $Id: rrsig_46.h,v 1.3.20.2 2005/04/29 00:16:39 marka Exp $ */ +/* $Id: rrsig_46.h,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2535 */ diff --git a/lib/dns/rdata/generic/rt_21.c b/lib/dns/rdata/generic/rt_21.c index 6977e98..6444102 100644 --- a/lib/dns/rdata/generic/rt_21.c +++ b/lib/dns/rdata/generic/rt_21.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rt_21.c,v 1.41.18.3 2005/04/27 05:01:52 sra Exp $ */ +/* $Id: rt_21.c,v 1.46 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Thu Mar 16 15:02:31 PST 2000 by brister */ diff --git a/lib/dns/rdata/generic/rt_21.h b/lib/dns/rdata/generic/rt_21.h index b8ec969..2c0e9fc 100644 --- a/lib/dns/rdata/generic/rt_21.h +++ b/lib/dns/rdata/generic/rt_21.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_RT_21_H #define GENERIC_RT_21_H 1 -/* $Id: rt_21.h,v 1.17.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: rt_21.h,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1183 */ diff --git a/lib/dns/rdata/generic/sig_24.c b/lib/dns/rdata/generic/sig_24.c index 9842953..e79e1e4 100644 --- a/lib/dns/rdata/generic/sig_24.c +++ b/lib/dns/rdata/generic/sig_24.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sig_24.c,v 1.62.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: sig_24.c,v 1.66 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Fri Mar 17 09:05:02 PST 2000 by gson */ diff --git a/lib/dns/rdata/generic/sig_24.h b/lib/dns/rdata/generic/sig_24.h index 96ed767..7212d4d 100644 --- a/lib/dns/rdata/generic/sig_24.h +++ b/lib/dns/rdata/generic/sig_24.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_SIG_24_H #define GENERIC_SIG_24_H 1 -/* $Id: sig_24.h,v 1.22.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: sig_24.h,v 1.26 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2535 */ diff --git a/lib/dns/rdata/generic/soa_6.c b/lib/dns/rdata/generic/soa_6.c index 8de678c..921aead 100644 --- a/lib/dns/rdata/generic/soa_6.c +++ b/lib/dns/rdata/generic/soa_6.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa_6.c,v 1.59 2004/03/05 05:10:18 marka Exp $ */ +/* $Id: soa_6.c,v 1.61.332.2 2009/02/16 23:47:15 tbox Exp $ */ /* Reviewed: Thu Mar 16 15:18:32 PST 2000 by explorer */ @@ -101,7 +101,11 @@ totext_soa(ARGS_TOTEXT) { REQUIRE(rdata->length != 0); multiline = ISC_TF((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0); - comment = ISC_TF((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0); + if (multiline) + comment = ISC_TF((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0); + else + comment = ISC_FALSE; + dns_name_init(&mname, NULL); dns_name_init(&rname, NULL); @@ -128,16 +132,13 @@ totext_soa(ARGS_TOTEXT) { RETERR(str_totext(tctx->linebreak, target)); for (i = 0; i < 5; i++) { - char buf[sizeof("2147483647")]; + char buf[sizeof("0123456789 ; ")]; unsigned long num; - unsigned int numlen; num = uint32_fromregion(&dregion); isc_region_consume(&dregion, 4); - numlen = sprintf(buf, "%lu", num); - INSIST(numlen > 0 && numlen < sizeof("2147483647")); + sprintf(buf, comment ? "%-10lu ; " : "%lu", num); RETERR(str_totext(buf, target)); - if (multiline && comment) { - RETERR(str_totext(" ; " + numlen, target)); + if (comment) { RETERR(str_totext(soa_fieldnames[i], target)); /* Print times in week/day/hour/minute/second form */ if (i >= 1) { @@ -147,7 +148,7 @@ totext_soa(ARGS_TOTEXT) { } RETERR(str_totext(tctx->linebreak, target)); } else if (i < 4) { - RETERR(str_totext(tctx->linebreak, target)); + RETERR(str_totext(tctx->linebreak, target)); } } @@ -159,8 +160,8 @@ totext_soa(ARGS_TOTEXT) { static inline isc_result_t fromwire_soa(ARGS_FROMWIRE) { - dns_name_t mname; - dns_name_t rname; + dns_name_t mname; + dns_name_t rname; isc_region_t sregion; isc_region_t tregion; @@ -171,11 +172,11 @@ fromwire_soa(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&mname, NULL); - dns_name_init(&rname, NULL); + dns_name_init(&mname, NULL); + dns_name_init(&rname, NULL); - RETERR(dns_name_fromwire(&mname, source, dctx, options, target)); - RETERR(dns_name_fromwire(&rname, source, dctx, options, target)); + RETERR(dns_name_fromwire(&mname, source, dctx, options, target)); + RETERR(dns_name_fromwire(&rname, source, dctx, options, target)); isc_buffer_activeregion(source, &sregion); isc_buffer_availableregion(target, &tregion); diff --git a/lib/dns/rdata/generic/soa_6.h b/lib/dns/rdata/generic/soa_6.h index 4211786..7443b04 100644 --- a/lib/dns/rdata/generic/soa_6.h +++ b/lib/dns/rdata/generic/soa_6.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_SOA_6_H #define GENERIC_SOA_6_H 1 -/* $Id: soa_6.h,v 1.28.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: soa_6.h,v 1.32 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_soa { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c index b65f580..12e813e 100644 --- a/lib/dns/rdata/generic/spf_99.c +++ b/lib/dns/rdata/generic/spf_99.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: spf_99.c,v 1.1.2.2 2005/07/16 00:40:54 marka Exp $ */ +/* $Id: spf_99.c,v 1.4 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/spf_99.h b/lib/dns/rdata/generic/spf_99.h index afe77ec..be5e978 100644 --- a/lib/dns/rdata/generic/spf_99.h +++ b/lib/dns/rdata/generic/spf_99.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_SPF_99_H #define GENERIC_SPF_99_H 1 -/* $Id: spf_99.h,v 1.1.2.2 2005/07/16 00:40:54 marka Exp $ */ +/* $Id: spf_99.h,v 1.4 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_spf_string { isc_uint8_t length; diff --git a/lib/dns/rdata/generic/sshfp_44.c b/lib/dns/rdata/generic/sshfp_44.c index 64b51c7..570a3b7 100644 --- a/lib/dns/rdata/generic/sshfp_44.c +++ b/lib/dns/rdata/generic/sshfp_44.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sshfp_44.c,v 1.3.18.1 2006/03/10 04:04:32 marka Exp $ */ +/* $Id: sshfp_44.c,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ /* RFC 4255 */ diff --git a/lib/dns/rdata/generic/sshfp_44.h b/lib/dns/rdata/generic/sshfp_44.h index 513eeac..daea74c 100644 --- a/lib/dns/rdata/generic/sshfp_44.h +++ b/lib/dns/rdata/generic/sshfp_44.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sshfp_44.h,v 1.2.18.3 2006/03/10 04:04:32 marka Exp $ */ +/* $Id: sshfp_44.h,v 1.8 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC 4255 */ diff --git a/lib/dns/rdata/generic/tkey_249.c b/lib/dns/rdata/generic/tkey_249.c index cee16ab..2412c85 100644 --- a/lib/dns/rdata/generic/tkey_249.c +++ b/lib/dns/rdata/generic/tkey_249.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tkey_249.c,v 1.55 2004/03/05 05:10:18 marka Exp $ */ +/* $Id: tkey_249.c,v 1.57 2007/06/19 23:47:17 tbox Exp $ */ /* * Reviewed: Thu Mar 16 17:35:30 PST 2000 by halley. diff --git a/lib/dns/rdata/generic/tkey_249.h b/lib/dns/rdata/generic/tkey_249.h index c1d2f06..34d5646 100644 --- a/lib/dns/rdata/generic/tkey_249.h +++ b/lib/dns/rdata/generic/tkey_249.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_TKEY_249_H #define GENERIC_TKEY_249_H 1 -/* $Id: tkey_249.h,v 1.20.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: tkey_249.h,v 1.24 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per draft-ietf-dnsind-tkey-00.txt */ diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c index 01ca87a..a158a59 100644 --- a/lib/dns/rdata/generic/txt_16.c +++ b/lib/dns/rdata/generic/txt_16.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: txt_16.c,v 1.41.18.2 2008/02/15 23:45:53 tbox Exp $ */ +/* $Id: txt_16.c,v 1.45 2008/02/15 23:46:51 tbox Exp $ */ /* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/txt_16.h b/lib/dns/rdata/generic/txt_16.h index 57d986a..fc46486 100644 --- a/lib/dns/rdata/generic/txt_16.h +++ b/lib/dns/rdata/generic/txt_16.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_TXT_16_H #define GENERIC_TXT_16_H 1 -/* $Id: txt_16.h,v 1.24.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: txt_16.h,v 1.28 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_txt_string { isc_uint8_t length; diff --git a/lib/dns/rdata/generic/unspec_103.c b/lib/dns/rdata/generic/unspec_103.c index f316ad9..384863e 100644 --- a/lib/dns/rdata/generic/unspec_103.c +++ b/lib/dns/rdata/generic/unspec_103.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: unspec_103.c,v 1.33 2004/03/05 05:10:18 marka Exp $ */ +/* $Id: unspec_103.c,v 1.35 2007/06/19 23:47:17 tbox Exp $ */ #ifndef RDATA_GENERIC_UNSPEC_103_C #define RDATA_GENERIC_UNSPEC_103_C diff --git a/lib/dns/rdata/generic/unspec_103.h b/lib/dns/rdata/generic/unspec_103.h index 6575c1a..4b2d310 100644 --- a/lib/dns/rdata/generic/unspec_103.h +++ b/lib/dns/rdata/generic/unspec_103.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef GENERIC_UNSPEC_103_H #define GENERIC_UNSPEC_103_H 1 -/* $Id: unspec_103.h,v 1.13.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: unspec_103.h,v 1.17 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_unspec_t { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/generic/x25_19.c b/lib/dns/rdata/generic/x25_19.c index 1199195..c496aaf 100644 --- a/lib/dns/rdata/generic/x25_19.c +++ b/lib/dns/rdata/generic/x25_19.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: x25_19.c,v 1.35.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: x25_19.c,v 1.39 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:15:57 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/generic/x25_19.h b/lib/dns/rdata/generic/x25_19.h index 32320d0..5ebc230 100644 --- a/lib/dns/rdata/generic/x25_19.h +++ b/lib/dns/rdata/generic/x25_19.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef GENERIC_X25_19_H #define GENERIC_X25_19_H 1 -/* $Id: x25_19.h,v 1.14.18.2 2005/04/29 00:16:40 marka Exp $ */ +/* $Id: x25_19.h,v 1.18 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1183 */ diff --git a/lib/dns/rdata/hs_4/a_1.c b/lib/dns/rdata/hs_4/a_1.c index 5d3ddae..487e8bc 100644 --- a/lib/dns/rdata/hs_4/a_1.c +++ b/lib/dns/rdata/hs_4/a_1.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.c,v 1.29 2004/03/05 05:10:20 marka Exp $ */ +/* $Id: a_1.c,v 1.31 2007/06/19 23:47:17 tbox Exp $ */ /* reviewed: Thu Mar 16 15:58:36 PST 2000 by brister */ diff --git a/lib/dns/rdata/hs_4/a_1.h b/lib/dns/rdata/hs_4/a_1.h index 59f54b5..dee812f 100644 --- a/lib/dns/rdata/hs_4/a_1.h +++ b/lib/dns/rdata/hs_4/a_1.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef HS_4_A_1_H #define HS_4_A_1_H 1 -/* $Id: a_1.h,v 1.8.18.2 2005/04/29 00:16:41 marka Exp $ */ +/* $Id: a_1.h,v 1.12 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_hs_a { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/in_1/a6_38.c b/lib/dns/rdata/in_1/a6_38.c index 50017e1..d4d42bb 100644 --- a/lib/dns/rdata/in_1/a6_38.c +++ b/lib/dns/rdata/in_1/a6_38.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a6_38.c,v 1.52 2004/03/05 05:10:23 marka Exp $ */ +/* $Id: a6_38.c,v 1.54 2007/06/19 23:47:17 tbox Exp $ */ /* RFC2874 */ diff --git a/lib/dns/rdata/in_1/a6_38.h b/lib/dns/rdata/in_1/a6_38.h index bb15dad..75e53f1 100644 --- a/lib/dns/rdata/in_1/a6_38.h +++ b/lib/dns/rdata/in_1/a6_38.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_A6_38_H #define IN_1_A6_38_H 1 -/* $Id: a6_38.h,v 1.20.18.2 2005/04/29 00:16:41 marka Exp $ */ +/* $Id: a6_38.h,v 1.24 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2874 */ diff --git a/lib/dns/rdata/in_1/a_1.c b/lib/dns/rdata/in_1/a_1.c index e8cb8ce..d7644bc 100644 --- a/lib/dns/rdata/in_1/a_1.c +++ b/lib/dns/rdata/in_1/a_1.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.c,v 1.51 2004/03/05 05:10:23 marka Exp $ */ +/* $Id: a_1.c,v 1.53 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/in_1/a_1.h b/lib/dns/rdata/in_1/a_1.h index d92a973..c192d1a 100644 --- a/lib/dns/rdata/in_1/a_1.h +++ b/lib/dns/rdata/in_1/a_1.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef IN_1_A_1_H #define IN_1_A_1_H 1 -/* $Id: a_1.h,v 1.24.18.2 2005/04/29 00:16:41 marka Exp $ */ +/* $Id: a_1.h,v 1.28 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_in_a { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/in_1/aaaa_28.c b/lib/dns/rdata/in_1/aaaa_28.c index 1dd32cf..d0503a9 100644 --- a/lib/dns/rdata/in_1/aaaa_28.c +++ b/lib/dns/rdata/in_1/aaaa_28.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: aaaa_28.c,v 1.41.18.2 2005/04/29 00:16:41 marka Exp $ */ +/* $Id: aaaa_28.c,v 1.45 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/in_1/aaaa_28.h b/lib/dns/rdata/in_1/aaaa_28.h index 31ad6a6..54a0cb3 100644 --- a/lib/dns/rdata/in_1/aaaa_28.h +++ b/lib/dns/rdata/in_1/aaaa_28.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_AAAA_28_H #define IN_1_AAAA_28_H 1 -/* $Id: aaaa_28.h,v 1.17.18.2 2005/04/29 00:16:42 marka Exp $ */ +/* $Id: aaaa_28.h,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1886 */ diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c index 2fce328..28ca68e 100644 --- a/lib/dns/rdata/in_1/apl_42.c +++ b/lib/dns/rdata/in_1/apl_42.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: apl_42.c,v 1.8.18.4 2008/01/22 23:27:06 tbox Exp $ */ +/* $Id: apl_42.c,v 1.14 2008/01/22 23:28:04 tbox Exp $ */ /* RFC3123 */ diff --git a/lib/dns/rdata/in_1/apl_42.h b/lib/dns/rdata/in_1/apl_42.h index d434ace..2d01040 100644 --- a/lib/dns/rdata/in_1/apl_42.h +++ b/lib/dns/rdata/in_1/apl_42.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -19,7 +19,7 @@ #ifndef IN_1_APL_42_H #define IN_1_APL_42_H 1 -/* $Id: apl_42.h,v 1.2.18.2 2005/04/29 00:16:42 marka Exp $ */ +/* $Id: apl_42.h,v 1.6 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_apl_ent { isc_boolean_t negative; diff --git a/lib/dns/rdata/in_1/dhcid_49.c b/lib/dns/rdata/in_1/dhcid_49.c new file mode 100644 index 0000000..27c4e4e --- /dev/null +++ b/lib/dns/rdata/in_1/dhcid_49.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2006, 2007 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: dhcid_49.c,v 1.5 2007/06/19 23:47:17 tbox Exp $ */ + +/* RFC 4701 */ + +#ifndef RDATA_IN_1_DHCID_49_C +#define RDATA_IN_1_DHCID_49_C 1 + +#define RRTYPE_DHCID_ATTRIBUTES 0 + +static inline isc_result_t +fromtext_in_dhcid(ARGS_FROMTEXT) { + + REQUIRE(type == 49); + REQUIRE(rdclass == 1); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(origin); + UNUSED(options); + UNUSED(callbacks); + + return (isc_base64_tobuffer(lexer, target, -1)); +} + +static inline isc_result_t +totext_in_dhcid(ARGS_TOTEXT) { + isc_region_t sr; + char buf[sizeof(" ; 64000 255 64000")]; + size_t n; + + REQUIRE(rdata->type == 49); + REQUIRE(rdata->rdclass == 1); + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, &sr); + + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext("( " /*)*/, target)); + RETERR(isc_base64_totext(&sr, tctx->width - 2, tctx->linebreak, + target)); + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { + RETERR(str_totext(/* ( */ " )", target)); + if (rdata->length > 2) { + n = snprintf(buf, sizeof(buf), " ; %u %u %u", + sr.base[0] * 256 + sr.base[1], + sr.base[2], rdata->length - 3); + INSIST(n < sizeof(buf)); + RETERR(str_totext(buf, target)); + } + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_in_dhcid(ARGS_FROMWIRE) { + isc_region_t sr; + + REQUIRE(type == 49); + REQUIRE(rdclass == 1); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(dctx); + UNUSED(options); + + isc_buffer_activeregion(source, &sr); + if (sr.length == 0) + return (ISC_R_UNEXPECTEDEND); + + isc_buffer_forward(source, sr.length); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline isc_result_t +towire_in_dhcid(ARGS_TOWIRE) { + isc_region_t sr; + + REQUIRE(rdata->type == 49); + REQUIRE(rdata->rdclass == 1); + REQUIRE(rdata->length != 0); + + UNUSED(cctx); + + dns_rdata_toregion(rdata, &sr); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline int +compare_in_dhcid(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 49); + REQUIRE(rdata1->rdclass == 1); + 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_in_dhcid(ARGS_FROMSTRUCT) { + dns_rdata_in_dhcid_t *dhcid = source; + + REQUIRE(type == 49); + REQUIRE(rdclass == 1); + REQUIRE(source != NULL); + REQUIRE(dhcid->common.rdtype == type); + REQUIRE(dhcid->common.rdclass == rdclass); + REQUIRE(dhcid->length != 0); + + UNUSED(type); + UNUSED(rdclass); + + return (mem_tobuffer(target, dhcid->dhcid, dhcid->length)); +} + +static inline isc_result_t +tostruct_in_dhcid(ARGS_TOSTRUCT) { + dns_rdata_in_dhcid_t *dhcid = target; + isc_region_t region; + + REQUIRE(rdata->type == 49); + REQUIRE(rdata->rdclass == 1); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + dhcid->common.rdclass = rdata->rdclass; + dhcid->common.rdtype = rdata->type; + ISC_LINK_INIT(&dhcid->common, link); + + dns_rdata_toregion(rdata, ®ion); + + dhcid->dhcid = mem_maybedup(mctx, region.base, region.length); + if (dhcid->dhcid == NULL) + return (ISC_R_NOMEMORY); + + dhcid->mctx = mctx; + return (ISC_R_SUCCESS); +} + +static inline void +freestruct_in_dhcid(ARGS_FREESTRUCT) { + dns_rdata_in_dhcid_t *dhcid = source; + + REQUIRE(dhcid != NULL); + REQUIRE(dhcid->common.rdtype == 49); + REQUIRE(dhcid->common.rdclass == 1); + + if (dhcid->mctx == NULL) + return; + + if (dhcid->dhcid != NULL) + isc_mem_free(dhcid->mctx, dhcid->dhcid); + dhcid->mctx = NULL; +} + +static inline isc_result_t +additionaldata_in_dhcid(ARGS_ADDLDATA) { + REQUIRE(rdata->type == 49); + REQUIRE(rdata->rdclass == 1); + + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_in_dhcid(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == 49); + REQUIRE(rdata->rdclass == 1); + + dns_rdata_toregion(rdata, &r); + + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_in_dhcid(ARGS_CHECKOWNER) { + + REQUIRE(type == 49); + REQUIRE(rdclass == 1); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_in_dhcid(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == 49); + REQUIRE(rdata->rdclass == 1); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +#endif /* RDATA_IN_1_DHCID_49_C */ diff --git a/lib/dns/rdata/in_1/dhcid_49.h b/lib/dns/rdata/in_1/dhcid_49.h new file mode 100644 index 0000000..2797192 --- /dev/null +++ b/lib/dns/rdata/in_1/dhcid_49.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2006, 2007 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 IN_1_DHCID_49_H +#define IN_1_DHCID_49_H 1 + +/* $Id: dhcid_49.h,v 1.5 2007/06/19 23:47:17 tbox Exp $ */ + +typedef struct dns_rdata_in_dhcid { + dns_rdatacommon_t common; + isc_mem_t *mctx; + unsigned char *dhcid; + unsigned int length; +} dns_rdata_in_dhcid_t; + +#endif /* IN_1_DHCID_49_H */ diff --git a/lib/dns/rdata/in_1/kx_36.c b/lib/dns/rdata/in_1/kx_36.c index 8a64aac..9df2e5e 100644 --- a/lib/dns/rdata/in_1/kx_36.c +++ b/lib/dns/rdata/in_1/kx_36.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: kx_36.c,v 1.41.18.2 2005/04/29 00:16:42 marka Exp $ */ +/* $Id: kx_36.c,v 1.45 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Thu Mar 16 17:24:54 PST 2000 by explorer */ diff --git a/lib/dns/rdata/in_1/kx_36.h b/lib/dns/rdata/in_1/kx_36.h index c44883d..391ae27 100644 --- a/lib/dns/rdata/in_1/kx_36.h +++ b/lib/dns/rdata/in_1/kx_36.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_KX_36_H #define IN_1_KX_36_H 1 -/* $Id: kx_36.h,v 1.16.18.2 2005/04/29 00:16:42 marka Exp $ */ +/* $Id: kx_36.h,v 1.20 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2230 */ diff --git a/lib/dns/rdata/in_1/naptr_35.c b/lib/dns/rdata/in_1/naptr_35.c index 9a880ea..21ab44c 100644 --- a/lib/dns/rdata/in_1/naptr_35.c +++ b/lib/dns/rdata/in_1/naptr_35.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: naptr_35.c,v 1.47.18.4 2008/02/15 23:45:53 tbox Exp $ */ +/* $Id: naptr_35.c,v 1.53 2008/02/15 23:46:51 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/in_1/naptr_35.h b/lib/dns/rdata/in_1/naptr_35.h index 2578b48..503f7a8 100644 --- a/lib/dns/rdata/in_1/naptr_35.h +++ b/lib/dns/rdata/in_1/naptr_35.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_NAPTR_35_H #define IN_1_NAPTR_35_H 1 -/* $Id: naptr_35.h,v 1.19.18.2 2005/04/29 00:16:42 marka Exp $ */ +/* $Id: naptr_35.h,v 1.23 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2915 */ diff --git a/lib/dns/rdata/in_1/nsap-ptr_23.c b/lib/dns/rdata/in_1/nsap-ptr_23.c index 1a65cbe..2da7869 100644 --- a/lib/dns/rdata/in_1/nsap-ptr_23.c +++ b/lib/dns/rdata/in_1/nsap-ptr_23.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsap-ptr_23.c,v 1.34.18.2 2005/04/29 00:16:42 marka Exp $ */ +/* $Id: nsap-ptr_23.c,v 1.38 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Fri Mar 17 10:16:02 PST 2000 by gson */ diff --git a/lib/dns/rdata/in_1/nsap-ptr_23.h b/lib/dns/rdata/in_1/nsap-ptr_23.h index bd8e025..14a8b19 100644 --- a/lib/dns/rdata/in_1/nsap-ptr_23.h +++ b/lib/dns/rdata/in_1/nsap-ptr_23.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_NSAP_PTR_23_H #define IN_1_NSAP_PTR_23_H 1 -/* $Id: nsap-ptr_23.h,v 1.15.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: nsap-ptr_23.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1348. Obsoleted in RFC 1706 - use PTR instead. */ diff --git a/lib/dns/rdata/in_1/nsap_22.c b/lib/dns/rdata/in_1/nsap_22.c index a348a30..c25f560 100644 --- a/lib/dns/rdata/in_1/nsap_22.c +++ b/lib/dns/rdata/in_1/nsap_22.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsap_22.c,v 1.38.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: nsap_22.c,v 1.42 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Fri Mar 17 10:41:07 PST 2000 by gson */ diff --git a/lib/dns/rdata/in_1/nsap_22.h b/lib/dns/rdata/in_1/nsap_22.h index 583fbac..11e3f66 100644 --- a/lib/dns/rdata/in_1/nsap_22.h +++ b/lib/dns/rdata/in_1/nsap_22.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_NSAP_22_H #define IN_1_NSAP_22_H 1 -/* $Id: nsap_22.h,v 1.14.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: nsap_22.h,v 1.18 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC1706 */ diff --git a/lib/dns/rdata/in_1/px_26.c b/lib/dns/rdata/in_1/px_26.c index 3df9b99..1d17f2f 100644 --- a/lib/dns/rdata/in_1/px_26.c +++ b/lib/dns/rdata/in_1/px_26.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: px_26.c,v 1.39.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: px_26.c,v 1.43 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Mon Mar 20 10:44:27 PST 2000 */ diff --git a/lib/dns/rdata/in_1/px_26.h b/lib/dns/rdata/in_1/px_26.h index a38d5f81..69a7bae 100644 --- a/lib/dns/rdata/in_1/px_26.h +++ b/lib/dns/rdata/in_1/px_26.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_PX_26_H #define IN_1_PX_26_H 1 -/* $Id: px_26.h,v 1.15.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: px_26.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ /*! * \brief Per RFC2163 */ diff --git a/lib/dns/rdata/in_1/srv_33.c b/lib/dns/rdata/in_1/srv_33.c index 2925a77..7bc85cd 100644 --- a/lib/dns/rdata/in_1/srv_33.c +++ b/lib/dns/rdata/in_1/srv_33.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: srv_33.c,v 1.41.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: srv_33.c,v 1.45 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Fri Mar 17 13:01:00 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/in_1/srv_33.h b/lib/dns/rdata/in_1/srv_33.h index 7d9fef6..e019698 100644 --- a/lib/dns/rdata/in_1/srv_33.h +++ b/lib/dns/rdata/in_1/srv_33.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_SRV_33_H #define IN_1_SRV_33_H 1 -/* $Id: srv_33.h,v 1.15.18.2 2005/04/29 00:16:43 marka Exp $ */ +/* $Id: srv_33.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */ /* Reviewed: Fri Mar 17 13:01:00 PST 2000 by bwelling */ diff --git a/lib/dns/rdata/in_1/wks_11.c b/lib/dns/rdata/in_1/wks_11.c index 749b8fd..55859c4 100644 --- a/lib/dns/rdata/in_1/wks_11.c +++ b/lib/dns/rdata/in_1/wks_11.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: wks_11.c,v 1.51.18.1 2004/09/16 01:02:19 marka Exp $ */ +/* $Id: wks_11.c,v 1.54.332.2 2009/02/16 23:47:15 tbox Exp $ */ /* Reviewed: Fri Mar 17 15:01:49 PST 2000 by explorer */ @@ -158,6 +158,7 @@ totext_in_wks(ARGS_TOTEXT) { RETERR(str_totext(buf, target)); isc_region_consume(&sr, 1); + INSIST(sr.length <= 8*1024); for (i = 0; i < sr.length; i++) { if (sr.base[i] != 0) for (j = 0; j < 8; j++) @@ -242,7 +243,8 @@ fromstruct_in_wks(ARGS_FROMSTRUCT) { REQUIRE(source != NULL); REQUIRE(wks->common.rdtype == type); REQUIRE(wks->common.rdclass == rdclass); - REQUIRE(wks->map != NULL || wks->map_len == 0); + REQUIRE((wks->map != NULL && wks->map_len <= 8*1024) || + wks->map_len == 0); UNUSED(type); UNUSED(rdclass); diff --git a/lib/dns/rdata/in_1/wks_11.h b/lib/dns/rdata/in_1/wks_11.h index a0093b9..2fd26e8 100644 --- a/lib/dns/rdata/in_1/wks_11.h +++ b/lib/dns/rdata/in_1/wks_11.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -18,7 +18,7 @@ #ifndef IN_1_WKS_11_H #define IN_1_WKS_11_H 1 -/* $Id: wks_11.h,v 1.20 2004/03/05 05:10:25 marka Exp $ */ +/* $Id: wks_11.h,v 1.22 2007/06/19 23:47:17 tbox Exp $ */ typedef struct dns_rdata_in_wks { dns_rdatacommon_t common; diff --git a/lib/dns/rdata/rdatastructpre.h b/lib/dns/rdata/rdatastructpre.h index d641ef5..ab7e051 100644 --- a/lib/dns/rdata/rdatastructpre.h +++ b/lib/dns/rdata/rdatastructpre.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatastructpre.h,v 1.14 2004/03/05 05:10:04 marka Exp $ */ +/* $Id: rdatastructpre.h,v 1.16 2007/06/19 23:47:17 tbox Exp $ */ #ifndef DNS_RDATASTRUCT_H #define DNS_RDATASTRUCT_H 1 diff --git a/lib/dns/rdata/rdatastructsuf.h b/lib/dns/rdata/rdatastructsuf.h index 1ab1b0a..3ba1275 100644 --- a/lib/dns/rdata/rdatastructsuf.h +++ b/lib/dns/rdata/rdatastructsuf.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatastructsuf.h,v 1.8 2004/03/05 05:10:04 marka Exp $ */ +/* $Id: rdatastructsuf.h,v 1.10 2007/06/19 23:47:17 tbox Exp $ */ ISC_LANG_ENDDECLS diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c index 7229fa3..d6f11ae 100644 --- a/lib/dns/rdatalist.c +++ b/lib/dns/rdatalist.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist.c,v 1.28.18.3 2005/04/29 00:16:02 marka Exp $ */ +/* $Id: rdatalist.c,v 1.36 2008/09/24 02:46:22 marka Exp $ */ /*! \file */ @@ -26,6 +26,7 @@ #include <isc/util.h> #include <dns/name.h> +#include <dns/nsec3.h> #include <dns/rdata.h> #include <dns/rdatalist.h> #include <dns/rdataset.h> @@ -41,6 +42,8 @@ static dns_rdatasetmethods_t methods = { isc__rdatalist_count, isc__rdatalist_addnoqname, isc__rdatalist_getnoqname, + isc__rdatalist_addclosest, + isc__rdatalist_getclosest, NULL, NULL, NULL @@ -63,8 +66,8 @@ dns_rdatalist_init(dns_rdatalist_t *rdatalist) { isc_result_t dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, - dns_rdataset_t *rdataset) { - + dns_rdataset_t *rdataset) +{ /* * Make 'rdataset' refer to the rdata in 'rdatalist'. */ @@ -88,6 +91,16 @@ dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, return (ISC_R_SUCCESS); } +isc_result_t +dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset, + dns_rdatalist_t **rdatalist) +{ + REQUIRE(rdatalist != NULL && rdataset != NULL); + *rdatalist = rdataset->private1; + + return (ISC_R_SUCCESS); +} + void isc__rdatalist_disassociate(dns_rdataset_t *rdataset) { UNUSED(rdataset); @@ -161,8 +174,8 @@ isc__rdatalist_count(dns_rdataset_t *rdataset) { isc_result_t isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { - dns_rdataset_t *nsec = NULL; - dns_rdataset_t *nsecsig = NULL; + dns_rdataset_t *neg = NULL; + dns_rdataset_t *negsig = NULL; dns_rdataset_t *rdset; dns_ttl_t ttl; @@ -172,24 +185,33 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { { if (rdset->rdclass != rdataset->rdclass) continue; - if (rdset->type == dns_rdatatype_nsec) - nsec = rdset; + if (rdset->type == dns_rdatatype_nsec || + rdset->type == dns_rdatatype_nsec3) + neg = rdset; + } + if (neg == NULL) + return (ISC_R_NOTFOUND); + + for (rdset = ISC_LIST_HEAD(name->list); + rdset != NULL; + rdset = ISC_LIST_NEXT(rdset, link)) + { if (rdset->type == dns_rdatatype_rrsig && - rdset->covers == dns_rdatatype_nsec) - nsecsig = rdset; + rdset->covers == neg->type) + negsig = rdset; } - if (nsec == NULL || nsecsig == NULL) + if (negsig == NULL) return (ISC_R_NOTFOUND); /* * Minimise ttl. */ ttl = rdataset->ttl; - if (nsec->ttl < ttl) - ttl = nsec->ttl; - if (nsecsig->ttl < ttl) - ttl = nsecsig->ttl; - rdataset->ttl = nsec->ttl = nsecsig->ttl = ttl; + if (neg->ttl < ttl) + ttl = neg->ttl; + if (negsig->ttl < ttl) + ttl = negsig->ttl; + rdataset->ttl = neg->ttl = negsig->ttl = ttl; rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; rdataset->private6 = name; return (ISC_R_SUCCESS); @@ -197,11 +219,11 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { isc_result_t isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, dns_rdataset_t *nsecsig) + dns_rdataset_t *neg, dns_rdataset_t *negsig) { dns_rdataclass_t rdclass = rdataset->rdclass; - dns_rdataset_t *tnsec = NULL; - dns_rdataset_t *tnsecsig = NULL; + dns_rdataset_t *tneg = NULL; + dns_rdataset_t *tnegsig = NULL; dns_name_t *noqname = rdataset->private6; REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0); @@ -213,17 +235,113 @@ isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, { if (rdataset->rdclass != rdclass) continue; - if (rdataset->type == dns_rdatatype_nsec) - tnsec = rdataset; + if (rdataset->type == dns_rdatatype_nsec || + rdataset->type == dns_rdatatype_nsec3) + tneg = rdataset; + } + if (tneg == NULL) + return (ISC_R_NOTFOUND); + + for (rdataset = ISC_LIST_HEAD(noqname->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { if (rdataset->type == dns_rdatatype_rrsig && - rdataset->covers == dns_rdatatype_nsec) - tnsecsig = rdataset; + rdataset->covers == tneg->type) + tnegsig = rdataset; } - if (tnsec == NULL || tnsecsig == NULL) + if (tnegsig == NULL) return (ISC_R_NOTFOUND); dns_name_clone(noqname, name); - dns_rdataset_clone(tnsec, nsec); - dns_rdataset_clone(tnsecsig, nsecsig); + dns_rdataset_clone(tneg, neg); + dns_rdataset_clone(tnegsig, negsig); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__rdatalist_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) { + dns_rdataset_t *neg = NULL; + dns_rdataset_t *negsig = NULL; + dns_rdataset_t *rdset; + dns_ttl_t ttl; + + for (rdset = ISC_LIST_HEAD(name->list); + rdset != NULL; + rdset = ISC_LIST_NEXT(rdset, link)) + { + if (rdset->rdclass != rdataset->rdclass) + continue; + if (rdset->type == dns_rdatatype_nsec || + rdset->type == dns_rdatatype_nsec3) + neg = rdset; + } + if (neg == NULL) + return (ISC_R_NOTFOUND); + + for (rdset = ISC_LIST_HEAD(name->list); + rdset != NULL; + rdset = ISC_LIST_NEXT(rdset, link)) + { + if (rdset->type == dns_rdatatype_rrsig && + rdset->covers == neg->type) + negsig = rdset; + } + + if (negsig == NULL) + return (ISC_R_NOTFOUND); + /* + * Minimise ttl. + */ + ttl = rdataset->ttl; + if (neg->ttl < ttl) + ttl = neg->ttl; + if (negsig->ttl < ttl) + ttl = negsig->ttl; + rdataset->ttl = neg->ttl = negsig->ttl = ttl; + rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; + rdataset->private7 = name; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *neg, dns_rdataset_t *negsig) +{ + dns_rdataclass_t rdclass = rdataset->rdclass; + dns_rdataset_t *tneg = NULL; + dns_rdataset_t *tnegsig = NULL; + dns_name_t *closest = rdataset->private7; + + REQUIRE((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0); + (void)dns_name_dynamic(closest); /* Sanity Check. */ + + for (rdataset = ISC_LIST_HEAD(closest->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (rdataset->rdclass != rdclass) + continue; + if (rdataset->type == dns_rdatatype_nsec || + rdataset->type == dns_rdatatype_nsec3) + tneg = rdataset; + } + if (tneg == NULL) + return (ISC_R_NOTFOUND); + + for (rdataset = ISC_LIST_HEAD(closest->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (rdataset->type == dns_rdatatype_rrsig && + rdataset->covers == tneg->type) + tnegsig = rdataset; + } + if (tnegsig == NULL) + return (ISC_R_NOTFOUND); + + dns_name_clone(closest, name); + dns_rdataset_clone(tneg, neg); + dns_rdataset_clone(tnegsig, negsig); return (ISC_R_SUCCESS); } diff --git a/lib/dns/rdatalist_p.h b/lib/dns/rdatalist_p.h index d697fec..3e73e20 100644 --- a/lib/dns/rdatalist_p.h +++ b/lib/dns/rdatalist_p.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist_p.h,v 1.5.18.2 2005/04/29 00:16:03 marka Exp $ */ +/* $Id: rdatalist_p.h,v 1.11 2008/09/25 04:02:38 tbox Exp $ */ #ifndef DNS_RDATALIST_P_H #define DNS_RDATALIST_P_H @@ -50,7 +50,14 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name); isc_result_t isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, dns_rdataset_t *nsecsig); + dns_rdataset_t *neg, dns_rdataset_t *negsig); + +isc_result_t +isc__rdatalist_addclosest(dns_rdataset_t *rdataset, dns_name_t *name); + +isc_result_t +isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *neg, dns_rdataset_t *negsig); ISC_LANG_ENDDECLS diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index c86b3c5..6088a06 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.c,v 1.72.18.5 2006/03/02 00:37:21 marka Exp $ */ +/* $Id: rdataset.c,v 1.82.50.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -59,6 +59,7 @@ dns_rdataset_init(dns_rdataset_t *rdataset) { rdataset->privateuint4 = 0; rdataset->private5 = NULL; rdataset->private6 = NULL; + rdataset->resign = 0; } void @@ -137,7 +138,7 @@ question_disassociate(dns_rdataset_t *rdataset) { static isc_result_t question_cursor(dns_rdataset_t *rdataset) { UNUSED(rdataset); - + return (ISC_R_NOMORE); } @@ -148,7 +149,7 @@ question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { */ UNUSED(rdataset); UNUSED(rdata); - + REQUIRE(0); } @@ -179,6 +180,8 @@ static dns_rdatasetmethods_t question_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; @@ -339,7 +342,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, } /* - * Do we want to shuffle this anwer? + * Do we want to shuffle this answer? */ if (!question && count > 1 && (!WANT_FIXED(rdataset) || order != NULL) && @@ -445,7 +448,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, /* * Copy out the name, type, class, ttl. */ - + rrbuffer = *target; dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); result = dns_name_towire(owner_name, cctx, target); @@ -620,14 +623,36 @@ dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { isc_result_t dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, - dns_rdataset_t *nsec, dns_rdataset_t *nsecsig) + dns_rdataset_t *neg, dns_rdataset_t *negsig) { REQUIRE(DNS_RDATASET_VALID(rdataset)); REQUIRE(rdataset->methods != NULL); if (rdataset->methods->getnoqname == NULL) return (ISC_R_NOTIMPLEMENTED); - return((rdataset->methods->getnoqname)(rdataset, name, nsec, nsecsig)); + return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig)); +} + +isc_result_t +dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) { + + REQUIRE(DNS_RDATASET_VALID(rdataset)); + REQUIRE(rdataset->methods != NULL); + if (rdataset->methods->addclosest == NULL) + return (ISC_R_NOTIMPLEMENTED); + return((rdataset->methods->addclosest)(rdataset, name)); +} + +isc_result_t +dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *neg, dns_rdataset_t *negsig) +{ + REQUIRE(DNS_RDATASET_VALID(rdataset)); + REQUIRE(rdataset->methods != NULL); + + if (rdataset->methods->getclosest == NULL) + return (ISC_R_NOTIMPLEMENTED); + return((rdataset->methods->getclosest)(rdataset, name, neg, negsig)); } /* diff --git a/lib/dns/rdatasetiter.c b/lib/dns/rdatasetiter.c index 8089e04..7ed3030 100644 --- a/lib/dns/rdatasetiter.c +++ b/lib/dns/rdatasetiter.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatasetiter.c,v 1.12.18.2 2005/04/29 00:16:03 marka Exp $ */ +/* $Id: rdatasetiter.c,v 1.16 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 5d89d01..b22868d 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataslab.c,v 1.35.18.8 2007/08/28 07:20:05 tbox Exp $ */ +/* $Id: rdataslab.c,v 1.48.50.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -33,10 +33,6 @@ #include <dns/rdataset.h> #include <dns/rdataslab.h> -#ifndef DNS_RDATASET_FIXED -#define DNS_RDATASET_FIXED 1 -#endif - /* * The rdataslab structure allows iteration to occur in both load order * and DNSSEC order. The structure is as follows: @@ -47,6 +43,7 @@ * data records * data length (2 bytes) * order (2 bytes) + * meta data (1 byte for RRSIG's) * data (data length bytes) * * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a @@ -65,7 +62,7 @@ * * DNSSEC order traversal is performed by walking the data records. * - * The order is stored with record to allow for efficient reconstuction of + * The order is stored with record to allow for efficient reconstruction * of the offset table following a merge or subtraction. * * The iterator methods here currently only support DNSSEC order iteration. @@ -141,6 +138,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, #if DNS_RDATASET_FIXED unsigned int *offsettable; #endif + unsigned int length; buflen = reservelen + 2; @@ -209,12 +207,18 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, x[i].order = x[i-1].order; #endif nitems--; - } else + } else { #if DNS_RDATASET_FIXED buflen += (8 + x[i-1].rdata.length); #else buflen += (2 + x[i-1].rdata.length); #endif + /* + * Provide space to store the per RR meta data. + */ + if (rdataset->type == dns_rdatatype_rrsig) + buflen++; + } } /* * Don't forget the last item! @@ -224,6 +228,11 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, #else buflen += (2 + x[i-1].rdata.length); #endif + /* + * Provide space to store the per RR meta data. + */ + if (rdataset->type == dns_rdatatype_rrsig) + buflen++; /* * Ensure that singleton types are actually singletons. @@ -246,7 +255,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, result = ISC_R_NOMEMORY; goto free_rdatas; } - + #if DNS_RDATASET_FIXED /* Allocate temporary offset table. */ offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int)); @@ -280,15 +289,25 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, #if DNS_RDATASET_FIXED offsettable[x[i].order] = rawbuf - offsetbase; #endif - *rawbuf++ = (x[i].rdata.length & 0xff00) >> 8; - *rawbuf++ = (x[i].rdata.length & 0x00ff); + length = x[i].rdata.length; + if (rdataset->type == dns_rdatatype_rrsig) + length++; + *rawbuf++ = (length & 0xff00) >> 8; + *rawbuf++ = (length & 0x00ff); #if DNS_RDATASET_FIXED rawbuf += 2; /* filled in later */ #endif + /* + * Store the per RR meta data. + */ + if (rdataset->type == dns_rdatatype_rrsig) { + *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ? + DNS_RDATASLAB_OFFLINE : 0; + } memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length); rawbuf += x[i].rdata.length; } - + #if DNS_RDATASET_FIXED fillin_offsets(offsetbase, offsettable, nalloc); isc_mem_put(mctx, offsettable, nalloc * sizeof(unsigned int)); @@ -360,17 +379,27 @@ static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { unsigned char *raw = rdataset->private5; isc_region_t r; + unsigned int length; + unsigned int flags = 0; REQUIRE(raw != NULL); - r.length = raw[0] * 256 + raw[1]; + length = raw[0] * 256 + raw[1]; #if DNS_RDATASET_FIXED raw += 4; #else raw += 2; -#endif +#endif + if (rdataset->type == dns_rdatatype_rrsig) { + if (*raw & DNS_RDATASLAB_OFFLINE) + flags |= DNS_RDATA_OFFLINE; + length--; + raw++; + } + r.length = length; r.base = raw; dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); + rdata->flags |= flags; } static void @@ -405,6 +434,8 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; @@ -474,15 +505,27 @@ rdata_from_slab(unsigned char **current, { unsigned char *tcurrent = *current; isc_region_t region; + unsigned int length; + isc_boolean_t offline = ISC_FALSE; - region.length = *tcurrent++ * 256; - region.length += *tcurrent++; + length = *tcurrent++ * 256; + length += *tcurrent++; + + if (type == dns_rdatatype_rrsig) { + if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) + offline = ISC_TRUE; + length--; + tcurrent++; + } + region.length = length; #if DNS_RDATASET_FIXED tcurrent += 2; #endif region.base = tcurrent; tcurrent += region.length; dns_rdata_fromregion(rdata, rdclass, type, ®ion); + if (offline) + rdata->flags |= DNS_RDATA_OFFLINE; *current = tcurrent; } @@ -511,7 +554,7 @@ rdata_in_slab(unsigned char *slab, unsigned int reservelen, for (i = 0; i < count; i++) { rdata_from_slab(¤t, rdclass, type, &trdata); - + n = dns_rdata_compare(&trdata, rdata); if (n == 0) return (ISC_TRUE); @@ -528,9 +571,8 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, dns_rdataclass_t rdclass, dns_rdatatype_t type, unsigned int flags, unsigned char **tslabp) { - unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent; + unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data; unsigned int ocount, ncount, count, olength, tlength, tcount, length; - isc_region_t nregion; dns_rdata_t ordata = DNS_RDATA_INIT; dns_rdata_t nrdata = DNS_RDATA_INIT; isc_boolean_t added_something = ISC_FALSE; @@ -603,29 +645,24 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, * the old slab. */ do { - nregion.length = *ncurrent++ * 256; - nregion.length += *ncurrent++; -#if DNS_RDATASET_FIXED - ncurrent += 2; /* Skip order. */ -#endif - nregion.base = ncurrent; dns_rdata_init(&nrdata); - dns_rdata_fromregion(&nrdata, rdclass, type, &nregion); + rdata_from_slab(&ncurrent, rdclass, type, &nrdata); if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata)) { /* * This rdata isn't in the old slab. */ #if DNS_RDATASET_FIXED - tlength += nregion.length + 8; + tlength += nrdata.length + 8; #else - tlength += nregion.length + 2; + tlength += nrdata.length + 2; #endif + if (type == dns_rdatatype_rrsig) + tlength++; tcount++; nncount++; added_something = ISC_TRUE; } - ncurrent += nregion.length; ncount--; } while (ncount > 0); ncount = nncount; @@ -726,12 +763,17 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, offsettable[oorder] = tcurrent - offsetbase; #endif length = ordata.length; + data = ordata.data; + if (type == dns_rdatatype_rrsig) { + length++; + data--; + } *tcurrent++ = (length & 0xff00) >> 8; *tcurrent++ = (length & 0x00ff); #if DNS_RDATASET_FIXED tcurrent += 2; /* fill in later */ #endif - memcpy(tcurrent, ordata.data, length); + memcpy(tcurrent, data, length); tcurrent += length; oadded++; if (oadded < ocount) { @@ -748,12 +790,17 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, offsettable[ocount + norder] = tcurrent - offsetbase; #endif length = nrdata.length; + data = nrdata.data; + if (type == dns_rdatatype_rrsig) { + length++; + data--; + } *tcurrent++ = (length & 0xff00) >> 8; *tcurrent++ = (length & 0x00ff); #if DNS_RDATASET_FIXED tcurrent += 2; /* fill in later */ #endif - memcpy(tcurrent, nrdata.data, length); + memcpy(tcurrent, data, length); tcurrent += length; nadded++; if (nadded < ncount) { @@ -799,8 +846,8 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, #if DNS_RDATASET_FIXED unsigned char *offsetbase; unsigned int *offsettable; -#endif unsigned int order; +#endif REQUIRE(tslabp != NULL && *tslabp == NULL); REQUIRE(mslab != NULL && sslab != NULL); diff --git a/lib/dns/request.c b/lib/dns/request.c index 64a3a4e..ac844e1 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: request.c,v 1.72.18.8 2008/07/22 03:51:44 marka Exp $ */ +/* $Id: request.c,v 1.82.72.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -95,7 +95,7 @@ struct dns_request { #define DNS_REQUEST_F_SENDING 0x0002 #define DNS_REQUEST_F_CANCELED 0x0004 /*%< ctlevent received, or otherwise synchronously canceled */ -#define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< cancelled due to a timeout */ +#define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< canceled due to a timeout */ #define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */ #define DNS_REQUEST_CANCELED(r) \ (((r)->flags & DNS_REQUEST_F_CANCELED) != 0) @@ -197,7 +197,7 @@ dns_requestmgr_create(isc_mem_t *mctx, dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6); requestmgr->mctx = NULL; isc_mem_attach(mctx, &requestmgr->mctx); - requestmgr->eref = 1; /* implict attach */ + requestmgr->eref = 1; /* implicit attach */ requestmgr->iref = 0; ISC_LIST_INIT(requestmgr->whenshutdown); ISC_LIST_INIT(requestmgr->requests); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index dc648c9..a1c263e 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,15 +15,18 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.284.18.79 2008/10/17 22:02:13 jinmei Exp $ */ +/* $Id: resolver.c,v 1.384.14.12 2009/05/11 02:38:03 tbox Exp $ */ /*! \file */ #include <config.h> +#include <isc/platform.h> #include <isc/print.h> #include <isc/string.h> +#include <isc/random.h> #include <isc/task.h> +#include <isc/stats.h> #include <isc/timer.h> #include <isc/util.h> @@ -52,22 +55,23 @@ #include <dns/resolver.h> #include <dns/result.h> #include <dns/rootns.h> +#include <dns/stats.h> #include <dns/tsig.h> #include <dns/validator.h> #define DNS_RESOLVER_TRACE #ifdef DNS_RESOLVER_TRACE -#define RTRACE(m) isc_log_write(dns_lctx, \ +#define RTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "res %p: %s", res, (m)) -#define RRTRACE(r, m) isc_log_write(dns_lctx, \ +#define RRTRACE(r, m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "res %p: %s", (r), (m)) -#define FCTXTRACE(m) isc_log_write(dns_lctx, \ +#define FCTXTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ @@ -79,14 +83,14 @@ ISC_LOG_DEBUG(3), \ "fctx %p(%s): %s %s", \ fctx, fctx->info, (m1), (m2)) -#define FTRACE(m) isc_log_write(dns_lctx, \ +#define FTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "fetch %p (fctx %p(%s)): %s", \ fetch, fetch->private, \ fetch->private->info, (m)) -#define QTRACE(m) isc_log_write(dns_lctx, \ +#define QTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ @@ -104,13 +108,13 @@ /*% * Maximum EDNS0 input packet size. */ -#define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */ +#define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */ /*% * This defines the maximum number of timeouts we will permit before we * disable EDNS0 on the query. */ -#define MAX_EDNS0_TIMEOUTS 3 +#define MAX_EDNS0_TIMEOUTS 3 typedef struct fetchctx fetchctx_t; @@ -141,19 +145,25 @@ typedef struct query { #define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!') #define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC) -#define RESQUERY_ATTR_CANCELED 0x02 +#define RESQUERY_ATTR_CANCELED 0x02 -#define RESQUERY_CONNECTING(q) ((q)->connects > 0) -#define RESQUERY_CANCELED(q) (((q)->attributes & \ +#define RESQUERY_CONNECTING(q) ((q)->connects > 0) +#define RESQUERY_CANCELED(q) (((q)->attributes & \ RESQUERY_ATTR_CANCELED) != 0) -#define RESQUERY_SENDING(q) ((q)->sends > 0) +#define RESQUERY_SENDING(q) ((q)->sends > 0) typedef enum { - fetchstate_init = 0, /*%< Start event has not run yet. */ + fetchstate_init = 0, /*%< Start event has not run yet. */ fetchstate_active, - fetchstate_done /*%< FETCHDONE events posted. */ + fetchstate_done /*%< FETCHDONE events posted. */ } fetchstate; +typedef enum { + badns_unreachable = 0, + badns_response, + badns_validation +} badnstype_t; + struct fetchctx { /*% Not locked. */ unsigned int magic; @@ -162,7 +172,7 @@ struct fetchctx { dns_rdatatype_t type; unsigned int options; unsigned int bucketnum; - char * info; + char * info; /*% Locked by appropriate bucket lock. */ fetchstate state; isc_boolean_t want_shutdown; @@ -170,8 +180,8 @@ struct fetchctx { isc_boolean_t spilled; unsigned int references; isc_event_t control_event; - ISC_LINK(struct fetchctx) link; - ISC_LIST(dns_fetchevent_t) events; + ISC_LINK(struct fetchctx) link; + ISC_LIST(dns_fetchevent_t) events; /*% Locked by task event serialization. */ dns_name_t domain; dns_rdataset_t nameservers; @@ -194,7 +204,7 @@ struct fetchctx { isc_sockaddrlist_t edns; isc_sockaddrlist_t edns512; dns_validator_t *validator; - ISC_LIST(dns_validator_t) validators; + ISC_LIST(dns_validator_t) validators; dns_db_t * cache; dns_adb_t * adb; @@ -219,6 +229,7 @@ struct fetchctx { * is used for EDNS0 black hole detection. */ unsigned int timeouts; + /*% * Look aside state for DS lookups. */ @@ -230,34 +241,65 @@ struct fetchctx { * Number of queries that reference this context. */ unsigned int nqueries; + + /*% + * The reason to print when logging a successful + * response to a query. + */ + const char * reason; + + /*% + * Random numbers to use for mixing up server addresses. + */ + isc_uint32_t rand_buf; + isc_uint32_t rand_bits; + + /*% + * Fetch-local statistics for detailed logging. + */ + isc_result_t result; /*%< fetch result */ + isc_result_t vresult; /*%< validation result */ + int exitline; + isc_time_t start; + isc_uint64_t duration; + isc_boolean_t logged; + unsigned int querysent; + unsigned int referrals; + unsigned int lamecount; + unsigned int neterr; + unsigned int badresp; + unsigned int adberr; + unsigned int findfail; + unsigned int valfail; + isc_boolean_t timeout; }; #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!') #define VALID_FCTX(fctx) ISC_MAGIC_VALID(fctx, FCTX_MAGIC) -#define FCTX_ATTR_HAVEANSWER 0x0001 -#define FCTX_ATTR_GLUING 0x0002 -#define FCTX_ATTR_ADDRWAIT 0x0004 -#define FCTX_ATTR_SHUTTINGDOWN 0x0008 -#define FCTX_ATTR_WANTCACHE 0x0010 -#define FCTX_ATTR_WANTNCACHE 0x0020 -#define FCTX_ATTR_NEEDEDNS0 0x0040 -#define FCTX_ATTR_TRIEDFIND 0x0080 -#define FCTX_ATTR_TRIEDALT 0x0100 - -#define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \ +#define FCTX_ATTR_HAVEANSWER 0x0001 +#define FCTX_ATTR_GLUING 0x0002 +#define FCTX_ATTR_ADDRWAIT 0x0004 +#define FCTX_ATTR_SHUTTINGDOWN 0x0008 +#define FCTX_ATTR_WANTCACHE 0x0010 +#define FCTX_ATTR_WANTNCACHE 0x0020 +#define FCTX_ATTR_NEEDEDNS0 0x0040 +#define FCTX_ATTR_TRIEDFIND 0x0080 +#define FCTX_ATTR_TRIEDALT 0x0100 + +#define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \ 0) -#define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \ +#define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \ 0) -#define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \ +#define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \ 0) -#define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \ +#define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \ != 0) -#define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0) -#define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0) -#define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0) -#define TRIEDFIND(f) (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0) -#define TRIEDALT(f) (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0) +#define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0) +#define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0) +#define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0) +#define TRIEDFIND(f) (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0) +#define TRIEDALT(f) (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0) typedef struct { dns_adbaddrinfo_t * addrinfo; @@ -282,14 +324,14 @@ typedef struct fctxbucket { typedef struct alternate { isc_boolean_t isaddress; - union { + union { isc_sockaddr_t addr; struct { - dns_name_t name; - in_port_t port; + dns_name_t name; + in_port_t port; } _n; } _u; - ISC_LINK(struct alternate) link; + ISC_LINK(struct alternate) link; } alternate_t; struct dns_resolver { @@ -311,6 +353,7 @@ struct dns_resolver { isc_boolean_t exclusivev4; dns_dispatch_t * dispatchv6; isc_boolean_t exclusivev6; + unsigned int ndisps; unsigned int nbuckets; fctxbucket_t * buckets; isc_uint32_t lame_ttl; @@ -328,6 +371,7 @@ struct dns_resolver { unsigned int spillatmin; isc_timer_t * spillattimer; isc_boolean_t zero_no_soa_ttl; + /* Locked by lock. */ unsigned int references; isc_boolean_t exiting; @@ -335,6 +379,7 @@ struct dns_resolver { unsigned int activebuckets; isc_boolean_t priming; unsigned int spillat; /* clients-per-query */ + unsigned int nextdisp; /* Locked by primelock. */ dns_fetch_t * primefetch; /* Locked by nlock. */ @@ -348,34 +393,45 @@ struct dns_resolver { * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0, * which we also use as an addrinfo flag. */ -#define FCTX_ADDRINFO_MARK 0x0001 -#define FCTX_ADDRINFO_FORWARDER 0x1000 -#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \ +#define FCTX_ADDRINFO_MARK 0x0001 +#define FCTX_ADDRINFO_FORWARDER 0x1000 +#define FCTX_ADDRINFO_TRIED 0x2000 +#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \ == 0) -#define ISFORWARDER(a) (((a)->flags & \ +#define ISFORWARDER(a) (((a)->flags & \ FCTX_ADDRINFO_FORWARDER) != 0) +#define TRIED(a) (((a)->flags & \ + FCTX_ADDRINFO_TRIED) != 0) #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) -#define dns_db_transfernode(a,b,c) do { (*c) = (*b); (*b) = NULL; } while (0) - static void destroy(dns_resolver_t *res); static void empty_bucket(dns_resolver_t *res); static isc_result_t resquery_send(resquery_t *query); static void resquery_response(isc_task_t *task, isc_event_t *event); static void resquery_connected(isc_task_t *task, isc_event_t *event); -static void fctx_try(fetchctx_t *fctx); +static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying); static isc_boolean_t fctx_destroy(fetchctx_t *fctx); static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, + isc_boolean_t optout, dns_rdataset_t *ardataset, isc_result_t *eresultp); static void validated(isc_task_t *task, isc_event_t *event); static void maybe_destroy(fetchctx_t *fctx); static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, - isc_result_t reason); + isc_result_t reason, badnstype_t badtype); + +/*% + * Increment resolver-related statistics counters. + */ +static inline void +inc_stats(dns_resolver_t *res, isc_statscounter_t counter) { + if (res->view->resstats != NULL) + isc_stats_increment(res->view->resstats, counter); +} static isc_result_t valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, @@ -403,6 +459,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, valoptions, task, validated, valarg, &validator); if (result == ISC_R_SUCCESS) { + inc_stats(fctx->res, dns_resstatscounter_val); if ((valoptions & DNS_VALIDATOR_DEFER) == 0) { INSIST(fctx->validator == NULL); fctx->validator = validator; @@ -522,21 +579,20 @@ fctx_stoptimer(fetchctx_t *fctx) { static inline isc_result_t -fctx_startidletimer(fetchctx_t *fctx) { +fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) { /* * Start the idle timer for fctx. The lifetime timer continues * to be in effect. */ return (isc_timer_reset(fctx->timer, isc_timertype_once, - &fctx->expires, &fctx->interval, - ISC_FALSE)); + &fctx->expires, interval, ISC_FALSE)); } /* * Stopping the idle timer is equivalent to calling fctx_starttimer(), but * we use fctx_stopidletimer for readability in the code below. */ -#define fctx_stopidletimer fctx_starttimer +#define fctx_stopidletimer fctx_starttimer static inline void @@ -551,7 +607,7 @@ resquery_destroy(resquery_t **queryp) { query->fctx->nqueries--; if (SHUTTINGDOWN(query->fctx)) - maybe_destroy(query->fctx); /* Locks bucket. */ + maybe_destroy(query->fctx); /* Locks bucket. */ query->magic = 0; isc_mem_put(query->mctx, query, sizeof(*query)); *queryp = NULL; @@ -563,7 +619,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, { fetchctx_t *fctx; resquery_t *query; - unsigned int rtt; + unsigned int rtt, rttms; unsigned int factor; dns_adbfind_t *find; dns_adbaddrinfo_t *addrinfo; @@ -590,6 +646,27 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, rtt = (unsigned int)isc_time_microdiff(finish, &query->start); factor = DNS_ADB_RTTADJDEFAULT; + + rttms = rtt / 1000; + if (rttms < DNS_RESOLVER_QRYRTTCLASS0) { + inc_stats(fctx->res, + dns_resstatscounter_queryrtt0); + } else if (rttms < DNS_RESOLVER_QRYRTTCLASS1) { + inc_stats(fctx->res, + dns_resstatscounter_queryrtt1); + } else if (rttms < DNS_RESOLVER_QRYRTTCLASS2) { + inc_stats(fctx->res, + dns_resstatscounter_queryrtt2); + } else if (rttms < DNS_RESOLVER_QRYRTTCLASS3) { + inc_stats(fctx->res, + dns_resstatscounter_queryrtt3); + } else if (rttms < DNS_RESOLVER_QRYRTTCLASS4) { + inc_stats(fctx->res, + dns_resstatscounter_queryrtt4); + } else { + inc_stats(fctx->res, + dns_resstatscounter_queryrtt5); + } } else { /* * We don't have an RTT for this query. Maybe the @@ -608,6 +685,12 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor); } + /* Remember that the server has been tried. */ + if (!TRIED(query->addrinfo)) { + dns_adb_changeflags(fctx->adb, query->addrinfo, + FCTX_ADDRINFO_TRIED, FCTX_ADDRINFO_TRIED); + } + /* * Age RTTs of servers not tried. */ @@ -790,14 +873,16 @@ fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) { } static inline void -fctx_sendevents(fetchctx_t *fctx, isc_result_t result) { +fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) { dns_fetchevent_t *event, *next_event; isc_task_t *task; unsigned int count = 0; isc_interval_t i; isc_boolean_t logit = ISC_FALSE; + isc_time_t now; unsigned int old_spillat; - unsigned int new_spillat = 0; /* initialized to silence compiler warnings */ + unsigned int new_spillat = 0; /* initialized to silence + compiler warnings */ /* * Caller must be holding the appropriate bucket lock. @@ -806,6 +891,14 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) { FCTXTRACE("sendevents"); + /* + * Keep some record of fetch result for logging later (if required). + */ + fctx->result = result; + fctx->exitline = line; + TIME_NOW(&now); + fctx->duration = isc_time_microdiff(&now, &fctx->start); + for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next_event) { @@ -864,26 +957,50 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) { } } +static inline void +log_edns(fetchctx_t *fctx) { + char domainbuf[DNS_NAME_FORMATSIZE]; + + if (fctx->reason == NULL) + return; + + dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED, + DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, + "success resolving '%s' (in '%s'?) after %s", + fctx->info, domainbuf, fctx->reason); + + fctx->reason = NULL; +} + static void -fctx_done(fetchctx_t *fctx, isc_result_t result) { +fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { dns_resolver_t *res; isc_boolean_t no_response; + REQUIRE(line >= 0); + FCTXTRACE("done"); res = fctx->res; - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { + /*% + * Log any deferred EDNS timeout messages. + */ + log_edns(fctx); no_response = ISC_TRUE; - else + } else no_response = ISC_FALSE; + + fctx->reason = NULL; fctx_stopeverything(fctx, no_response); LOCK(&res->buckets[fctx->bucketnum].lock); fctx->state = fetchstate_done; fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; - fctx_sendevents(fctx, result); + fctx_sendevents(fctx, result, line); UNLOCK(&res->buckets[fctx->bucketnum].lock); } @@ -921,7 +1038,8 @@ process_sendevent(resquery_t *query, isc_event_t *event) { /* * No route to remote. */ - add_bad(fctx, query->addrinfo, sevent->result); + add_bad(fctx, query->addrinfo, sevent->result, + badns_unreachable); fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); retry = ISC_TRUE; break; @@ -942,9 +1060,9 @@ process_sendevent(resquery_t *query, isc_event_t *event) { fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); else - fctx_try(fctx); + fctx_try(fctx, ISC_TRUE); } } @@ -991,7 +1109,8 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) { } static inline isc_result_t -fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize) +fctx_addopt(dns_message_t *message, unsigned int version, + isc_uint16_t udpsize, isc_boolean_t request_nsid) { dns_rdataset_t *rdataset; dns_rdatalist_t *rdatalist; @@ -1027,10 +1146,23 @@ fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize) rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO; /* - * No EDNS options. + * Set EDNS options if applicable */ - rdata->data = NULL; - rdata->length = 0; + if (request_nsid) { + /* Send empty NSID option (RFC5001) */ + unsigned char data[4]; + isc_buffer_t buf; + + isc_buffer_init(&buf, data, sizeof(data)); + isc_buffer_putuint16(&buf, DNS_OPT_NSID); + isc_buffer_putuint16(&buf, 0); + rdata->data = data; + rdata->length = sizeof(data); + } else { + rdata->data = NULL; + rdata->length = 0; + } + rdata->rdclass = rdatalist->rdclass; rdata->type = rdatalist->type; rdata->flags = 0; @@ -1048,7 +1180,7 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { unsigned int us; /* - * We retry every .5 seconds the first two times through the address + * We retry every .8 seconds the first two times through the address * list, and then we do exponential back-off. */ if (fctx->restarts < 3) @@ -1088,14 +1220,19 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, resquery_t *query; isc_sockaddr_t addr; isc_boolean_t have_addr = ISC_FALSE; + unsigned int srtt; FCTXTRACE("query"); res = fctx->res; task = res->buckets[fctx->bucketnum].task; - fctx_setretryinterval(fctx, addrinfo->srtt); - result = fctx_startidletimer(fctx); + srtt = addrinfo->srtt; + if (ISFORWARDER(addrinfo) && srtt < 1000000) + srtt = 1000000; + + fctx_setretryinterval(fctx, srtt); + result = fctx_startidletimer(fctx, &fctx->interval); if (result != ISC_R_SUCCESS) return (result); @@ -1262,9 +1399,17 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (result != ISC_R_SUCCESS) goto cleanup_dispatch; } + fctx->querysent++; ISC_LIST_APPEND(fctx->queries, query, link); query->fctx->nqueries++; + if (isc_sockaddr_pf(&addrinfo->sockaddr) == PF_INET) + inc_stats(res, dns_resstatscounter_queryv4); + else + inc_stats(res, dns_resstatscounter_queryv6); + if (res->view->resquerystats != NULL) + dns_rdatatypestats_increment(res->view->resquerystats, + fctx->type); return (ISC_R_SUCCESS); @@ -1486,34 +1631,55 @@ resquery_send(resquery_t *query) { !useedns) { query->options |= DNS_FETCHOPT_NOEDNS0; - dns_adb_changeflags(fctx->adb, - query->addrinfo, + dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); } + /* Sync NOEDNS0 flag in addrinfo->flags and options now. */ + if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) != 0) + query->options |= DNS_FETCHOPT_NOEDNS0; + + /* + * Handle timeouts by reducing the UDP response size to 512 bytes + * then if that doesn't work disabling EDNS (includes DO) and CD. + * + * These timeout can be due to: + * * broken nameservers that don't respond to EDNS queries. + * * broken/misconfigured firewalls and NAT implementations + * that don't handle IP fragmentation. + * * broken/misconfigured firewalls that don't handle responses + * greater than 512 bytes. + * * broken/misconfigured firewalls that don't handle EDNS, DO + * or CD. + * * packet loss / link outage. + */ + if (fctx->timeout) { + if ((triededns512(fctx, &query->addrinfo->sockaddr) || + fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) && + (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { + query->options |= DNS_FETCHOPT_NOEDNS0; + fctx->reason = "disabling EDNS"; + } else if ((triededns(fctx, &query->addrinfo->sockaddr) || + fctx->timeouts >= MAX_EDNS0_TIMEOUTS) && + (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { + query->options |= DNS_FETCHOPT_EDNS512; + fctx->reason = "reducing the advertised EDNS UDP " + "packet size to 512 octets"; + } + fctx->timeout = ISC_FALSE; + } + /* * Use EDNS0, unless the caller doesn't want it, or we know that * the remote server doesn't like it. */ - - if ((triededns512(fctx, &query->addrinfo->sockaddr) || - fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) && - (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { - query->options |= DNS_FETCHOPT_NOEDNS0; - FCTXTRACE("too many timeouts, disabling EDNS0"); - } else if ((triededns(fctx, &query->addrinfo->sockaddr) || - fctx->timeouts >= MAX_EDNS0_TIMEOUTS) && - (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { - query->options |= DNS_FETCHOPT_EDNS512; - FCTXTRACE("too many timeouts, setting EDNS size to 512"); - } - if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) { - unsigned int version = 0; /* Default version. */ + unsigned int version = 0; /* Default version. */ unsigned int flags; isc_uint16_t udpsize = res->udpsize; + isc_boolean_t reqnsid = res->view->requestnsid; flags = query->addrinfo->flags; if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) { @@ -1524,8 +1690,15 @@ resquery_send(resquery_t *query) { udpsize = 512; else if (peer != NULL) (void)dns_peer_getudpsize(peer, &udpsize); - result = fctx_addopt(fctx->qmessage, version, udpsize); - if (result != ISC_R_SUCCESS) { + + /* request NSID for current view or peer? */ + if (peer != NULL) + (void) dns_peer_getrequestnsid(peer, &reqnsid); + result = fctx_addopt(fctx->qmessage, version, + udpsize, reqnsid); + if (reqnsid && result == ISC_R_SUCCESS) { + query->options |= DNS_FETCHOPT_WANTNSID; + } else if (result != ISC_R_SUCCESS) { /* * We couldn't add the OPT, but we'll press on. * We're not using EDNS0, so set the NOEDNS0 @@ -1636,13 +1809,15 @@ resquery_send(resquery_t *query) { /* * XXXRTH Make sure we don't send to ourselves! We should probably - * prune out these addresses when we get them from the ADB. + * prune out these addresses when we get them from the ADB. */ result = isc_socket_sendto(socket, &r, task, resquery_senddone, query, address, NULL); if (result != ISC_R_SUCCESS) goto cleanup_message; + query->sends++; + QTRACE("sent"); return (ISC_R_SUCCESS); @@ -1672,6 +1847,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; resquery_t *query = event->ev_arg; isc_boolean_t retry = ISC_FALSE; + isc_interval_t interval; isc_result_t result; unsigned int attrs; fetchctx_t *fctx; @@ -1704,6 +1880,20 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { } else { switch (sevent->result) { case ISC_R_SUCCESS: + + /* + * Extend the idle timer for TCP. 20 seconds + * should be long enough for a TCP connection to be + * established, a single DNS request to be sent, + * and the response received. + */ + isc_interval_set(&interval, 20, 0); + result = fctx_startidletimer(query->fctx, &interval); + if (result != ISC_R_SUCCESS) { + fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); + fctx_done(fctx, result, __LINE__); + break; + } /* * We are connected. Create a dispatcher and * send the query. @@ -1736,9 +1926,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { result = resquery_send(query); if (result != ISC_R_SUCCESS) { - fctx_cancelquery(&query, NULL, NULL, - ISC_FALSE); - fctx_done(fctx, result); + fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); + fctx_done(fctx, result, __LINE__); } break; @@ -1773,9 +1962,9 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); else - fctx_try(fctx); + fctx_try(fctx, ISC_TRUE); } } @@ -1809,13 +1998,16 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) want_try = ISC_TRUE; - else if (fctx->pending == 0) { - /* - * We've got nothing else to wait for and don't - * know the answer. There's nothing to do but - * fail the fctx. - */ - want_done = ISC_TRUE; + else { + fctx->findfail++; + if (fctx->pending == 0) { + /* + * We've got nothing else to wait for and don't + * know the answer. There's nothing to do but + * fail the fctx. + */ + want_done = ISC_TRUE; + } } } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { @@ -1834,9 +2026,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { dns_adb_destroyfind(&find); if (want_try) - fctx_try(fctx); + fctx_try(fctx, ISC_TRUE); else if (want_done) - fctx_done(fctx, ISC_R_FAILURE); + fctx_done(fctx, ISC_R_FAILURE, __LINE__); else if (bucket_empty) empty_bucket(res); } @@ -1924,7 +2116,9 @@ mark_bad(fetchctx_t *fctx) { } static void -add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) { +add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, + badnstype_t badtype) +{ char namebuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; char classbuf[64]; @@ -1935,6 +2129,21 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) { const char *sep1, *sep2; isc_sockaddr_t *address = &addrinfo->sockaddr; + if (reason == DNS_R_LAME) + fctx->lamecount++; + else { + switch (badtype) { + case badns_unreachable: + fctx->neterr++; + break; + case badns_response: + fctx->badresp++; + break; + case badns_validation: + break; /* counted as 'valfail' */ + } + } + if (bad_server(fctx, address)) { /* * We already know this server is bad. @@ -1951,7 +2160,7 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) { *sa = *address; ISC_LIST_INITANDAPPEND(fctx->bad, sa, link); - if (reason == DNS_R_LAME) /* already logged */ + if (reason == DNS_R_LAME) /* already logged */ return; if (reason == DNS_R_UNEXPECTEDRCODE && @@ -1987,15 +2196,79 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) { namebuf, typebuf, classbuf, addrbuf); } +/* + * Return 'bits' bits of random entropy from fctx->rand_buf, + * refreshing it by calling isc_random_get() whenever the requested + * number of bits is greater than the number in the buffer. + */ +static inline isc_uint32_t +random_bits(fetchctx_t *fctx, isc_uint32_t bits) { + isc_uint32_t ret = 0; + + REQUIRE(VALID_FCTX(fctx)); + REQUIRE(bits <= 32); + if (bits == 0) + return (0); + + if (bits >= fctx->rand_bits) { + /* if rand_bits == 0, this is unnecessary but harmless */ + bits -= fctx->rand_bits; + ret = fctx->rand_buf << bits; + + /* refresh random buffer now */ + isc_random_get(&fctx->rand_buf); + fctx->rand_bits = sizeof(fctx->rand_buf) * CHAR_BIT; + } + + if (bits > 0) { + isc_uint32_t mask = 0xffffffff; + if (bits < 32) { + mask = (1 << bits) - 1; + } + + ret |= fctx->rand_buf & mask; + fctx->rand_buf >>= bits; + fctx->rand_bits -= bits; + } + + return (ret); +} + +/* + * Add some random jitter to a server's RTT value so that the + * order of queries will be unpredictable. + * + * RTT values of servers which have been tried are fuzzed by 128 ms. + * Servers that haven't been tried yet have their RTT set to a random + * value between 0 ms and 7 ms; they should get to go first, but in + * unpredictable order. + */ +static inline void +randomize_srtt(fetchctx_t *fctx, dns_adbaddrinfo_t *ai) { + if (TRIED(ai)) { + ai->srtt >>= 10; /* convert to milliseconds, near enough */ + ai->srtt |= (ai->srtt & 0x80) | random_bits(fctx, 7); + ai->srtt <<= 10; /* now back to microseconds */ + } else + ai->srtt = random_bits(fctx, 3) << 10; +} + +/* + * Sort addrinfo list by RTT (with random jitter) + */ static void -sort_adbfind(dns_adbfind_t *find) { +sort_adbfind(fetchctx_t *fctx, dns_adbfind_t *find) { dns_adbaddrinfo_t *best, *curr; dns_adbaddrinfolist_t sorted; - /* - * Lame N^2 bubble sort. - */ + /* Add jitter to SRTT values */ + curr = ISC_LIST_HEAD(find->list); + while (curr != NULL) { + randomize_srtt(fctx, curr); + curr = ISC_LIST_NEXT(curr, publink); + } + /* Lame N^2 bubble sort. */ ISC_LIST_INIT(sorted); while (!ISC_LIST_EMPTY(find->list)) { best = ISC_LIST_HEAD(find->list); @@ -2011,39 +2284,25 @@ sort_adbfind(dns_adbfind_t *find) { find->list = sorted; } +/* + * Sort a list of finds by server RTT (with random jitter) + */ static void -sort_finds(fetchctx_t *fctx) { +sort_finds(fetchctx_t *fctx, dns_adbfindlist_t *findlist) { dns_adbfind_t *best, *curr; dns_adbfindlist_t sorted; dns_adbaddrinfo_t *addrinfo, *bestaddrinfo; - /* - * Lame N^2 bubble sort. - */ - - ISC_LIST_INIT(sorted); - while (!ISC_LIST_EMPTY(fctx->finds)) { - best = ISC_LIST_HEAD(fctx->finds); - bestaddrinfo = ISC_LIST_HEAD(best->list); - INSIST(bestaddrinfo != NULL); - curr = ISC_LIST_NEXT(best, publink); - while (curr != NULL) { - addrinfo = ISC_LIST_HEAD(curr->list); - INSIST(addrinfo != NULL); - if (addrinfo->srtt < bestaddrinfo->srtt) { - best = curr; - bestaddrinfo = addrinfo; - } - curr = ISC_LIST_NEXT(curr, publink); - } - ISC_LIST_UNLINK(fctx->finds, best, publink); - ISC_LIST_APPEND(sorted, best, publink); - } - fctx->finds = sorted; + /* Sort each find's addrinfo list by SRTT (after adding jitter) */ + for (curr = ISC_LIST_HEAD(*findlist); + curr != NULL; + curr = ISC_LIST_NEXT(curr, publink)) + sort_adbfind(fctx, curr); + /* Lame N^2 bubble sort. */ ISC_LIST_INIT(sorted); - while (!ISC_LIST_EMPTY(fctx->altfinds)) { - best = ISC_LIST_HEAD(fctx->altfinds); + while (!ISC_LIST_EMPTY(*findlist)) { + best = ISC_LIST_HEAD(*findlist); bestaddrinfo = ISC_LIST_HEAD(best->list); INSIST(bestaddrinfo != NULL); curr = ISC_LIST_NEXT(best, publink); @@ -2056,10 +2315,10 @@ sort_finds(fetchctx_t *fctx) { } curr = ISC_LIST_NEXT(curr, publink); } - ISC_LIST_UNLINK(fctx->altfinds, best, publink); + ISC_LIST_UNLINK(*findlist, best, publink); ISC_LIST_APPEND(sorted, best, publink); } - fctx->altfinds = sorted; + *findlist = sorted; } static void @@ -2103,6 +2362,7 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, * XXXRTH Follow the CNAME/DNAME chain? */ dns_adb_destroyfind(&find); + fctx->adberr++; } } else if (!ISC_LIST_EMPTY(find->list)) { /* @@ -2110,7 +2370,6 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, * name. */ INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); - sort_adbfind(find); if (flags != 0 || port != 0) { for (ai = ISC_LIST_HEAD(find->list); ai != NULL; @@ -2147,6 +2406,11 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, find->result_v4 != DNS_R_NXDOMAIN))) *need_alternate = ISC_TRUE; } else { + if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) + fctx->lamecount++; /* cached lame server */ + else + fctx->adberr++; /* unreachable server, etc. */ + /* * If we know there are no addresses for * the family we are using then try to add @@ -2188,7 +2452,7 @@ fctx_getaddresses(fetchctx_t *fctx) { } res = fctx->res; - stdoptions = 0; /* Keep compiler happy. */ + stdoptions = 0; /* Keep compiler happy. */ /* * Forwarders. @@ -2379,7 +2643,8 @@ fctx_getaddresses(fetchctx_t *fctx) { * We've found some addresses. We might still be looking * for more addresses. */ - sort_finds(fctx); + sort_finds(fctx, &fctx->finds); + sort_finds(fctx, &fctx->altfinds); result = ISC_R_SUCCESS; } @@ -2593,7 +2858,7 @@ fctx_nextaddress(fetchctx_t *fctx) { } static void -fctx_try(fetchctx_t *fctx) { +fctx_try(fetchctx_t *fctx, isc_boolean_t retrying) { isc_result_t result; dns_adbaddrinfo_t *addrinfo; @@ -2623,7 +2888,7 @@ fctx_try(fetchctx_t *fctx) { /* * Something bad happened. */ - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); return; } @@ -2633,14 +2898,16 @@ fctx_try(fetchctx_t *fctx) { * might be bad ones. In this case, return SERVFAIL. */ if (addrinfo == NULL) { - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } } result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); + else if (retrying) + inc_stats(fctx->res, dns_resstatscounter_retry); } static isc_boolean_t @@ -2738,12 +3005,16 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) { FCTXTRACE("timeout"); + inc_stats(fctx->res, dns_resstatscounter_querytimeout); + if (event->ev_type == ISC_TIMEREVENT_LIFE) { - fctx_done(fctx, ISC_R_TIMEDOUT); + fctx->reason = NULL; + fctx_done(fctx, ISC_R_TIMEDOUT, __LINE__); } else { isc_result_t result; fctx->timeouts++; + fctx->timeout = ISC_TRUE; /* * We could cancel the running queries here, or we could let * them keep going. Since we normally use separate sockets for @@ -2765,12 +3036,12 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) { */ result = fctx_starttimer(fctx); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); else /* * Keep trying. */ - fctx_try(fctx); + fctx_try(fctx, ISC_TRUE); } isc_event_free(&event); @@ -2860,7 +3131,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { if (fctx->state != fetchstate_done) { fctx->state = fetchstate_done; - fctx_sendevents(fctx, ISC_R_CANCELED); + fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__); } if (fctx->references == 0 && fctx->pending == 0 && @@ -2899,7 +3170,7 @@ fctx_start(isc_task_t *task, isc_event_t *event) { */ fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; fctx->state = fetchstate_done; - fctx_sendevents(fctx, ISC_R_CANCELED); + fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__); /* * Since we haven't started, we INSIST that we have no * pending ADB finds and no pending validations. @@ -2938,9 +3209,9 @@ fctx_start(isc_task_t *task, isc_event_t *event) { */ result = fctx_starttimer(fctx); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); else - fctx_try(fctx); + fctx_try(fctx, ISC_FALSE); } else if (bucket_empty) empty_bucket(res); } @@ -3026,8 +3297,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, return (ISC_R_NOMEMORY); dns_name_format(name, buf, sizeof(buf)); dns_rdatatype_format(type, typebuf, sizeof(typebuf)); - strcat(buf, "/"); /* checked */ - strcat(buf, typebuf); /* checked */ + strcat(buf, "/"); /* checked */ + strcat(buf, typebuf); /* checked */ fctx->info = isc_mem_strdup(res->buckets[bucketnum].mctx, buf); if (fctx->info == NULL) { result = ISC_R_NOMEMORY; @@ -3070,10 +3341,27 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, fctx->altfind = NULL; fctx->pending = 0; fctx->restarts = 0; + fctx->querysent = 0; + fctx->referrals = 0; + TIME_NOW(&fctx->start); fctx->timeouts = 0; + fctx->lamecount = 0; + fctx->adberr = 0; + fctx->neterr = 0; + fctx->badresp = 0; + fctx->findfail = 0; + fctx->valfail = 0; + fctx->result = ISC_R_FAILURE; + fctx->vresult = ISC_R_SUCCESS; + fctx->exitline = -1; /* sentinel */ + fctx->logged = ISC_FALSE; fctx->attributes = 0; fctx->spilled = ISC_FALSE; fctx->nqueries = 0; + fctx->reason = NULL; + fctx->rand_buf = 0; + fctx->rand_bits = 0; + fctx->timeout = ISC_FALSE; dns_name_init(&fctx->nsname, NULL); fctx->nsfetch = NULL; @@ -3162,7 +3450,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, /* * Compute an expiration time for the entire fetch. */ - isc_interval_set(&interval, 30, 0); /* XXXRTH constant */ + isc_interval_set(&interval, 30, 0); /* XXXRTH constant */ iresult = isc_time_nowplusinterval(&fctx->expires, &interval); if (iresult != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, @@ -3382,13 +3670,13 @@ clone_results(fetchctx_t *fctx) { } } -#define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0) -#define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0) -#define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0) -#define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0) -#define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0) -#define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0) -#define CHECKNAMES(r) (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0) +#define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0) +#define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0) +#define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0) +#define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0) +#define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0) +#define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0) +#define CHECKNAMES(r) (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0) /* @@ -3397,7 +3685,7 @@ clone_results(fetchctx_t *fctx) { * was the last fctx in the resolver, destroy the resolver. * * Requires: - * '*fctx' is shutting down. + * '*fctx' is shutting down. */ static void maybe_destroy(fetchctx_t *fctx) { @@ -3494,7 +3782,7 @@ validated(isc_task_t *task, isc_event_t *event) { * so, destroy the fctx. */ if (SHUTTINGDOWN(fctx) && !sentresponse) { - maybe_destroy(fctx); /* Locks bucket. */ + maybe_destroy(fctx); /* Locks bucket. */ goto cleanup_event; } @@ -3543,6 +3831,9 @@ validated(isc_task_t *task, isc_event_t *event) { if (vevent->result != ISC_R_SUCCESS) { FCTXTRACE("validation failed"); + inc_stats(fctx->res, dns_resstatscounter_valfail); + fctx->valfail++; + fctx->vresult = vevent->result; result = ISC_R_NOTFOUND; if (vevent->rdataset != NULL) result = dns_db_findnode(fctx->cache, vevent->name, @@ -3557,7 +3848,7 @@ validated(isc_task_t *task, isc_event_t *event) { if (result == ISC_R_SUCCESS) dns_db_detachnode(fctx->cache, &node); result = vevent->result; - add_bad(fctx, addrinfo, result); + add_bad(fctx, addrinfo, result, badns_validation); isc_event_free(&event); UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); INSIST(fctx->validator == NULL); @@ -3565,9 +3856,9 @@ validated(isc_task_t *task, isc_event_t *event) { if (fctx->validator != NULL) { dns_validator_send(fctx->validator); } else if (sentresponse) - fctx_done(fctx, result); /* Locks bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks bucket. */ else - fctx_try(fctx); /* Locks bucket. */ + fctx_try(fctx, ISC_TRUE); /* Locks bucket. */ return; } @@ -3577,6 +3868,8 @@ validated(isc_task_t *task, isc_event_t *event) { dns_rdatatype_t covers; FCTXTRACE("nonexistence validation OK"); + inc_stats(fctx->res, dns_resstatscounter_valnegsuccess); + if (fctx->rmessage->rcode == dns_rcode_nxdomain) covers = dns_rdatatype_any; else @@ -3590,7 +3883,7 @@ validated(isc_task_t *task, isc_event_t *event) { /* * If we are asking for a SOA record set the cache time * to zero to facilitate locating the containing zone of - * a arbitary zone. + * a arbitrary zone. */ ttl = fctx->res->view->maxncachettl; if (fctx->type == dns_rdatatype_soa && @@ -3599,12 +3892,13 @@ validated(isc_task_t *task, isc_event_t *event) { ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, - covers, now, ttl, + covers, now, ttl, vevent->optout, ardataset, &eresult); if (result != ISC_R_SUCCESS) goto noanswer_response; goto answer_response; - } + } else + inc_stats(fctx->res, dns_resstatscounter_valsuccess); FCTXTRACE("validation OK"); @@ -3615,6 +3909,11 @@ validated(isc_task_t *task, isc_event_t *event) { RUNTIME_CHECK(result == ISC_R_SUCCESS); INSIST(vevent->sigrdataset != NULL); vevent->sigrdataset->ttl = vevent->rdataset->ttl; + if (vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER] != NULL) { + result = dns_rdataset_addclosest(vevent->rdataset, + vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER]); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } } /* @@ -3654,7 +3953,7 @@ validated(isc_task_t *task, isc_event_t *event) { dns_db_detachnode(fctx->cache, &node); UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); if (SHUTTINGDOWN(fctx)) - maybe_destroy(fctx); /* Locks bucket. */ + maybe_destroy(fctx); /* Locks bucket. */ goto cleanup_event; } @@ -3744,7 +4043,7 @@ validated(isc_task_t *task, isc_event_t *event) { UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); - fctx_done(fctx, result); /* Locks bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks bucket. */ cleanup_event: INSIST(node == NULL); @@ -3929,53 +4228,53 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, rdataset->trust = dns_trust_pending; if (sigrdataset != NULL) sigrdataset->trust = dns_trust_pending; - if (!need_validation) + if (!need_validation || !ANSWER(rdataset)) { addedrdataset = ardataset; - else - addedrdataset = NULL; - result = dns_db_addrdataset(fctx->cache, node, NULL, - now, rdataset, 0, - addedrdataset); - if (result == DNS_R_UNCHANGED) { - result = ISC_R_SUCCESS; - if (!need_validation && - ardataset != NULL && - ardataset->type == 0) { - /* - * The answer in the cache is better - * than the answer we found, and is - * a negative cache entry, so we - * must set eresult appropriately. - */ - if (NXDOMAIN(ardataset)) - eresult = DNS_R_NCACHENXDOMAIN; - else - eresult = DNS_R_NCACHENXRRSET; - /* - * We have a negative response from - * the cache so don't attempt to - * add the RRSIG rrset. - */ - continue; - } - } - if (result != ISC_R_SUCCESS) - break; - if (sigrdataset != NULL) { - if (!need_validation) - addedrdataset = asigrdataset; - else - addedrdataset = NULL; - result = dns_db_addrdataset(fctx->cache, - node, NULL, now, - sigrdataset, 0, - addedrdataset); - if (result == DNS_R_UNCHANGED) + result = dns_db_addrdataset(fctx->cache, node, + NULL, now, rdataset, + 0, addedrdataset); + if (result == DNS_R_UNCHANGED) { result = ISC_R_SUCCESS; + if (!need_validation && + ardataset != NULL && + ardataset->type == 0) { + /* + * The answer in the cache is + * better than the answer we + * found, and is a negative + * cache entry, so we must set + * eresult appropriately. + */ + if (NXDOMAIN(ardataset)) + eresult = + DNS_R_NCACHENXDOMAIN; + else + eresult = + DNS_R_NCACHENXRRSET; + /* + * We have a negative response + * from the cache so don't + * attempt to add the RRSIG + * rrset. + */ + continue; + } + } if (result != ISC_R_SUCCESS) break; - } else if (!ANSWER(rdataset)) - continue; + if (sigrdataset != NULL) { + addedrdataset = asigrdataset; + result = dns_db_addrdataset(fctx->cache, + node, NULL, now, + sigrdataset, 0, + addedrdataset); + if (result == DNS_R_UNCHANGED) + result = ISC_R_SUCCESS; + if (result != ISC_R_SUCCESS) + break; + } else if (!ANSWER(rdataset)) + continue; + } if (ANSWER(rdataset) && need_validation) { if (fctx->type != dns_rdatatype_any && @@ -4011,7 +4310,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, * Defer any further validations. * This prevents multiple validators * from manipulating fctx->rmessage - * simultaniously. + * simultaneously. */ valoptions |= DNS_VALIDATOR_DEFER; } @@ -4155,12 +4454,12 @@ cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) } /* - * Do what dns_ncache_add() does, and then compute an appropriate eresult. + * Do what dns_ncache_addoptout() does, and then compute an appropriate eresult. */ static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, - dns_rdataset_t *ardataset, + isc_boolean_t optout, dns_rdataset_t *ardataset, isc_result_t *eresultp) { isc_result_t result; @@ -4170,8 +4469,8 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdataset_init(&rdataset); ardataset = &rdataset; } - result = dns_ncache_add(message, cache, node, covers, now, - maxttl, ardataset); + result = dns_ncache_addoptout(message, cache, node, covers, now, + maxttl, optout, ardataset); if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) { /* * If the cache now contains a negative entry and we @@ -4327,15 +4626,17 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, /* * If we are asking for a SOA record set the cache time * to zero to facilitate locating the containing zone of - * a arbitary zone. + * a arbitrary zone. */ ttl = fctx->res->view->maxncachettl; if (fctx->type == dns_rdatatype_soa && - covers == dns_rdatatype_any) + covers == dns_rdatatype_any && + fctx->res->zero_no_soa_ttl) ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, - covers, now, ttl, ardataset, &eresult); + covers, now, ttl, ISC_FALSE, + ardataset, &eresult); if (result != ISC_R_SUCCESS) goto unlock; @@ -4710,7 +5011,8 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, type = rdataset->type; if (type == dns_rdatatype_rrsig) type = rdataset->covers; - if (type == dns_rdatatype_nsec) { + if (type == dns_rdatatype_nsec || + type == dns_rdatatype_nsec3) { /* * NSEC or RRSIG NSEC. */ @@ -4719,7 +5021,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, DNS_NAMEATTR_NCACHE; rdataset->attributes |= DNS_RDATASETATTR_NCACHE; - } else { + } else if (type == dns_rdatatype_nsec) { name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= @@ -4855,7 +5157,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, * Set the current query domain to the referral name. * * XXXRTH We should check if we're in forward-only mode, and - * if so we should bail out. + * if so we should bail out. */ INSIST(dns_name_countlabels(&fctx->domain) > 0); dns_name_free(&fctx->domain, @@ -4931,6 +5233,13 @@ answer_response(fetchctx_t *fctx) { found = ISC_FALSE; want_chaining = ISC_FALSE; aflag = 0; + if (rdataset->type == dns_rdatatype_nsec3) { + /* + * NSEC3 records are not allowed to + * appear in the answer section. + */ + return (DNS_R_FORMERR); + } if (rdataset->type == type && !found_cname) { /* * We've found an ordinary answer. @@ -5157,7 +5466,7 @@ answer_response(fetchctx_t *fctx) { */ if (found_dname) { /* - * Copy the the dname into the + * Copy the dname into the * qname fixed name. * * Although we check for @@ -5311,7 +5620,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { bucketnum = fctx->bucketnum; if (fevent->result == ISC_R_CANCELED) { dns_resolver_destroyfetch(&fctx->nsfetch); - fctx_done(fctx, ISC_R_CANCELED); + fctx_done(fctx, ISC_R_CANCELED, __LINE__); } else if (fevent->result == ISC_R_SUCCESS) { FCTXTRACE("resuming DS lookup"); @@ -5327,13 +5636,13 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { fctx->res->buckets[bucketnum].mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); goto cleanup; } /* * Try again. */ - fctx_try(fctx); + fctx_try(fctx, ISC_TRUE); } else { unsigned int n; dns_rdataset_t *nsrdataset = NULL; @@ -5345,7 +5654,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { domain = dns_fixedname_name(&fixed); dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL); if (dns_name_equal(&fctx->nsname, domain)) { - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); dns_resolver_destroyfetch(&fctx->nsfetch); goto cleanup; } @@ -5372,7 +5681,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); else { LOCK(&res->buckets[bucketnum].lock); locked = ISC_TRUE; @@ -5439,6 +5748,65 @@ checknames(dns_message_t *message) { checknamessection(message, DNS_SECTION_ADDITIONAL); } +/* + * Log server NSID at log level 'level' + */ +static isc_result_t +log_nsid(dns_rdataset_t *opt, resquery_t *query, int level, isc_mem_t *mctx) +{ + static const char hex[17] = "0123456789abcdef"; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_uint16_t optcode, nsid_len, buflen, i; + isc_result_t result; + isc_buffer_t nsidbuf; + dns_rdata_t rdata; + unsigned char *p, *buf, *nsid; + + /* Extract rdata from OPT rdataset */ + result = dns_rdataset_first(opt); + if (result != ISC_R_SUCCESS) + return (ISC_R_FAILURE); + + dns_rdata_init(&rdata); + dns_rdataset_current(opt, &rdata); + if (rdata.length < 4) + return (ISC_R_FAILURE); + + /* Check for NSID */ + isc_buffer_init(&nsidbuf, rdata.data, rdata.length); + isc_buffer_add(&nsidbuf, rdata.length); + optcode = isc_buffer_getuint16(&nsidbuf); + nsid_len = isc_buffer_getuint16(&nsidbuf); + if (optcode != DNS_OPT_NSID || nsid_len == 0) + return (ISC_R_FAILURE); + + /* Allocate buffer for storing hex version of the NSID */ + buflen = nsid_len * 2 + 1; + buf = isc_mem_get(mctx, buflen); + if (buf == NULL) + return (ISC_R_NOSPACE); + + /* Convert to hex */ + p = buf; + nsid = rdata.data + 4; + for (i = 0; i < nsid_len; i++) { + *p++ = hex[(nsid[0] >> 4) & 0xf]; + *p++ = hex[nsid[0] & 0xf]; + nsid++; + } + *p = '\0'; + + isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf, + sizeof(addrbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, level, + "received NSID '%s' from %s", buf, addrbuf); + + /* Clean up */ + isc_mem_put(mctx, buf, buflen); + return (ISC_R_SUCCESS); +} + static void log_packet(dns_message_t *message, int level, isc_mem_t *mctx) { isc_buffer_t buffer; @@ -5484,6 +5852,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { isc_boolean_t keep_trying, get_nameservers, resend; isc_boolean_t truncated; dns_message_t *message; + dns_rdataset_t *opt; fetchctx_t *fctx; dns_name_t *fname; dns_fixedname_t foundname; @@ -5493,6 +5862,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { unsigned int options; unsigned int findoptions; isc_result_t broken_server; + badnstype_t broken_type = badns_response; REQUIRE(VALID_QUERY(query)); fctx = query->fctx; @@ -5502,6 +5872,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) { QTRACE("response"); + if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) + inc_stats(fctx->res, dns_resstatscounter_responsev4); + else + inc_stats(fctx->res, dns_resstatscounter_responsev6); + (void)isc_timer_touch(fctx->timer); keep_trying = ISC_FALSE; @@ -5517,11 +5892,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } fctx->timeouts = 0; + fctx->timeout = ISC_FALSE; /* * XXXRTH We should really get the current time just once. We - * need a routine to convert from an isc_time_t to an - * isc_stdtime_t. + * need a routine to convert from an isc_time_t to an + * isc_stdtime_t. */ TIME_NOW(&tnow); finish = &tnow; @@ -5564,6 +5940,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { devent->result == ISC_R_CONNREFUSED || devent->result == ISC_R_CANCELED)) { broken_server = devent->result; + broken_type = badns_unreachable; } } goto done; @@ -5616,6 +5993,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); + inc_stats(fctx->res, + dns_resstatscounter_edns0fail); } else { broken_server = result; keep_trying = ISC_TRUE; @@ -5644,6 +6023,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); + inc_stats(fctx->res, + dns_resstatscounter_edns0fail); } else { broken_server = DNS_R_UNEXPECTEDRCODE; keep_trying = ISC_TRUE; @@ -5657,12 +6038,21 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } } + /* * Log the incoming packet. */ log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx); /* + * Did we request NSID? If so, and if the response contains + * NSID data, log it at INFO level. + */ + opt = dns_message_getopt(message); + if (opt != NULL && (query->options & DNS_FETCHOPT_WANTNSID) != 0) + log_nsid(opt, query, ISC_LOG_INFO, fctx->res->mctx); + + /* * If the message is signed, check the signature. If not, this * returns success anyway. */ @@ -5690,6 +6080,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { truncated = ISC_TRUE; if (truncated) { + inc_stats(fctx->res, dns_resstatscounter_truncated); if ((options & DNS_FETCHOPT_TCP) != 0) { broken_server = DNS_R_TRUNCATEDTCP; keep_trying = ISC_TRUE; @@ -5711,6 +6102,26 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } /* + * Update statistics about erroneous responses. + */ + if (message->rcode != dns_rcode_noerror) { + switch (message->rcode) { + case dns_rcode_nxdomain: + inc_stats(fctx->res, dns_resstatscounter_nxdomain); + break; + case dns_rcode_servfail: + inc_stats(fctx->res, dns_resstatscounter_servfail); + break; + case dns_rcode_formerr: + inc_stats(fctx->res, dns_resstatscounter_formerr); + break; + default: + inc_stats(fctx->res, dns_resstatscounter_othererror); + break; + } + } + + /* * Is the remote server broken, or does it dislike us? */ if (message->rcode != dns_rcode_noerror && @@ -5728,8 +6139,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * reasons. * * XXXRTH We should check if the question - * we're asking requires EDNS0, and - * if so, we should bail out. + * we're asking requires EDNS0, and + * if so, we should bail out. */ options |= DNS_FETCHOPT_NOEDNS0; resend = ISC_TRUE; @@ -5740,6 +6151,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); + inc_stats(fctx->res, dns_resstatscounter_edns0fail); } else if (message->rcode == dns_rcode_formerr) { if (ISFORWARDER(query->addrinfo)) { /* @@ -5767,12 +6179,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ result = DNS_R_YXDOMAIN; } else if (message->rcode == dns_rcode_badvers) { - dns_rdataset_t *opt; unsigned int flags, mask; unsigned int version; resend = ISC_TRUE; - opt = dns_message_getopt(message); version = (opt->ttl >> 16) & 0xff; flags = (version << DNS_FETCHOPT_EDNSVERSIONSHIFT) | DNS_FETCHOPT_EDNSVERSIONSET; @@ -5815,6 +6225,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) && is_lame(fctx)) { + inc_stats(fctx->res, dns_resstatscounter_lame); log_lame(fctx, query->addrinfo); result = dns_adb_marklame(fctx->adb, query->addrinfo, &fctx->name, fctx->type, @@ -5928,6 +6339,18 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * has not experienced any restarts yet. */ fctx->restarts = 0; + + /* + * Update local statistics counters collected for each + * new zone. + */ + fctx->referrals++; + fctx->querysent = 0; + fctx->lamecount = 0; + fctx->neterr = 0; + fctx->badresp = 0; + fctx->adberr = 0; + result = ISC_R_SUCCESS; } else if (result != ISC_R_SUCCESS) { /* @@ -6001,7 +6424,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Add this server to the list of bad servers for * this fctx. */ - add_bad(fctx, addrinfo, broken_server); + add_bad(fctx, addrinfo, broken_server, broken_type); } if (get_nameservers) { @@ -6009,7 +6432,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { dns_fixedname_init(&foundname); fname = dns_fixedname_name(&foundname); if (result != ISC_R_SUCCESS) { - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } findoptions = 0; @@ -6027,7 +6450,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { NULL); if (result != ISC_R_SUCCESS) { FCTXTRACE("couldn't find a zonecut"); - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } if (!dns_name_issubdomain(fname, &fctx->domain)) { @@ -6036,7 +6459,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * QDOMAIN. */ FCTXTRACE("nameservers now above QDOMAIN"); - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } dns_name_free(&fctx->domain, @@ -6046,7 +6469,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { fctx->res->buckets[fctx->bucketnum].mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { - fctx_done(fctx, DNS_R_SERVFAIL); + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } fctx_cancelqueries(fctx, ISC_TRUE); @@ -6058,15 +6481,16 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* * Try again. */ - fctx_try(fctx); + fctx_try(fctx, !get_nameservers); } else if (resend) { /* * Resend (probably with changed options). */ FCTXTRACE("resend"); + inc_stats(fctx->res, dns_resstatscounter_retry); result = fctx_query(fctx, addrinfo, options); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) { /* * All has gone well so far, but we are waiting for the @@ -6080,10 +6504,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); } else if (result == DNS_R_CHASEDSSERVERS) { unsigned int n; - add_bad(fctx, addrinfo, result); + add_bad(fctx, addrinfo, result, broken_type); fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupforwaddrs(fctx); @@ -6100,18 +6524,18 @@ resquery_response(isc_task_t *task, isc_event_t *event) { &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); LOCK(&fctx->res->buckets[fctx->bucketnum].lock); fctx->references++; UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); } else { /* * We're done. */ - fctx_done(fctx, result); + fctx_done(fctx, result, __LINE__); } } @@ -6284,7 +6708,8 @@ dns_resolver_create(dns_view_t *view, res->spillatmax = 100; res->spillattimer = NULL; res->zero_no_soa_ttl = ISC_FALSE; - + res->ndisps = 0; + res->nextdisp = 0; /* meaningless at this point, but init it */ res->nbuckets = ntasks; res->activebuckets = ntasks; res->buckets = isc_mem_get(view->mctx, @@ -6304,13 +6729,23 @@ dns_resolver_create(dns_view_t *view, goto cleanup_buckets; } res->buckets[i].mctx = NULL; + snprintf(name, sizeof(name), "res%u", i); +#ifdef ISC_PLATFORM_USETHREADS + /* + * Use a separate memory context for each bucket to reduce + * contention among multiple threads. Do this only when + * enabling threads because it will be require more memory. + */ result = isc_mem_create(0, 0, &res->buckets[i].mctx); if (result != ISC_R_SUCCESS) { isc_task_detach(&res->buckets[i].task); DESTROYLOCK(&res->buckets[i].lock); goto cleanup_buckets; } - snprintf(name, sizeof(name), "res%u", i); + isc_mem_setname(res->buckets[i].mctx, name, NULL); +#else + isc_mem_attach(view->mctx, &res->buckets[i].mctx); +#endif isc_task_setname(res->buckets[i].task, name, res); ISC_LIST_INIT(res->buckets[i].fctxs); res->buckets[i].exiting = ISC_FALSE; @@ -6356,14 +6791,14 @@ dns_resolver_create(dns_view_t *view, task = NULL; result = isc_task_create(taskmgr, 0, &task); if (result != ISC_R_SUCCESS) - goto cleanup_primelock; + goto cleanup_primelock; result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, task, spillattimer_countdown, res, &res->spillattimer); isc_task_detach(&task); if (result != ISC_R_SUCCESS) - goto cleanup_primelock; + goto cleanup_primelock; #if USE_ALGLOCK result = isc_rwlock_init(&res->alglock, 0, 0); @@ -6973,6 +7408,47 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { empty_bucket(res); } +void +dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx, + isc_logcategory_t *category, isc_logmodule_t *module, + int level, isc_boolean_t duplicateok) +{ + fetchctx_t *fctx; + dns_resolver_t *res; + char domainbuf[DNS_NAME_FORMATSIZE]; + + REQUIRE(DNS_FETCH_VALID(fetch)); + fctx = fetch->private; + REQUIRE(VALID_FCTX(fctx)); + res = fctx->res; + + LOCK(&res->buckets[fctx->bucketnum].lock); + + INSIST(fctx->exitline >= 0); + if (!fctx->logged || duplicateok) { + dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + isc_log_write(lctx, category, module, level, + "fetch completed at %s:%d for %s in " + "%" ISC_PRINT_QUADFORMAT "u." + "%06" ISC_PRINT_QUADFORMAT "u: %s/%s " + "[domain:%s,referral:%u,restart:%u,qrysent:%u," + "timeout:%u,lame:%u,neterr:%u,badresp:%u," + "adberr:%u,findfail:%u,valfail:%u]", + __FILE__, fctx->exitline, fctx->info, + fctx->duration / 1000000, + fctx->duration % 1000000, + isc_result_totext(fctx->result), + isc_result_totext(fctx->vresult), domainbuf, + fctx->referrals, fctx->restarts, + fctx->querysent, fctx->timeouts, fctx->lamecount, + fctx->neterr, fctx->badresp, fctx->adberr, + fctx->findfail, fctx->valfail); + fctx->logged = ISC_TRUE; + } + + UNLOCK(&res->buckets[fctx->bucketnum].lock); +} + dns_dispatchmgr_t * dns_resolver_dispatchmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); @@ -7296,3 +7772,10 @@ dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state) { resolver->zero_no_soa_ttl = state; } + +unsigned int +dns_resolver_getoptions(dns_resolver_t *resolver) { + REQUIRE(VALID_RESOLVER(resolver)); + + return (resolver->options); +} diff --git a/lib/dns/result.c b/lib/dns/result.c index fdb58e0..54c70e0 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.c,v 1.115.10.7 2005/06/17 02:04:31 marka Exp $ */ +/* $Id: result.c,v 1.125 2008/09/25 04:02:38 tbox Exp $ */ /*! \file */ @@ -155,7 +155,8 @@ static const char *text[DNS_R_NRESULTS] = { "must-be-secure", /*%< 100 DNS_R_MUSTBESECURE */ "covering NSEC record returned", /*%< 101 DNS_R_COVERINGNSEC */ "MX is an address", /*%< 102 DNS_R_MXISADDRESS */ - "duplicate query" /*%< 103 DNS_R_DUPLICATE */ + "duplicate query", /*%< 103 DNS_R_DUPLICATE */ + "invalid NSEC3 owner name (wildcard)", /*%< 104 DNS_R_INVALIDNSEC3 */ }; static const char *rcode_text[DNS_R_NRCODERESULTS] = { diff --git a/lib/dns/rootns.c b/lib/dns/rootns.c index a988bea..3c50a18 100644 --- a/lib/dns/rootns.c +++ b/lib/dns/rootns.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rootns.c,v 1.26.18.7 2008/02/05 23:46:09 tbox Exp $ */ +/* $Id: rootns.c,v 1.36 2008/09/24 02:46:22 marka Exp $ */ /*! \file */ @@ -97,6 +97,7 @@ in_rootns(dns_rdataset_t *rootns, dns_name_t *name) { if (dns_name_compare(name, &ns.name) == 0) return (ISC_R_SUCCESS); result = dns_rdataset_next(rootns); + dns_rdata_reset(&rdata); } if (result == ISC_R_NOMORE) result = ISC_R_NOTFOUND; @@ -158,7 +159,7 @@ check_hints(dns_db_t *db) { dns_rdataset_init(&rootns); (void)dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0, now, NULL, name, &rootns, NULL); - result = dns_db_createiterator(db, ISC_FALSE, &dbiter); + result = dns_db_createiterator(db, 0, &dbiter); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_dbiterator_first(dbiter); @@ -338,6 +339,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { result = dns_rdataset_first(&rootrrset); while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); dns_rdataset_current(&rootrrset, &rdata); if (!inrrset(&hintrrset, &rdata)) report(view, name, ISC_TRUE, &rdata); @@ -345,6 +347,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, } result = dns_rdataset_first(&hintrrset); while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); dns_rdataset_current(&hintrrset, &rdata); if (!inrrset(&rootrrset, &rdata)) report(view, name, ISC_FALSE, &rdata); @@ -355,6 +358,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { result = dns_rdataset_first(&rootrrset); while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); dns_rdataset_current(&rootrrset, &rdata); report(view, name, ISC_TRUE, &rdata); result = dns_rdataset_next(&rootrrset); @@ -377,6 +381,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { result = dns_rdataset_first(&rootrrset); while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); dns_rdataset_current(&rootrrset, &rdata); if (!inrrset(&hintrrset, &rdata)) report(view, name, ISC_TRUE, &rdata); @@ -385,6 +390,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, } result = dns_rdataset_first(&hintrrset); while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); dns_rdataset_current(&hintrrset, &rdata); if (!inrrset(&rootrrset, &rdata)) report(view, name, ISC_FALSE, &rdata); @@ -396,6 +402,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db, (rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) { result = dns_rdataset_first(&rootrrset); while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); dns_rdataset_current(&rootrrset, &rdata); report(view, name, ISC_TRUE, &rdata); dns_rdata_reset(&rdata); diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index effb2bf..03fca9e 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdb.c,v 1.45.18.16 2008/01/17 23:45:58 tbox Exp $ */ +/* $Id: sdb.c,v 1.66.48.2 2009/04/21 23:47:18 tbox Exp $ */ /*! \file */ @@ -880,9 +880,12 @@ find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, { result = DNS_R_ZONECUT; dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL) + if (sigrdataset != NULL && + dns_rdataset_isassociated + (sigrdataset)) { dns_rdataset_disassociate (sigrdataset); + } } else result = DNS_R_DELEGATION; break; @@ -1035,8 +1038,7 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { } static isc_result_t -createiterator(dns_db_t *db, isc_boolean_t relative_names, - dns_dbiterator_t **iteratorp) +createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp) { dns_sdb_t *sdb = (dns_sdb_t *)db; sdb_dbiterator_t *sdbiter; @@ -1048,6 +1050,10 @@ createiterator(dns_db_t *db, isc_boolean_t relative_names, if (imp->methods->allnodes == NULL) return (ISC_R_NOTIMPLEMENTED); + if ((options & DNS_DB_NSEC3ONLY) != 0 || + (options & DNS_DB_NONSEC3) != 0) + return (ISC_R_NOTIMPLEMENTED); + sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t)); if (sdbiter == NULL) return (ISC_R_NOMEMORY); @@ -1055,7 +1061,7 @@ createiterator(dns_db_t *db, isc_boolean_t relative_names, sdbiter->common.methods = &dbiterator_methods; sdbiter->common.db = NULL; dns_db_attach(db, &sdbiter->common.db); - sdbiter->common.relative_names = relative_names; + sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES); sdbiter->common.magic = DNS_DBITERATOR_MAGIC; ISC_LIST_INIT(sdbiter->nodelist); sdbiter->current = NULL; @@ -1246,6 +1252,14 @@ static dns_dbmethods_t sdb_methods = { ispersistent, overmem, settask, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, NULL }; @@ -1371,6 +1385,8 @@ static dns_rdatasetmethods_t methods = { isc__rdatalist_getnoqname, NULL, NULL, + NULL, + NULL, NULL }; diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index b91f825..89cd0ee 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2005-2007 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005-2009 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdlz.c,v 1.2.2.11 2007/08/28 07:20:05 tbox Exp $ */ +/* $Id: sdlz.c,v 1.18.50.2 2009/04/21 23:47:18 tbox Exp $ */ /*! \file */ @@ -667,8 +667,7 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { } static isc_result_t -createiterator(dns_db_t *db, isc_boolean_t relative_names, - dns_dbiterator_t **iteratorp) +createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp) { dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; sdlz_dbiterator_t *sdlziter; @@ -681,6 +680,10 @@ createiterator(dns_db_t *db, isc_boolean_t relative_names, if (sdlz->dlzimp->methods->allnodes == NULL) return (ISC_R_NOTIMPLEMENTED); + if ((options & DNS_DB_NSEC3ONLY) != 0 || + (options & DNS_DB_NONSEC3) != 0) + return (ISC_R_NOTIMPLEMENTED); + isc_buffer_init(&b, zonestr, sizeof(zonestr)); result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b); if (result != ISC_R_SUCCESS) @@ -694,7 +697,7 @@ createiterator(dns_db_t *db, isc_boolean_t relative_names, sdlziter->common.methods = &dbiterator_methods; sdlziter->common.db = NULL; dns_db_attach(db, &sdlziter->common.db); - sdlziter->common.relative_names = relative_names; + sdlziter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES); sdlziter->common.magic = DNS_DBITERATOR_MAGIC; ISC_LIST_INIT(sdlziter->nodelist); sdlziter->current = NULL; @@ -841,9 +844,12 @@ find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, { result = DNS_R_ZONECUT; dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL) + if (sigrdataset != NULL && + dns_rdataset_isassociated + (sigrdataset)) { dns_rdataset_disassociate (sigrdataset); + } } else result = DNS_R_DELEGATION; break; @@ -1051,6 +1057,14 @@ static dns_dbmethods_t sdlzdb_methods = { overmem, settask, NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL }; /* @@ -1193,6 +1207,8 @@ static dns_rdatasetmethods_t rdataset_methods = { isc__rdatalist_getnoqname, NULL, NULL, + NULL, + NULL, NULL }; @@ -1327,7 +1343,7 @@ dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx, return (result); isc_buffer_putuint8(&b2, 0); - /* make sure strings are always lowercase */ + /* make sure strings are always lowercase */ dns_sdlz_tolower(namestr); dns_sdlz_tolower(clientstr); @@ -1440,7 +1456,7 @@ dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx, return (result); isc_buffer_putuint8(&b, 0); - /* make sure strings are always lowercase */ + /* make sure strings are always lowercase */ dns_sdlz_tolower(namestr); /* Call SDLZ driver's find zone method */ @@ -1571,7 +1587,7 @@ dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl, return (ISC_R_SUCCESS); failure: - if (rdatabuf != NULL) + if (rdatabuf != NULL) isc_buffer_free(&rdatabuf); if (lex != NULL) isc_lex_destroy(&lex); diff --git a/lib/dns/soa.c b/lib/dns/soa.c index 20198c0..83a1c17 100644 --- a/lib/dns/soa.c +++ b/lib/dns/soa.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa.c,v 1.4.18.2 2005/04/29 00:16:05 marka Exp $ */ +/* $Id: soa.c,v 1.8 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/spnego.asn1 b/lib/dns/spnego.asn1 new file mode 100644 index 0000000..43d152b --- /dev/null +++ b/lib/dns/spnego.asn1 @@ -0,0 +1,52 @@ +-- Copyright (C) The Internet Society 2005. This version of +-- this module is part of RFC 4178; see the RFC itself for +-- full legal notices. + +-- (The above copyright notice is per RFC 3978 5.6 (a), q.v.) + +-- $Id: spnego.asn1,v 1.2 2006/12/04 01:52:46 marka Exp $ + +-- This is the SPNEGO ASN.1 module from RFC 4178, tweaked +-- to get the Heimdal ASN.1 compiler to accept it. + +SPNEGOASNOneSpec DEFINITIONS ::= BEGIN + +MechType ::= OBJECT IDENTIFIER + +MechTypeList ::= SEQUENCE OF MechType + +ContextFlags ::= BIT STRING { + delegFlag (0), + mutualFlag (1), + replayFlag (2), + sequenceFlag (3), + anonFlag (4), + confFlag (5), + integFlag (6) +} + +NegTokenInit ::= SEQUENCE { + mechTypes [0] MechTypeList, + reqFlags [1] ContextFlags OPTIONAL, + mechToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL +} + +NegTokenResp ::= SEQUENCE { + negState [0] ENUMERATED { + accept-completed (0), + accept-incomplete (1), + reject (2), + request-mic (3) + } OPTIONAL, + supportedMech [1] MechType OPTIONAL, + responseToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL +} + +NegotiationToken ::= CHOICE { + negTokenInit [0] NegTokenInit, + negTokenResp [1] NegTokenResp +} + +END diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c new file mode 100644 index 0000000..0ae6ea2 --- /dev/null +++ b/lib/dns/spnego.c @@ -0,0 +1,1792 @@ +/* + * Copyright (C) 2006-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: spnego.c,v 1.8.118.2 2009/01/18 23:47:40 tbox Exp $ */ + +/*! \file + * \brief + * Portable SPNEGO implementation. + * + * This is part of a portable implementation of the SPNEGO protocol + * (RFCs 2478 and 4178). This implementation uses the RFC 4178 ASN.1 + * module but is not a full implementation of the RFC 4178 protocol; + * at the moment, we only support GSS-TSIG with Kerberos + * authentication, so we only need enough of the SPNEGO protocol to + * support that. + * + * The files that make up this portable SPNEGO implementation are: + * \li spnego.c (this file) + * \li spnego.h (API SPNEGO exports to the rest of lib/dns) + * \li spnego.asn1 (SPNEGO ASN.1 module) + * \li spnego_asn1.c (routines generated from spngo.asn1) + * \li spnego_asn1.pl (perl script to generate spnego_asn1.c) + * + * Everything but the functions exported in spnego.h is static, to + * avoid possible conflicts with other libraries (particularly Heimdal, + * since much of this code comes from Heimdal by way of mod_auth_kerb). + * + * spnego_asn1.c is shipped as part of lib/dns because generating it + * requires both Perl and the Heimdal ASN.1 compiler. See + * spnego_asn1.pl for further details. We've tried to eliminate all + * compiler warnings from the generated code, but you may see a few + * when using a compiler version we haven't tested yet. + */ + +/* + * Portions of this code were derived from mod_auth_kerb and Heimdal. + * These packages are available from: + * + * http://modauthkerb.sourceforge.net/ + * http://www.pdc.kth.se/heimdal/ + * + * and were released under the following licenses: + * + * ---------------------------------------------------------------- + * + * Copyright (c) 2004 Masarykova universita + * (Masaryk University, Brno, Czech Republic) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the University nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * ---------------------------------------------------------------- + * + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * XXXSRA We should omit this file entirely in Makefile.in via autoconf, + * but this will keep it from generating errors until that's written. + */ + +#ifdef GSSAPI + +/* + * XXXSRA Some of the following files are almost certainly unnecessary, + * but using this list (borrowed from gssapictx.c) gets rid of some + * whacky compilation errors when building with MSVC and should be + * harmless in any case. + */ + +#include <config.h> + +#include <stdlib.h> +#include <errno.h> + +#include <isc/buffer.h> +#include <isc/dir.h> +#include <isc/entropy.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/once.h> +#include <isc/random.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +#include <dns/fixedname.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/result.h> +#include <dns/types.h> +#include <dns/keyvalues.h> +#include <dns/log.h> + +#include <dst/gssapi.h> +#include <dst/result.h> + +#include "dst_internal.h" + +/* + * The API we export + */ +#include "spnego.h" + +/* asn1_err.h */ +/* Generated from ../../../lib/asn1/asn1_err.et */ + +typedef enum asn1_error_number { + ASN1_BAD_TIMEFORMAT = 1859794432, + ASN1_MISSING_FIELD = 1859794433, + ASN1_MISPLACED_FIELD = 1859794434, + ASN1_TYPE_MISMATCH = 1859794435, + ASN1_OVERFLOW = 1859794436, + ASN1_OVERRUN = 1859794437, + ASN1_BAD_ID = 1859794438, + ASN1_BAD_LENGTH = 1859794439, + ASN1_BAD_FORMAT = 1859794440, + ASN1_PARSE_ERROR = 1859794441 +} asn1_error_number; + +#define ERROR_TABLE_BASE_asn1 1859794432 + +#define __asn1_common_definitions__ + +typedef struct octet_string { + size_t length; + void *data; +} octet_string; + +typedef char *general_string; + +typedef char *utf8_string; + +typedef struct oid { + size_t length; + unsigned *components; +} oid; + +/* der.h */ + +typedef enum { + ASN1_C_UNIV = 0, ASN1_C_APPL = 1, + ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3 +} Der_class; + +typedef enum { + PRIM = 0, CONS = 1 +} Der_type; + +/* Universal tags */ + +enum { + UT_Boolean = 1, + UT_Integer = 2, + UT_BitString = 3, + UT_OctetString = 4, + UT_Null = 5, + UT_OID = 6, + UT_Enumerated = 10, + UT_Sequence = 16, + UT_Set = 17, + UT_PrintableString = 19, + UT_IA5String = 22, + UT_UTCTime = 23, + UT_GeneralizedTime = 24, + UT_VisibleString = 26, + UT_GeneralString = 27 +}; + +#define ASN1_INDEFINITE 0xdce0deed + +static int +der_get_length(const unsigned char *p, size_t len, + size_t * val, size_t * size); + +static int +der_get_octet_string(const unsigned char *p, size_t len, + octet_string * data, size_t * size); +static int +der_get_oid(const unsigned char *p, size_t len, + oid * data, size_t * size); +static int +der_get_tag(const unsigned char *p, size_t len, + Der_class * class, Der_type * type, + int *tag, size_t * size); + +static int +der_match_tag(const unsigned char *p, size_t len, + Der_class class, Der_type type, + int tag, size_t * size); +static int +der_match_tag_and_length(const unsigned char *p, size_t len, + Der_class class, Der_type type, int tag, + size_t * length_ret, size_t * size); + +static int +decode_oid(const unsigned char *p, size_t len, + oid * k, size_t * size); + +static int +decode_enumerated(const unsigned char *p, size_t len, + unsigned *num, size_t *size); + +static int +decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *); + +static int +der_put_int(unsigned char *p, size_t len, int val, size_t *); + +static int +der_put_length(unsigned char *p, size_t len, size_t val, size_t *); + +static int +der_put_octet_string(unsigned char *p, size_t len, + const octet_string * data, size_t *); +static int +der_put_oid(unsigned char *p, size_t len, + const oid * data, size_t * size); +static int +der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type, + int tag, size_t *); +static int +der_put_length_and_tag(unsigned char *, size_t, size_t, + Der_class, Der_type, int, size_t *); + +static int +encode_enumerated(unsigned char *p, size_t len, + const unsigned *data, size_t *); + +static int +encode_octet_string(unsigned char *p, size_t len, + const octet_string * k, size_t *); +static int +encode_oid(unsigned char *p, size_t len, + const oid * k, size_t *); + +static void +free_octet_string(octet_string * k); + +static void +free_oid (oid * k); + +static size_t +length_len(size_t len); + +static int +fix_dce(size_t reallen, size_t * len); + +/* + * Include stuff generated by the ASN.1 compiler. + */ + +#include "spnego_asn1.c" + +static unsigned char gss_krb5_mech_oid_bytes[] = { + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 +}; + +static gss_OID_desc gss_krb5_mech_oid_desc = { + sizeof(gss_krb5_mech_oid_bytes), + gss_krb5_mech_oid_bytes +}; + +static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc; + +static unsigned char gss_mskrb5_mech_oid_bytes[] = { + 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02 +}; + +static gss_OID_desc gss_mskrb5_mech_oid_desc = { + sizeof(gss_mskrb5_mech_oid_bytes), + gss_mskrb5_mech_oid_bytes +}; + +static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc; + +static unsigned char gss_spnego_mech_oid_bytes[] = { + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 +}; + +static gss_OID_desc gss_spnego_mech_oid_desc = { + sizeof(gss_spnego_mech_oid_bytes), + gss_spnego_mech_oid_bytes +}; + +static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc; + +/* spnegokrb5_locl.h */ + +static OM_uint32 +gssapi_spnego_encapsulate(OM_uint32 *, + unsigned char *, + size_t, + gss_buffer_t, + const gss_OID); + +static OM_uint32 +gssapi_spnego_decapsulate(OM_uint32 *, + gss_buffer_t, + unsigned char **, + size_t *, + const gss_OID); + +/* mod_auth_kerb.c */ + +static int +cmp_gss_type(gss_buffer_t token, gss_OID oid) +{ + unsigned char *p; + size_t len; + + if (token->length == 0) + return (GSS_S_DEFECTIVE_TOKEN); + + p = token->value; + if (*p++ != 0x60) + return (GSS_S_DEFECTIVE_TOKEN); + len = *p++; + if (len & 0x80) { + if ((len & 0x7f) > 4) + return (GSS_S_DEFECTIVE_TOKEN); + p += len & 0x7f; + } + if (*p++ != 0x06) + return (GSS_S_DEFECTIVE_TOKEN); + + if (((OM_uint32) *p++) != oid->length) + return (GSS_S_DEFECTIVE_TOKEN); + + return (memcmp(p, oid->elements, oid->length)); +} + +/* accept_sec_context.c */ +/* + * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly + * based on Heimdal code) + */ + +static OM_uint32 +code_NegTokenArg(OM_uint32 * minor_status, + const NegTokenResp * resp, + unsigned char **outbuf, + size_t * outbuf_size) +{ + OM_uint32 ret; + u_char *buf; + size_t buf_size, buf_len; + + buf_size = 1024; + buf = malloc(buf_size); + if (buf == NULL) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + do { + ret = encode_NegTokenResp(buf + buf_size - 1, + buf_size, + resp, &buf_len); + if (ret == 0) { + size_t tmp; + + ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, + buf_size - buf_len, + buf_len, + ASN1_C_CONTEXT, + CONS, + 1, + &tmp); + if (ret == 0) + buf_len += tmp; + } + if (ret) { + if (ret == ASN1_OVERFLOW) { + u_char *tmp; + + buf_size *= 2; + tmp = realloc(buf, buf_size); + if (tmp == NULL) { + *minor_status = ENOMEM; + free(buf); + return (GSS_S_FAILURE); + } + buf = tmp; + } else { + *minor_status = ret; + free(buf); + return (GSS_S_FAILURE); + } + } + } while (ret == ASN1_OVERFLOW); + + *outbuf = malloc(buf_len); + if (*outbuf == NULL) { + *minor_status = ENOMEM; + free(buf); + return (GSS_S_FAILURE); + } + memcpy(*outbuf, buf + buf_size - buf_len, buf_len); + *outbuf_size = buf_len; + + free(buf); + + return (GSS_S_COMPLETE); +} + +static OM_uint32 +send_reject(OM_uint32 * minor_status, + gss_buffer_t output_token) +{ + NegTokenResp resp; + OM_uint32 ret; + + resp.negState = malloc(sizeof(*resp.negState)); + if (resp.negState == NULL) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + *(resp.negState) = reject; + + resp.supportedMech = NULL; + resp.responseToken = NULL; + resp.mechListMIC = NULL; + + ret = code_NegTokenArg(minor_status, &resp, + (unsigned char **)&output_token->value, + &output_token->length); + free_NegTokenResp(&resp); + if (ret) + return (ret); + + return (GSS_S_BAD_MECH); +} + +static OM_uint32 +send_accept(OM_uint32 * minor_status, + gss_buffer_t output_token, + gss_buffer_t mech_token, + const gss_OID pref) +{ + NegTokenResp resp; + OM_uint32 ret; + + memset(&resp, 0, sizeof(resp)); + resp.negState = malloc(sizeof(*resp.negState)); + if (resp.negState == NULL) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + *(resp.negState) = accept_completed; + + resp.supportedMech = malloc(sizeof(*resp.supportedMech)); + if (resp.supportedMech == NULL) { + free_NegTokenResp(&resp); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + ret = der_get_oid(pref->elements, + pref->length, + resp.supportedMech, + NULL); + if (ret) { + free_NegTokenResp(&resp); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + if (mech_token != NULL && mech_token->length != 0) { + resp.responseToken = malloc(sizeof(*resp.responseToken)); + if (resp.responseToken == NULL) { + free_NegTokenResp(&resp); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + resp.responseToken->length = mech_token->length; + resp.responseToken->data = mech_token->value; + } + + ret = code_NegTokenArg(minor_status, &resp, + (unsigned char **)&output_token->value, + &output_token->length); + if (resp.responseToken != NULL) { + free(resp.responseToken); + resp.responseToken = NULL; + } + free_NegTokenResp(&resp); + if (ret) + return (ret); + + return (GSS_S_COMPLETE); +} + +OM_uint32 +gss_accept_sec_context_spnego(OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) +{ + NegTokenInit init_token; + OM_uint32 major_status; + OM_uint32 minor_status2; + gss_buffer_desc ibuf, obuf; + gss_buffer_t ot = NULL; + gss_OID pref = GSS_KRB5_MECH; + unsigned char *buf; + size_t buf_size; + size_t len, taglen, ni_len; + int found = 0; + int ret; + unsigned i; + + /* + * Before doing anything else, see whether this is a SPNEGO + * PDU. If not, dispatch to the GSSAPI library and get out. + */ + + if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH)) + return (gss_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle)); + + /* + * If we get here, it's SPNEGO. + */ + + memset(&init_token, 0, sizeof(init_token)); + + ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer, + &buf, &buf_size, GSS_SPNEGO_MECH); + if (ret) + return (ret); + + ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS, + 0, &len, &taglen); + if (ret) + return (ret); + + ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len); + if (ret) { + *minor_status = EINVAL; /* XXX */ + return (GSS_S_DEFECTIVE_TOKEN); + } + + for (i = 0; !found && i < init_token.mechTypes.len; ++i) { + char mechbuf[17]; + size_t mech_len; + + ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1, + sizeof(mechbuf), + &init_token.mechTypes.val[i], + &mech_len); + if (ret) + return (GSS_S_DEFECTIVE_TOKEN); + if (mech_len == GSS_KRB5_MECH->length && + memcmp(GSS_KRB5_MECH->elements, + mechbuf + sizeof(mechbuf) - mech_len, + mech_len) == 0) { + found = 1; + break; + } + if (mech_len == GSS_MSKRB5_MECH->length && + memcmp(GSS_MSKRB5_MECH->elements, + mechbuf + sizeof(mechbuf) - mech_len, + mech_len) == 0) { + found = 1; + if (i == 0) + pref = GSS_MSKRB5_MECH; + break; + } + } + + if (!found) + return (send_reject(minor_status, output_token)); + + if (i == 0 && init_token.mechToken != NULL) { + ibuf.length = init_token.mechToken->length; + ibuf.value = init_token.mechToken->data; + + major_status = gss_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + &ibuf, + input_chan_bindings, + src_name, + mech_type, + &obuf, + ret_flags, + time_rec, + delegated_cred_handle); + if (GSS_ERROR(major_status)) { + send_reject(&minor_status2, output_token); + return (major_status); + } + ot = &obuf; + } + ret = send_accept(&minor_status2, output_token, ot, pref); + if (ot != NULL && ot->length != 0) + gss_release_buffer(&minor_status2, ot); + + return (ret); +} + +/* decapsulate.c */ + +static OM_uint32 +gssapi_verify_mech_header(u_char ** str, + size_t total_len, + const gss_OID mech) +{ + size_t len, len_len, mech_len, foo; + int e; + u_char *p = *str; + + if (total_len < 1) + return (GSS_S_DEFECTIVE_TOKEN); + if (*p++ != 0x60) + return (GSS_S_DEFECTIVE_TOKEN); + e = der_get_length(p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return (GSS_S_DEFECTIVE_TOKEN); + p += len_len; + if (*p++ != 0x06) + return (GSS_S_DEFECTIVE_TOKEN); + e = der_get_length(p, total_len - 1 - len_len - 1, + &mech_len, &foo); + if (e) + return (GSS_S_DEFECTIVE_TOKEN); + p += foo; + if (mech_len != mech->length) + return (GSS_S_BAD_MECH); + if (memcmp(p, mech->elements, mech->length) != 0) + return (GSS_S_BAD_MECH); + p += mech_len; + *str = p; + return (GSS_S_COMPLETE); +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does + * not copy data, so just free `in_token'. + */ + +static OM_uint32 +gssapi_spnego_decapsulate(OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + unsigned char **buf, + size_t *buf_len, + const gss_OID mech) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = gssapi_verify_mech_header(&p, + input_token_buffer->length, + mech); + if (ret) { + *minor_status = ret; + return (GSS_S_FAILURE); + } + *buf_len = input_token_buffer->length - + (p - (u_char *) input_token_buffer->value); + *buf = p; + return (GSS_S_COMPLETE); +} + +/* der_free.c */ + +static void +free_octet_string(octet_string *k) +{ + free(k->data); + k->data = NULL; +} + +static void +free_oid(oid *k) +{ + free(k->components); + k->components = NULL; +} + +/* der_get.c */ + +/* + * All decoding functions take a pointer `p' to first position in which to + * read, from the left, `len' which means the maximum number of characters we + * are able to read, `ret' were the value will be returned and `size' where + * the number of used bytes is stored. Either 0 or an error code is returned. + */ + +static int +der_get_unsigned(const unsigned char *p, size_t len, + unsigned *ret, size_t *size) +{ + unsigned val = 0; + size_t oldlen = len; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if (size) + *size = oldlen; + return (0); +} + +static int +der_get_int(const unsigned char *p, size_t len, + int *ret, size_t *size) +{ + int val = 0; + size_t oldlen = len; + + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if (size) + *size = oldlen; + return (0); +} + +static int +der_get_length(const unsigned char *p, size_t len, + size_t *val, size_t *size) +{ + size_t v; + + if (len <= 0) + return (ASN1_OVERRUN); + --len; + v = *p++; + if (v < 128) { + *val = v; + if (size) + *size = 1; + } else { + int e; + size_t l; + unsigned tmp; + + if (v == 0x80) { + *val = ASN1_INDEFINITE; + if (size) + *size = 1; + return (0); + } + v &= 0x7F; + if (len < v) + return (ASN1_OVERRUN); + e = der_get_unsigned(p, v, &tmp, &l); + if (e) + return (e); + *val = tmp; + if (size) + *size = l + 1; + } + return (0); +} + +static int +der_get_octet_string(const unsigned char *p, size_t len, + octet_string *data, size_t *size) +{ + data->length = len; + data->data = malloc(len); + if (data->data == NULL && data->length != 0) + return (ENOMEM); + memcpy(data->data, p, len); + if (size) + *size = len; + return (0); +} + +static int +der_get_oid(const unsigned char *p, size_t len, + oid *data, size_t *size) +{ + int n; + size_t oldlen = len; + + if (len < 1) + return (ASN1_OVERRUN); + + data->components = malloc(len * sizeof(*data->components)); + if (data->components == NULL && len != 0) + return (ENOMEM); + data->components[0] = (*p) / 40; + data->components[1] = (*p) % 40; + --len; + ++p; + for (n = 2; len > 0; ++n) { + unsigned u = 0; + + do { + --len; + u = u * 128 + (*p++ % 128); + } while (len > 0 && p[-1] & 0x80); + data->components[n] = u; + } + if (p[-1] & 0x80) { + free_oid(data); + return (ASN1_OVERRUN); + } + data->length = n; + if (size) + *size = oldlen; + return (0); +} + +static int +der_get_tag(const unsigned char *p, size_t len, + Der_class *class, Der_type *type, + int *tag, size_t *size) +{ + if (len < 1) + return (ASN1_OVERRUN); + *class = (Der_class) (((*p) >> 6) & 0x03); + *type = (Der_type) (((*p) >> 5) & 0x01); + *tag = (*p) & 0x1F; + if (size) + *size = 1; + return (0); +} + +static int +der_match_tag(const unsigned char *p, size_t len, + Der_class class, Der_type type, + int tag, size_t *size) +{ + size_t l; + Der_class thisclass; + Der_type thistype; + int thistag; + int e; + + e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l); + if (e) + return (e); + if (class != thisclass || type != thistype) + return (ASN1_BAD_ID); + if (tag > thistag) + return (ASN1_MISPLACED_FIELD); + if (tag < thistag) + return (ASN1_MISSING_FIELD); + if (size) + *size = l; + return (0); +} + +static int +der_match_tag_and_length(const unsigned char *p, size_t len, + Der_class class, Der_type type, int tag, + size_t *length_ret, size_t *size) +{ + size_t l, ret = 0; + int e; + + e = der_match_tag(p, len, class, type, tag, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, length_ret, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + if (size) + *size = ret; + return (0); +} + +static int +decode_enumerated(const unsigned char *p, size_t len, + unsigned *num, size_t *size) +{ + size_t ret = 0; + size_t l, reallen; + int e; + + e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &reallen, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + e = der_get_int(p, reallen, num, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + if (size) + *size = ret; + return (0); +} + +static int +decode_octet_string(const unsigned char *p, size_t len, + octet_string *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + size_t slen; + + e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + + e = der_get_length(p, len, &slen, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + if (len < slen) + return (ASN1_OVERRUN); + + e = der_get_octet_string(p, slen, k, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + if (size) + *size = ret; + return (0); +} + +static int +decode_oid(const unsigned char *p, size_t len, + oid *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + size_t slen; + + e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + + e = der_get_length(p, len, &slen, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + if (len < slen) + return (ASN1_OVERRUN); + + e = der_get_oid(p, slen, k, &l); + if (e) + return (e); + p += l; + len -= l; + ret += l; + if (size) + *size = ret; + return (0); +} + +static int +fix_dce(size_t reallen, size_t *len) +{ + if (reallen == ASN1_INDEFINITE) + return (1); + if (*len < reallen) + return (-1); + *len = reallen; + return (0); +} + +/* der_length.c */ + +static size_t +len_unsigned(unsigned val) +{ + size_t ret = 0; + + do { + ++ret; + val /= 256; + } while (val); + return (ret); +} + +static size_t +length_len(size_t len) +{ + if (len < 128) + return (1); + else + return (len_unsigned(len) + 1); +} + + +/* der_put.c */ + +/* + * All encoding functions take a pointer `p' to first position in which to + * write, from the right, `len' which means the maximum number of characters + * we are able to write. The function returns the number of characters + * written in `size' (if non-NULL). The return value is 0 or an error. + */ + +static int +der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size) +{ + unsigned char *base = p; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return (ASN1_OVERFLOW); + else { + *size = base - p; + return (0); + } + } else if (len < 1) + return (ASN1_OVERFLOW); + else { + *p = 0; + *size = 1; + return (0); + } +} + +static int +der_put_int(unsigned char *p, size_t len, int val, size_t *size) +{ + unsigned char *base = p; + + if (val >= 0) { + do { + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = val % 256; + len--; + val /= 256; + } while (val); + if (p[1] >= 128) { + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = ~(val % 256); + len--; + val /= 256; + } while (val); + if (p[1] < 128) { + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = 0xff; + len--; + } + } + *size = base - p; + return (0); +} + +static int +der_put_length(unsigned char *p, size_t len, size_t val, size_t *size) +{ + if (len < 1) + return (ASN1_OVERFLOW); + if (val < 128) { + *p = val; + *size = 1; + return (0); + } else { + size_t l; + int e; + + e = der_put_unsigned(p, len - 1, val, &l); + if (e) + return (e); + p -= l; + *p = 0x80 | l; + *size = l + 1; + return (0); + } +} + +static int +der_put_octet_string(unsigned char *p, size_t len, + const octet_string *data, size_t *size) +{ + if (len < data->length) + return (ASN1_OVERFLOW); + p -= data->length; + len -= data->length; + memcpy(p + 1, data->data, data->length); + *size = data->length; + return (0); +} + +static int +der_put_oid(unsigned char *p, size_t len, + const oid *data, size_t *size) +{ + unsigned char *base = p; + int n; + + for (n = data->length - 1; n >= 2; --n) { + unsigned u = data->components[n]; + + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = u % 128; + u /= 128; + --len; + while (u > 0) { + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = 128 + u % 128; + u /= 128; + --len; + } + } + if (len < 1) + return (ASN1_OVERFLOW); + *p-- = 40 * data->components[0] + data->components[1]; + *size = base - p; + return (0); +} + +static int +der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type, + int tag, size_t *size) +{ + if (len < 1) + return (ASN1_OVERFLOW); + *p = (class << 6) | (type << 5) | tag; /* XXX */ + *size = 1; + return (0); +} + +static int +der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val, + Der_class class, Der_type type, int tag, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_length(p, len, len_val, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + e = der_put_tag(p, len, class, type, tag, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + *size = ret; + return (0); +} + +static int +encode_enumerated(unsigned char *p, size_t len, const unsigned *data, + size_t *size) +{ + unsigned num = *data; + size_t ret = 0; + size_t l; + int e; + + e = der_put_int(p, len, num, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + *size = ret; + return (0); +} + +static int +encode_octet_string(unsigned char *p, size_t len, + const octet_string *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_octet_string(p, len, k, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + *size = ret; + return (0); +} + +static int +encode_oid(unsigned char *p, size_t len, + const oid *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_oid(p, len, k, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l); + if (e) + return (e); + p -= l; + len -= l; + ret += l; + *size = ret; + return (0); +} + + +/* encapsulate.c */ + +static void +gssapi_encap_length(size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + size_t len_len; + + *len = 1 + 1 + mech->length + data_len; + + len_len = length_len(*len); + + *total_len = 1 + len_len + *len; +} + +static u_char * +gssapi_mech_make_header(u_char *p, + size_t len, + const gss_OID mech) +{ + int e; + size_t len_len, foo; + + *p++ = 0x60; + len_len = length_len(len); + e = der_put_length(p + len_len - 1, len_len, len, &foo); + if (e || foo != len_len) + return (NULL); + p += len_len; + *p++ = 0x06; + *p++ = mech->length; + memcpy(p, mech->elements, mech->length); + p += mech->length; + return (p); +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. + */ + +static OM_uint32 +gssapi_spnego_encapsulate(OM_uint32 * minor_status, + unsigned char *buf, + size_t buf_size, + gss_buffer_t output_token, + const gss_OID mech) +{ + size_t len, outer_len; + u_char *p; + + gssapi_encap_length(buf_size, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc(outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + p = gssapi_mech_make_header(output_token->value, len, mech); + if (p == NULL) { + if (output_token->length != 0) + gss_release_buffer(minor_status, output_token); + return (GSS_S_FAILURE); + } + memcpy(p, buf, buf_size); + return (GSS_S_COMPLETE); +} + +/* init_sec_context.c */ +/* + * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly + * based on Heimdal code) + */ + +static int +add_mech(MechTypeList * mech_list, gss_OID mech) +{ + MechType *tmp; + int ret; + + tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp)); + if (tmp == NULL) + return (ENOMEM); + mech_list->val = tmp; + + ret = der_get_oid(mech->elements, mech->length, + &mech_list->val[mech_list->len], NULL); + if (ret) + return (ret); + + mech_list->len++; + return (0); +} + +/* + * return the length of the mechanism in token or -1 + * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN + */ + +static ssize_t +gssapi_krb5_get_mech(const u_char *ptr, + size_t total_len, + const u_char **mech_ret) +{ + size_t len, len_len, mech_len, foo; + const u_char *p = ptr; + int e; + + if (total_len < 1) + return (-1); + if (*p++ != 0x60) + return (-1); + e = der_get_length (p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return (-1); + p += len_len; + if (*p++ != 0x06) + return (-1); + e = der_get_length (p, total_len - 1 - len_len - 1, + &mech_len, &foo); + if (e) + return (-1); + p += foo; + *mech_ret = p; + return (mech_len); +} + +static OM_uint32 +spnego_initial(OM_uint32 *minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t *context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + NegTokenInit token_init; + OM_uint32 major_status, minor_status2; + gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER; + unsigned char *buf = NULL; + size_t buf_size; + size_t len; + int ret; + + (void)mech_type; + + memset(&token_init, 0, sizeof(token_init)); + + ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH); + if (ret) { + *minor_status = ret; + ret = GSS_S_FAILURE; + goto end; + } + + major_status = gss_init_sec_context(minor_status, + initiator_cred_handle, + context_handle, + target_name, + GSS_KRB5_MECH, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + &krb5_output_token, + ret_flags, + time_rec); + if (GSS_ERROR(major_status)) { + ret = major_status; + goto end; + } + if (krb5_output_token.length > 0) { + token_init.mechToken = malloc(sizeof(*token_init.mechToken)); + if (token_init.mechToken == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto end; + } + token_init.mechToken->data = krb5_output_token.value; + token_init.mechToken->length = krb5_output_token.length; + } + /* + * The MS implementation of SPNEGO seems to not like the mechListMIC + * field, so we omit it (it's optional anyway) + */ + + buf_size = 1024; + buf = malloc(buf_size); + + do { + ret = encode_NegTokenInit(buf + buf_size - 1, + buf_size, + &token_init, &len); + if (ret == 0) { + size_t tmp; + + ret = der_put_length_and_tag(buf + buf_size - len - 1, + buf_size - len, + len, + ASN1_C_CONTEXT, + CONS, + 0, + &tmp); + if (ret == 0) + len += tmp; + } + if (ret) { + if (ret == ASN1_OVERFLOW) { + u_char *tmp; + + buf_size *= 2; + tmp = realloc(buf, buf_size); + if (tmp == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto end; + } + buf = tmp; + } else { + *minor_status = ret; + ret = GSS_S_FAILURE; + goto end; + } + } + } while (ret == ASN1_OVERFLOW); + + ret = gssapi_spnego_encapsulate(minor_status, + buf + buf_size - len, len, + output_token, GSS_SPNEGO_MECH); + if (ret == GSS_S_COMPLETE) + ret = major_status; + +end: + if (token_init.mechToken != NULL) { + free(token_init.mechToken); + token_init.mechToken = NULL; + } + free_NegTokenInit(&token_init); + if (krb5_output_token.length != 0) + gss_release_buffer(&minor_status2, &krb5_output_token); + if (buf) + free(buf); + + return (ret); +} + +static OM_uint32 +spnego_reply(OM_uint32 *minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t *context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + OM_uint32 ret; + NegTokenResp resp; + unsigned char *buf; + size_t buf_size; + u_char oidbuf[17]; + size_t oidlen; + gss_buffer_desc sub_token; + ssize_t mech_len; + const u_char *p; + size_t len, taglen; + + (void)mech_type; + + output_token->length = 0; + output_token->value = NULL; + + /* + * SPNEGO doesn't include gss wrapping on SubsequentContextToken + * like the Kerberos 5 mech does. But lets check for it anyway. + */ + + mech_len = gssapi_krb5_get_mech(input_token->value, + input_token->length, + &p); + + if (mech_len < 0) { + buf = input_token->value; + buf_size = input_token->length; + } else if ((size_t)mech_len == GSS_KRB5_MECH->length && + memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0) + return (gss_init_sec_context(minor_status, + initiator_cred_handle, + context_handle, + target_name, + GSS_KRB5_MECH, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec)); + else if ((size_t)mech_len == GSS_SPNEGO_MECH->length && + memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) { + ret = gssapi_spnego_decapsulate(minor_status, + input_token, + &buf, + &buf_size, + GSS_SPNEGO_MECH); + if (ret) + return (ret); + } else + return (GSS_S_BAD_MECH); + + ret = der_match_tag_and_length(buf, buf_size, + ASN1_C_CONTEXT, CONS, 1, &len, &taglen); + if (ret) + return (ret); + + if(len > buf_size - taglen) + return (ASN1_OVERRUN); + + ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL); + if (ret) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + if (resp.negState == NULL || + *(resp.negState) == reject || + resp.supportedMech == NULL) { + free_NegTokenResp(&resp); + return (GSS_S_BAD_MECH); + } + + ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1, + sizeof(oidbuf), + resp.supportedMech, + &oidlen); + if (ret || oidlen != GSS_KRB5_MECH->length || + memcmp(oidbuf + sizeof(oidbuf) - oidlen, + GSS_KRB5_MECH->elements, + oidlen) != 0) { + free_NegTokenResp(&resp); + return GSS_S_BAD_MECH; + } + + if (resp.responseToken != NULL) { + sub_token.length = resp.responseToken->length; + sub_token.value = resp.responseToken->data; + } else { + sub_token.length = 0; + sub_token.value = NULL; + } + + ret = gss_init_sec_context(minor_status, + initiator_cred_handle, + context_handle, + target_name, + GSS_KRB5_MECH, + req_flags, + time_req, + input_chan_bindings, + &sub_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + if (ret) { + free_NegTokenResp(&resp); + return (ret); + } + + /* + * XXXSRA I don't think this limited implementation ever needs + * to check the MIC -- our preferred mechanism (Kerberos) + * authenticates its own messages and is the only mechanism + * we'll accept, so if the mechanism negotiation completes + * successfully, we don't need the MIC. See RFC 4178. + */ + + free_NegTokenResp(&resp); + return (ret); +} + + + +OM_uint32 +gss_init_sec_context_spnego(OM_uint32 *minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t *context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + /* Dirty trick to suppress compiler warnings */ + + /* Figure out whether we're starting over or processing a reply */ + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) + return (spnego_initial(minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec)); + else + return (spnego_reply(minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec)); +} + +#endif /* GSSAPI */ diff --git a/lib/dns/spnego.h b/lib/dns/spnego.h new file mode 100644 index 0000000..c44614b --- /dev/null +++ b/lib/dns/spnego.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2006, 2007 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: spnego.h,v 1.4 2007/06/19 23:47:16 tbox Exp $ */ + +/*! \file + * \brief + * Entry points into portable SPNEGO implementation. + * See spnego.c for information on the SPNEGO implementation itself. + */ + +#ifndef _SPNEGO_H_ +#define _SPNEGO_H_ + +/*% + * Wrapper for GSSAPI gss_init_sec_context(), using portable SPNEGO + * implementation instead of the one that's part of the GSSAPI + * library. Takes arguments identical to the standard GSSAPI + * function, uses standard gss_init_sec_context() to handle + * everything inside the SPNEGO wrapper. + */ +OM_uint32 +gss_init_sec_context_spnego(OM_uint32 *, + const gss_cred_id_t, + gss_ctx_id_t *, + const gss_name_t, + const gss_OID, + OM_uint32, + OM_uint32, + const gss_channel_bindings_t, + const gss_buffer_t, + gss_OID *, + gss_buffer_t, + OM_uint32 *, + OM_uint32 *); + +/*% + * Wrapper for GSSAPI gss_accept_sec_context(), using portable SPNEGO + * implementation instead of the one that's part of the GSSAPI + * library. Takes arguments identical to the standard GSSAPI + * function. Checks the OID of the input token to see if it's SPNEGO; + * if so, processes it, otherwise hands the call off to the standard + * gss_accept_sec_context() function. + */ +OM_uint32 gss_accept_sec_context_spnego(OM_uint32 *, + gss_ctx_id_t *, + const gss_cred_id_t, + const gss_buffer_t, + const gss_channel_bindings_t, + gss_name_t *, + gss_OID *, + gss_buffer_t, + OM_uint32 *, + OM_uint32 *, + gss_cred_id_t *); + + +#endif diff --git a/lib/dns/spnego_asn1.c b/lib/dns/spnego_asn1.c new file mode 100644 index 0000000..75c2304 --- /dev/null +++ b/lib/dns/spnego_asn1.c @@ -0,0 +1,885 @@ +/* + * Copyright (C) 2006, 2007 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: spnego_asn1.c,v 1.4 2007/06/19 23:47:16 tbox Exp $ */ + +/*! \file + * \brief Method routines generated from SPNEGO ASN.1 module. + * See spnego_asn1.pl for details. Do not edit. + */ + +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#ifndef __asn1_h__ +#define __asn1_h__ + + +#ifndef __asn1_common_definitions__ +#define __asn1_common_definitions__ + +typedef struct octet_string { + size_t length; + void *data; +} octet_string; + +typedef char *general_string; + +typedef char *utf8_string; + +typedef struct oid { + size_t length; + unsigned *components; +} oid; + +#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \ + do { \ + (BL) = length_##T((S)); \ + (B) = malloc((BL)); \ + if((B) == NULL) { \ + (R) = ENOMEM; \ + } else { \ + (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \ + (S), (L)); \ + if((R) != 0) { \ + free((B)); \ + (B) = NULL; \ + } \ + } \ + } while (0) + +#endif + +/* + * MechType ::= OBJECT IDENTIFIER + */ + +typedef oid MechType; + +static int encode_MechType(unsigned char *, size_t, const MechType *, size_t *); +static int decode_MechType(const unsigned char *, size_t, MechType *, size_t *); +static void free_MechType(MechType *); +/* unused declaration: length_MechType */ +/* unused declaration: copy_MechType */ + + +/* + * MechTypeList ::= SEQUENCE OF MechType + */ + +typedef struct MechTypeList { + unsigned int len; + MechType *val; +} MechTypeList; + +static int encode_MechTypeList(unsigned char *, size_t, const MechTypeList *, size_t *); +static int decode_MechTypeList(const unsigned char *, size_t, MechTypeList *, size_t *); +static void free_MechTypeList(MechTypeList *); +/* unused declaration: length_MechTypeList */ +/* unused declaration: copy_MechTypeList */ + + +/* + * ContextFlags ::= BIT STRING { delegFlag(0), mutualFlag(1), replayFlag(2), + * sequenceFlag(3), anonFlag(4), confFlag(5), integFlag(6) } + */ + +typedef struct ContextFlags { + unsigned int delegFlag:1; + unsigned int mutualFlag:1; + unsigned int replayFlag:1; + unsigned int sequenceFlag:1; + unsigned int anonFlag:1; + unsigned int confFlag:1; + unsigned int integFlag:1; +} ContextFlags; + + +static int encode_ContextFlags(unsigned char *, size_t, const ContextFlags *, size_t *); +static int decode_ContextFlags(const unsigned char *, size_t, ContextFlags *, size_t *); +static void free_ContextFlags(ContextFlags *); +/* unused declaration: length_ContextFlags */ +/* unused declaration: copy_ContextFlags */ +/* unused declaration: ContextFlags2int */ +/* unused declaration: int2ContextFlags */ +/* unused declaration: asn1_ContextFlags_units */ + +/* + * NegTokenInit ::= SEQUENCE { mechTypes[0] MechTypeList, reqFlags[1] + * ContextFlags OPTIONAL, mechToken[2] OCTET STRING OPTIONAL, + * mechListMIC[3] OCTET STRING OPTIONAL } + */ + +typedef struct NegTokenInit { + MechTypeList mechTypes; + ContextFlags *reqFlags; + octet_string *mechToken; + octet_string *mechListMIC; +} NegTokenInit; + +static int encode_NegTokenInit(unsigned char *, size_t, const NegTokenInit *, size_t *); +static int decode_NegTokenInit(const unsigned char *, size_t, NegTokenInit *, size_t *); +static void free_NegTokenInit(NegTokenInit *); +/* unused declaration: length_NegTokenInit */ +/* unused declaration: copy_NegTokenInit */ + + +/* + * NegTokenResp ::= SEQUENCE { negState[0] ENUMERATED { + * accept-completed(0), accept-incomplete(1), reject(2), request-mic(3) } + * OPTIONAL, supportedMech[1] MechType OPTIONAL, responseToken[2] OCTET + * STRING OPTIONAL, mechListMIC[3] OCTET STRING OPTIONAL } + */ + +typedef struct NegTokenResp { + enum { + accept_completed = 0, + accept_incomplete = 1, + reject = 2, + request_mic = 3 + } *negState; + + MechType *supportedMech; + octet_string *responseToken; + octet_string *mechListMIC; +} NegTokenResp; + +static int encode_NegTokenResp(unsigned char *, size_t, const NegTokenResp *, size_t *); +static int decode_NegTokenResp(const unsigned char *, size_t, NegTokenResp *, size_t *); +static void free_NegTokenResp(NegTokenResp *); +/* unused declaration: length_NegTokenResp */ +/* unused declaration: copy_NegTokenResp */ + + + + +#endif /* __asn1_h__ */ +/* Generated from spnego.asn1 */ +/* Do not edit */ + + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +static int +encode_MechType(unsigned char *p, size_t len, const MechType * data, size_t * size) +{ + size_t ret = 0; + size_t l; + int i, e; + + i = 0; + e = encode_oid(p, len, data, &l); + BACK; + *size = ret; + return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +static int +decode_MechType(const unsigned char *p, size_t len, MechType * data, size_t * size) +{ + size_t ret = 0, reallen; + size_t l; + int e; + + memset(data, 0, sizeof(*data)); + reallen = 0; + e = decode_oid(p, len, data, &l); + FORW; + if (size) + *size = ret; + return 0; +fail: + free_MechType(data); + return e; +} + +static void +free_MechType(MechType * data) +{ + free_oid(data); +} + +/* unused function: length_MechType */ + + +/* unused function: copy_MechType */ + +/* Generated from spnego.asn1 */ +/* Do not edit */ + + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +static int +encode_MechTypeList(unsigned char *p, size_t len, const MechTypeList * data, size_t * size) +{ + size_t ret = 0; + size_t l; + int i, e; + + i = 0; + for (i = (data)->len - 1; i >= 0; --i) { + int oldret = ret; + ret = 0; + e = encode_MechType(p, len, &(data)->val[i], &l); + BACK; + ret += oldret; + } + e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l); + BACK; + *size = ret; + return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +static int +decode_MechTypeList(const unsigned char *p, size_t len, MechTypeList * data, size_t * size) +{ + size_t ret = 0, reallen; + size_t l; + int e; + + memset(data, 0, sizeof(*data)); + reallen = 0; + e = der_match_tag_and_length(p, len, ASN1_C_UNIV, CONS, UT_Sequence, &reallen, &l); + FORW; + if (len < reallen) + return ASN1_OVERRUN; + len = reallen; + { + size_t origlen = len; + int oldret = ret; + ret = 0; + (data)->len = 0; + (data)->val = NULL; + while (ret < origlen) { + (data)->len++; + (data)->val = realloc((data)->val, sizeof(*((data)->val)) * (data)->len); + e = decode_MechType(p, len, &(data)->val[(data)->len - 1], &l); + FORW; + len = origlen - ret; + } + ret += oldret; + } + if (size) + *size = ret; + return 0; +fail: + free_MechTypeList(data); + return e; +} + +static void +free_MechTypeList(MechTypeList * data) +{ + while ((data)->len) { + free_MechType(&(data)->val[(data)->len - 1]); + (data)->len--; + } + free((data)->val); + (data)->val = NULL; +} + +/* unused function: length_MechTypeList */ + + +/* unused function: copy_MechTypeList */ + +/* Generated from spnego.asn1 */ +/* Do not edit */ + + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +static int +encode_ContextFlags(unsigned char *p, size_t len, const ContextFlags * data, size_t * size) +{ + size_t ret = 0; + size_t l; + int i, e; + + i = 0; + { + unsigned char c = 0; + *p-- = c; + len--; + ret++; + c = 0; + *p-- = c; + len--; + ret++; + c = 0; + *p-- = c; + len--; + ret++; + c = 0; + if (data->integFlag) + c |= 1 << 1; + if (data->confFlag) + c |= 1 << 2; + if (data->anonFlag) + c |= 1 << 3; + if (data->sequenceFlag) + c |= 1 << 4; + if (data->replayFlag) + c |= 1 << 5; + if (data->mutualFlag) + c |= 1 << 6; + if (data->delegFlag) + c |= 1 << 7; + *p-- = c; + *p-- = 0; + len -= 2; + ret += 2; + } + + e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, PRIM, UT_BitString, &l); + BACK; + *size = ret; + return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +static int +decode_ContextFlags(const unsigned char *p, size_t len, ContextFlags * data, size_t * size) +{ + size_t ret = 0, reallen; + size_t l; + int e; + + memset(data, 0, sizeof(*data)); + reallen = 0; + e = der_match_tag_and_length(p, len, ASN1_C_UNIV, PRIM, UT_BitString, &reallen, &l); + FORW; + if (len < reallen) + return ASN1_OVERRUN; + p++; + len--; + reallen--; + ret++; + data->delegFlag = (*p >> 7) & 1; + data->mutualFlag = (*p >> 6) & 1; + data->replayFlag = (*p >> 5) & 1; + data->sequenceFlag = (*p >> 4) & 1; + data->anonFlag = (*p >> 3) & 1; + data->confFlag = (*p >> 2) & 1; + data->integFlag = (*p >> 1) & 1; + p += reallen; + len -= reallen; + ret += reallen; + if (size) + *size = ret; + return 0; +fail: + free_ContextFlags(data); + return e; +} + +static void +free_ContextFlags(ContextFlags * data) +{ + (void)data; +} + +/* unused function: length_ContextFlags */ + + +/* unused function: copy_ContextFlags */ + + +/* unused function: ContextFlags2int */ + + +/* unused function: int2ContextFlags */ + + +/* unused variable: ContextFlags_units */ + +/* unused function: asn1_ContextFlags_units */ + +/* Generated from spnego.asn1 */ +/* Do not edit */ + + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +static int +encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit * data, size_t * size) +{ + size_t ret = 0; + size_t l; + int i, e; + + i = 0; + if ((data)->mechListMIC) { + int oldret = ret; + ret = 0; + e = encode_octet_string(p, len, (data)->mechListMIC, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 3, &l); + BACK; + ret += oldret; + } + if ((data)->mechToken) { + int oldret = ret; + ret = 0; + e = encode_octet_string(p, len, (data)->mechToken, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 2, &l); + BACK; + ret += oldret; + } + if ((data)->reqFlags) { + int oldret = ret; + ret = 0; + e = encode_ContextFlags(p, len, (data)->reqFlags, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 1, &l); + BACK; + ret += oldret; + } { + int oldret = ret; + ret = 0; + e = encode_MechTypeList(p, len, &(data)->mechTypes, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 0, &l); + BACK; + ret += oldret; + } + e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l); + BACK; + *size = ret; + return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +static int +decode_NegTokenInit(const unsigned char *p, size_t len, NegTokenInit * data, size_t * size) +{ + size_t ret = 0, reallen; + size_t l; + int e; + + memset(data, 0, sizeof(*data)); + reallen = 0; + e = der_match_tag_and_length(p, len, ASN1_C_UNIV, CONS, UT_Sequence, &reallen, &l); + FORW; + { + int dce_fix; + if ((dce_fix = fix_dce(reallen, &len)) < 0) + return ASN1_BAD_FORMAT; + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 0, &l); + if (e) + return e; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + e = decode_MechTypeList(p, len, &(data)->mechTypes, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 1, &l); + if (e) + (data)->reqFlags = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->reqFlags = malloc(sizeof(*(data)->reqFlags)); + if ((data)->reqFlags == NULL) + return ENOMEM; + e = decode_ContextFlags(p, len, (data)->reqFlags, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 2, &l); + if (e) + (data)->mechToken = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->mechToken = malloc(sizeof(*(data)->mechToken)); + if ((data)->mechToken == NULL) + return ENOMEM; + e = decode_octet_string(p, len, (data)->mechToken, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 3, &l); + if (e) + (data)->mechListMIC = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->mechListMIC = malloc(sizeof(*(data)->mechListMIC)); + if ((data)->mechListMIC == NULL) + return ENOMEM; + e = decode_octet_string(p, len, (data)->mechListMIC, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } + } + if (size) + *size = ret; + return 0; +fail: + free_NegTokenInit(data); + return e; +} + +static void +free_NegTokenInit(NegTokenInit * data) +{ + free_MechTypeList(&(data)->mechTypes); + if ((data)->reqFlags) { + free_ContextFlags((data)->reqFlags); + free((data)->reqFlags); + (data)->reqFlags = NULL; + } + if ((data)->mechToken) { + free_octet_string((data)->mechToken); + free((data)->mechToken); + (data)->mechToken = NULL; + } + if ((data)->mechListMIC) { + free_octet_string((data)->mechListMIC); + free((data)->mechListMIC); + (data)->mechListMIC = NULL; + } +} + +/* unused function: length_NegTokenInit */ + + +/* unused function: copy_NegTokenInit */ + +/* Generated from spnego.asn1 */ +/* Do not edit */ + + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +static int +encode_NegTokenResp(unsigned char *p, size_t len, const NegTokenResp * data, size_t * size) +{ + size_t ret = 0; + size_t l; + int i, e; + + i = 0; + if ((data)->mechListMIC) { + int oldret = ret; + ret = 0; + e = encode_octet_string(p, len, (data)->mechListMIC, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 3, &l); + BACK; + ret += oldret; + } + if ((data)->responseToken) { + int oldret = ret; + ret = 0; + e = encode_octet_string(p, len, (data)->responseToken, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 2, &l); + BACK; + ret += oldret; + } + if ((data)->supportedMech) { + int oldret = ret; + ret = 0; + e = encode_MechType(p, len, (data)->supportedMech, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 1, &l); + BACK; + ret += oldret; + } + if ((data)->negState) { + int oldret = ret; + ret = 0; + e = encode_enumerated(p, len, (data)->negState, &l); + BACK; + e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 0, &l); + BACK; + ret += oldret; + } + e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l); + BACK; + *size = ret; + return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +static int +decode_NegTokenResp(const unsigned char *p, size_t len, NegTokenResp * data, size_t * size) +{ + size_t ret = 0, reallen; + size_t l; + int e; + + memset(data, 0, sizeof(*data)); + reallen = 0; + e = der_match_tag_and_length(p, len, ASN1_C_UNIV, CONS, UT_Sequence, &reallen, &l); + FORW; + { + int dce_fix; + if ((dce_fix = fix_dce(reallen, &len)) < 0) + return ASN1_BAD_FORMAT; + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 0, &l); + if (e) + (data)->negState = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->negState = malloc(sizeof(*(data)->negState)); + if ((data)->negState == NULL) + return ENOMEM; + e = decode_enumerated(p, len, (data)->negState, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 1, &l); + if (e) + (data)->supportedMech = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->supportedMech = malloc(sizeof(*(data)->supportedMech)); + if ((data)->supportedMech == NULL) + return ENOMEM; + e = decode_MechType(p, len, (data)->supportedMech, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 2, &l); + if (e) + (data)->responseToken = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->responseToken = malloc(sizeof(*(data)->responseToken)); + if ((data)->responseToken == NULL) + return ENOMEM; + e = decode_octet_string(p, len, (data)->responseToken, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + { + size_t newlen, oldlen; + + e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 3, &l); + if (e) + (data)->mechListMIC = NULL; + else { + p += l; + len -= l; + ret += l; + e = der_get_length(p, len, &newlen, &l); + FORW; + { + int dce_fix; + oldlen = len; + if ((dce_fix = fix_dce(newlen, &len)) < 0) + return ASN1_BAD_FORMAT; + (data)->mechListMIC = malloc(sizeof(*(data)->mechListMIC)); + if ((data)->mechListMIC == NULL) + return ENOMEM; + e = decode_octet_string(p, len, (data)->mechListMIC, &l); + FORW; + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } else + len = oldlen - newlen; + } + } + } + if (dce_fix) { + e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l); + FORW; + } + } + if (size) + *size = ret; + return 0; +fail: + free_NegTokenResp(data); + return e; +} + +static void +free_NegTokenResp(NegTokenResp * data) +{ + if ((data)->negState) { + free((data)->negState); + (data)->negState = NULL; + } + if ((data)->supportedMech) { + free_MechType((data)->supportedMech); + free((data)->supportedMech); + (data)->supportedMech = NULL; + } + if ((data)->responseToken) { + free_octet_string((data)->responseToken); + free((data)->responseToken); + (data)->responseToken = NULL; + } + if ((data)->mechListMIC) { + free_octet_string((data)->mechListMIC); + free((data)->mechListMIC); + (data)->mechListMIC = NULL; + } +} + +/* unused function: length_NegTokenResp */ + + +/* unused function: copy_NegTokenResp */ + +/* Generated from spnego.asn1 */ +/* Do not edit */ + + +/* CHOICE */ +/* unused variable: asn1_NegotiationToken_dummy_holder */ diff --git a/lib/dns/spnego_asn1.pl b/lib/dns/spnego_asn1.pl new file mode 100755 index 0000000..93dd676 --- /dev/null +++ b/lib/dns/spnego_asn1.pl @@ -0,0 +1,200 @@ +#!/bin/bin/perl -w +# +# Copyright (C) 2006, 2007 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: spnego_asn1.pl,v 1.4 2007/06/19 23:47:16 tbox Exp $ + +# Our SPNEGO implementation uses some functions generated by the +# Heimdal ASN.1 compiler, which this script then whacks a bit to make +# them work properly in this stripped down implementation. We don't +# want to require our users to have a copy of the compiler, so we ship +# the output of this script, but we need to keep the script around in +# any case to cope with future changes to the SPNEGO ASN.1 code, so we +# might as well supply the script for users who want it. + +# Overall plan: run the ASN.1 compiler, run each of its output files +# through indent, fix up symbols and whack everything to be static. +# We use indent for two reasons: (1) to whack the Heimdal compiler's +# output into something closer to ISC's coding standard, and (2) to +# make it easier for this script to parse the result. + +# Output from this script is C code which we expect to be #included +# into another C file, which is why everything generated by this +# script is marked "static". The intent is to minimize the number of +# extern symbols exported by the SPNEGO implementation, to avoid +# potential conflicts with the GSSAPI libraries. + +### + +# Filename of the ASN.1 specification. Hardcoded for the moment +# since this script is intended for compiling exactly one module. + +my $asn1_source = $ENV{ASN1_SOURCE} || "spnego.asn1"; + +# Heimdal ASN.1 compiler. This script was written using the version +# from Heimdal 0.7.1. To build this, download a copy of +# heimdal-0.7.1.tar.gz, configure and build with the default options, +# then look for the compiler in heimdal-0.7.1/lib/asn1/asn1_compile. + +my $asn1_compile = $ENV{ASN1_COMPILE} || "asn1_compile"; + +# BSD indent program. This script was written using the version of +# indent that comes with FreeBSD 4.11-STABLE. The GNU project, as +# usual, couldn't resist the temptation to monkey with indent's +# command line syntax, so this probably won't work with GNU indent. + +my $indent = $ENV{INDENT} || "indent"; + +### + +# Step 1: run the compiler. Input is the ASN.1 file. Outputs are a +# header file (name specified on command line without the .h suffix), +# a file called "asn1_files" listing the names of the other output +# files, and a set of files containing C code generated by the +# compiler for each data type that the compiler found. + +if (! -r $asn1_source || system($asn1_compile, $asn1_source, "asn1")) { + die("Couldn't compile ASN.1 source file $asn1_source\n"); +} + +my @files = ("asn1.h"); + +open(F, "asn1_files") + or die("Couldn't open asn1_files: $!\n"); +push(@files, split) + while (<F>); +close(F); + +unlink("asn1_files"); + +### + +# Step 2: generate header block. + +print(q~/* + * Copyright (C) 2006 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: spnego_asn1.pl,v 1.4 2007/06/19 23:47:16 tbox Exp $ */ + +/*! \file + * \brief Method routines generated from SPNEGO ASN.1 module. + * See spnego_asn1.pl for details. Do not edit. + */ + +~); + +### + +# Step 3: read and process each generated file, then delete it. + +my $output; + +for my $file (@files) { + + my $is_static = 0; + + system($indent, "-di1", "-ldi1", $file) == 0 + or die("Couldn't indent $file"); + + unlink("$file.BAK"); + + open(F, $file) + or die("Couldn't open $file: $!"); + + while (<F>) { + + # Symbol name fixups + + s/heim_general_string/general_string/g; + s/heim_octet_string/octet_string/g; + s/heim_oid/oid/g; + s/heim_utf8_string/utf8_string/g; + + # Convert all externs to statics + + if (/^static/) { + $is_static = 1; + } + + if (!/^typedef/ && + !$is_static && + /^[A-Za-z_][0-9A-Za-z_]*[ \t]*($|[^:0-9A-Za-z_])/) { + $_ = "static " . $_; + $is_static = 1; + } + + if (/[{};]/) { + $is_static = 0; + } + + # Suppress file inclusion, pass anything else through + + if (!/#include/) { + $output .= $_; + } + } + + close(F); + unlink($file); +} + +# Step 4: Delete unused stuff to avoid code bloat and compiler warnings. + +my @unused_functions = qw(ContextFlags2int + int2ContextFlags + asn1_ContextFlags_units + length_NegTokenInit + copy_NegTokenInit + length_NegTokenResp + copy_NegTokenResp + length_MechTypeList + length_MechType + copy_MechTypeList + length_ContextFlags + copy_ContextFlags + copy_MechType); + +$output =~ s<^static [^\n]+\n$_\(.+?^}></* unused function: $_ */\n>ms + foreach (@unused_functions); + +$output =~ s<^static .+$_\(.*\);$></* unused declaration: $_ */>m + foreach (@unused_functions); + +$output =~ s<^static struct units ContextFlags_units\[\].+?^};> + </* unused variable: ContextFlags_units */>ms; + +$output =~ s<^static int asn1_NegotiationToken_dummy_holder = 1;> + </* unused variable: asn1_NegotiationToken_dummy_holder */>ms; + +$output =~ s<^static void\nfree_ContextFlags\(ContextFlags \* data\)\n{\n> + <$&\t(void)data;\n>ms; + +# Step 5: Write the result. + +print($output); + diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index fa3011c..ab69242 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -17,7 +17,7 @@ /*! \file */ /* - * $Id: ssu.c,v 1.24.18.4 2006/02/16 23:51:32 marka Exp $ + * $Id: ssu.c,v 1.34 2008/01/18 23:46:58 tbox Exp $ * Principal Author: Brian Wellington */ @@ -25,14 +25,17 @@ #include <isc/magic.h> #include <isc/mem.h> +#include <isc/netaddr.h> #include <isc/result.h> -#include <isc/string.h> /* Required for HP/UX (and others?) */ +#include <isc/string.h> #include <isc/util.h> #include <dns/fixedname.h> #include <dns/name.h> #include <dns/ssu.h> +#include <dst/gssapi.h> + #define SSUTABLEMAGIC ISC_MAGIC('S', 'S', 'U', 'T') #define VALID_SSUTABLE(table) ISC_MAGIC_VALID(table, SSUTABLEMAGIC) @@ -245,50 +248,178 @@ isusertype(dns_rdatatype_t type) { type != dns_rdatatype_rrsig)); } +static void +reverse_from_address(dns_name_t *tcpself, isc_netaddr_t *tcpaddr) { + char buf[16 * 4 + sizeof("IP6.ARPA.")]; + isc_result_t result; + unsigned char *ap; + isc_buffer_t b; + unsigned long l; + + switch (tcpaddr->family) { + case AF_INET: + l = ntohl(tcpaddr->type.in.s_addr); + result = isc_string_printf(buf, sizeof(buf), + "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.", + (l >> 0) & 0xff, (l >> 8) & 0xff, + (l >> 16) & 0xff, (l >> 24) & 0xff); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + break; + case AF_INET6: + ap = tcpaddr->type.in6.s6_addr; + result = isc_string_printf(buf, sizeof(buf), + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x." + "IP6.ARPA.", + ap[15] & 0x0f, (ap[15] >> 4) & 0x0f, + ap[14] & 0x0f, (ap[14] >> 4) & 0x0f, + ap[13] & 0x0f, (ap[13] >> 4) & 0x0f, + ap[12] & 0x0f, (ap[12] >> 4) & 0x0f, + ap[11] & 0x0f, (ap[11] >> 4) & 0x0f, + ap[10] & 0x0f, (ap[10] >> 4) & 0x0f, + ap[9] & 0x0f, (ap[9] >> 4) & 0x0f, + ap[8] & 0x0f, (ap[8] >> 4) & 0x0f, + ap[7] & 0x0f, (ap[7] >> 4) & 0x0f, + ap[6] & 0x0f, (ap[6] >> 4) & 0x0f, + ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, + ap[4] & 0x0f, (ap[4] >> 4) & 0x0f, + ap[3] & 0x0f, (ap[3] >> 4) & 0x0f, + ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, + ap[1] & 0x0f, (ap[1] >> 4) & 0x0f, + ap[0] & 0x0f, (ap[0] >> 4) & 0x0f); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + break; + default: + INSIST(0); + } + isc_buffer_init(&b, buf, strlen(buf)); + isc_buffer_add(&b, strlen(buf)); + result = dns_name_fromtext(tcpself, &b, dns_rootname, 0, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); +} + +static void +stf_from_address(dns_name_t *stfself, isc_netaddr_t *tcpaddr) { + char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")]; + isc_result_t result; + unsigned char *ap; + isc_buffer_t b; + unsigned long l; + + switch(tcpaddr->family) { + case AF_INET: + l = ntohl(tcpaddr->type.in.s_addr); + result = isc_string_printf(buf, sizeof(buf), + "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx" + "2.0.0.2.IP6.ARPA.", + l & 0xf, (l >> 4) & 0xf, + (l >> 8) & 0xf, (l >> 12) & 0xf, + (l >> 16) & 0xf, (l >> 20) & 0xf, + (l >> 24) & 0xf, (l >> 28) & 0xf); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + break; + case AF_INET6: + ap = tcpaddr->type.in6.s6_addr; + result = isc_string_printf(buf, sizeof(buf), + "%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.IP6.ARPA.", + ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, + ap[4] & 0x0f, (ap[4] >> 4) & 0x0f, + ap[3] & 0x0f, (ap[3] >> 4) & 0x0f, + ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, + ap[1] & 0x0f, (ap[1] >> 4) & 0x0f, + ap[0] & 0x0f, (ap[0] >> 4) & 0x0f); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + break; + default: + INSIST(0); + } + isc_buffer_init(&b, buf, strlen(buf)); + isc_buffer_add(&b, strlen(buf)); + result = dns_name_fromtext(stfself, &b, dns_rootname, 0, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); +} + isc_boolean_t dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer, - dns_name_t *name, dns_rdatatype_t type) + dns_name_t *name, isc_netaddr_t *tcpaddr, + dns_rdatatype_t type) { dns_ssurule_t *rule; unsigned int i; dns_fixedname_t fixed; dns_name_t *wildcard; + dns_name_t *tcpself; + dns_name_t *stfself; isc_result_t result; REQUIRE(VALID_SSUTABLE(table)); REQUIRE(signer == NULL || dns_name_isabsolute(signer)); REQUIRE(dns_name_isabsolute(name)); - if (signer == NULL) + if (signer == NULL && tcpaddr == NULL) return (ISC_FALSE); - rule = ISC_LIST_HEAD(table->rules); - rule = ISC_LIST_NEXT(rule, link); + for (rule = ISC_LIST_HEAD(table->rules); rule != NULL; rule = ISC_LIST_NEXT(rule, link)) { - if (dns_name_iswildcard(rule->identity)) { - if (!dns_name_matcheswildcard(signer, rule->identity)) + switch (rule->matchtype) { + case DNS_SSUMATCHTYPE_NAME: + case DNS_SSUMATCHTYPE_SUBDOMAIN: + case DNS_SSUMATCHTYPE_WILDCARD: + case DNS_SSUMATCHTYPE_SELF: + case DNS_SSUMATCHTYPE_SELFSUB: + case DNS_SSUMATCHTYPE_SELFWILD: + if (signer == NULL) continue; - } else if (!dns_name_equal(signer, rule->identity)) + if (dns_name_iswildcard(rule->identity)) { + if (!dns_name_matcheswildcard(signer, + rule->identity)) + continue; + } else { + if (!dns_name_equal(signer, rule->identity)) + continue; + } + break; + case DNS_SSUMATCHTYPE_SELFKRB5: + case DNS_SSUMATCHTYPE_SELFMS: + case DNS_SSUMATCHTYPE_SUBDOMAINKRB5: + case DNS_SSUMATCHTYPE_SUBDOMAINMS: + if (signer == NULL) continue; + break; + case DNS_SSUMATCHTYPE_TCPSELF: + case DNS_SSUMATCHTYPE_6TO4SELF: + if (tcpaddr == NULL) + continue; + break; + } - if (rule->matchtype == DNS_SSUMATCHTYPE_NAME) { + switch (rule->matchtype) { + case DNS_SSUMATCHTYPE_NAME: if (!dns_name_equal(name, rule->name)) continue; - } else if (rule->matchtype == DNS_SSUMATCHTYPE_SUBDOMAIN) { + break; + case DNS_SSUMATCHTYPE_SUBDOMAIN: if (!dns_name_issubdomain(name, rule->name)) continue; - } else if (rule->matchtype == DNS_SSUMATCHTYPE_WILDCARD) { + break; + case DNS_SSUMATCHTYPE_WILDCARD: if (!dns_name_matcheswildcard(name, rule->name)) continue; - } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELF) { + break; + case DNS_SSUMATCHTYPE_SELF: if (!dns_name_equal(signer, name)) continue; - } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELFSUB) { + break; + case DNS_SSUMATCHTYPE_SELFSUB: if (!dns_name_issubdomain(name, signer)) continue; - } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELFWILD) { + break; + case DNS_SSUMATCHTYPE_SELFWILD: dns_fixedname_init(&fixed); wildcard = dns_fixedname_name(&fixed); result = dns_name_concatenate(dns_wildcardname, signer, @@ -297,6 +428,61 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer, continue; if (!dns_name_matcheswildcard(name, wildcard)) continue; + break; + case DNS_SSUMATCHTYPE_SELFKRB5: + if (!dst_gssapi_identitymatchesrealmkrb5(signer, name, + rule->identity)) + continue; + break; + case DNS_SSUMATCHTYPE_SELFMS: + if (!dst_gssapi_identitymatchesrealmms(signer, name, + rule->identity)) + continue; + break; + case DNS_SSUMATCHTYPE_SUBDOMAINKRB5: + if (!dns_name_issubdomain(name, rule->name)) + continue; + if (!dst_gssapi_identitymatchesrealmkrb5(signer, NULL, + rule->identity)) + continue; + break; + case DNS_SSUMATCHTYPE_SUBDOMAINMS: + if (!dns_name_issubdomain(name, rule->name)) + continue; + if (!dst_gssapi_identitymatchesrealmms(signer, NULL, + rule->identity)) + continue; + break; + case DNS_SSUMATCHTYPE_TCPSELF: + dns_fixedname_init(&fixed); + tcpself = dns_fixedname_name(&fixed); + reverse_from_address(tcpself, tcpaddr); + if (dns_name_iswildcard(rule->identity)) { + if (!dns_name_matcheswildcard(tcpself, + rule->identity)) + continue; + } else { + if (!dns_name_equal(tcpself, rule->identity)) + continue; + } + if (!dns_name_equal(tcpself, name)) + continue; + break; + case DNS_SSUMATCHTYPE_6TO4SELF: + dns_fixedname_init(&fixed); + stfself = dns_fixedname_name(&fixed); + stf_from_address(stfself, tcpaddr); + if (dns_name_iswildcard(rule->identity)) { + if (!dns_name_matcheswildcard(stfself, + rule->identity)) + continue; + } else { + if (!dns_name_equal(stfself, rule->identity)) + continue; + } + if (!dns_name_equal(stfself, name)) + continue; + break; } if (rule->ntypes == 0) { diff --git a/lib/dns/stats.c b/lib/dns/stats.c index 660046f..60fed35 100644 --- a/lib/dns/stats.c +++ b/lib/dns/stats.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,16 +15,363 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.c,v 1.6.18.4 2005/06/27 00:20:02 marka Exp $ */ +/* $Id: stats.c,v 1.16.118.2 2009/01/29 23:47:44 tbox Exp $ */ /*! \file */ #include <config.h> +#include <isc/magic.h> #include <isc/mem.h> +#include <isc/stats.h> +#include <isc/util.h> +#include <dns/opcode.h> +#include <dns/rdatatype.h> #include <dns/stats.h> +#define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't') +#define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC) + +/*% + * Statistics types. + */ +typedef enum { + dns_statstype_general = 0, + dns_statstype_rdtype = 1, + dns_statstype_rdataset = 2, + dns_statstype_opcode = 3 +} dns_statstype_t; + +/*% + * It doesn't make sense to have 2^16 counters for all possible types since + * most of them won't be used. We have counters for the first 256 types and + * those explicitly supported in the rdata implementation. + * XXXJT: this introduces tight coupling with the rdata implementation. + * Ideally, we should have rdata handle this type of details. + */ +enum { + /* For 0-255, we use the rdtype value as counter indices */ + rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */ + rdtypecounter_others = 257, /* anything else */ + rdtypecounter_max = 258, + /* The following are used for rdataset */ + rdtypenxcounter_max = rdtypecounter_max * 2, + rdtypecounter_nxdomain = rdtypenxcounter_max, + rdatasettypecounter_max = rdtypecounter_nxdomain + 1 +}; + +struct dns_stats { + /*% Unlocked */ + unsigned int magic; + dns_statstype_t type; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_stats_t *counters; + + /*% Locked by lock */ + unsigned int references; +}; + +typedef struct rdatadumparg { + dns_rdatatypestats_dumper_t fn; + void *arg; +} rdatadumparg_t; + +typedef struct opcodedumparg { + dns_opcodestats_dumper_t fn; + void *arg; +} opcodedumparg_t; + +void +dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) { + REQUIRE(DNS_STATS_VALID(stats)); + REQUIRE(statsp != NULL && *statsp == NULL); + + LOCK(&stats->lock); + stats->references++; + UNLOCK(&stats->lock); + + *statsp = stats; +} + +void +dns_stats_detach(dns_stats_t **statsp) { + dns_stats_t *stats; + + REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp)); + + stats = *statsp; + *statsp = NULL; + + LOCK(&stats->lock); + stats->references--; + UNLOCK(&stats->lock); + + if (stats->references == 0) { + isc_stats_detach(&stats->counters); + DESTROYLOCK(&stats->lock); + isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); + } +} + +/*% + * Create methods + */ +static isc_result_t +create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, + dns_stats_t **statsp) +{ + dns_stats_t *stats; + isc_result_t result; + + stats = isc_mem_get(mctx, sizeof(*stats)); + if (stats == NULL) + return (ISC_R_NOMEMORY); + + stats->counters = NULL; + stats->references = 1; + + result = isc_mutex_init(&stats->lock); + if (result != ISC_R_SUCCESS) + goto clean_stats; + + result = isc_stats_create(mctx, &stats->counters, ncounters); + if (result != ISC_R_SUCCESS) + goto clean_mutex; + + stats->magic = DNS_STATS_MAGIC; + stats->type = type; + stats->mctx = NULL; + isc_mem_attach(mctx, &stats->mctx); + *statsp = stats; + + return (ISC_R_SUCCESS); + + clean_mutex: + DESTROYLOCK(&stats->lock); + clean_stats: + isc_mem_put(mctx, stats, sizeof(*stats)); + + return (result); +} + +isc_result_t +dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_general, ncounters, statsp)); +} + +isc_result_t +dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_rdtype, rdtypecounter_max, + statsp)); +} + +isc_result_t +dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_rdataset, + (rdtypecounter_max * 2) + 1, statsp)); +} + +isc_result_t +dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_opcode, 16, statsp)); +} + +/*% + * Increment/Decrement methods + */ +void +dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter) { + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); + + isc_stats_increment(stats->counters, counter); +} + +void +dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) { + int counter; + + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); + + if (type == dns_rdatatype_dlv) + counter = rdtypecounter_dlv; + else if (type > dns_rdatatype_any) + counter = rdtypecounter_others; + else + counter = (int)type; + + isc_stats_increment(stats->counters, (isc_statscounter_t)counter); +} + +static inline void +update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype, + isc_boolean_t increment) +{ + int counter; + dns_rdatatype_t rdtype; + + if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & + DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) { + counter = rdtypecounter_nxdomain; + } else { + rdtype = DNS_RDATASTATSTYPE_BASE(rrsettype); + if (rdtype == dns_rdatatype_dlv) + counter = (int)rdtypecounter_dlv; + else if (rdtype > dns_rdatatype_any) + counter = (int)rdtypecounter_others; + else + counter = (int)rdtype; + + if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & + DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0) + counter += rdtypecounter_max; + } + + if (increment) + isc_stats_increment(stats->counters, counter); + else + isc_stats_decrement(stats->counters, counter); +} + +void +dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) +{ + REQUIRE(DNS_STATS_VALID(stats) && + stats->type == dns_statstype_rdataset); + + update_rdatasetstats(stats, rrsettype, ISC_TRUE); +} + +void +dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) +{ + REQUIRE(DNS_STATS_VALID(stats) && + stats->type == dns_statstype_rdataset); + + update_rdatasetstats(stats, rrsettype, ISC_FALSE); +} +void +dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) { + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); + + isc_stats_increment(stats->counters, (isc_statscounter_t)code); +} + +/*% + * Dump methods + */ +void +dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, + void *arg, unsigned int options) +{ + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); + + isc_stats_dump(stats->counters, (isc_stats_dumper_t)dump_fn, + arg, options); +} + +static void +dump_rdentry(int rdcounter, isc_uint64_t value, dns_rdatastatstype_t attributes, + dns_rdatatypestats_dumper_t dump_fn, void * arg) +{ + dns_rdatatype_t rdtype = dns_rdatatype_none; /* sentinel */ + dns_rdatastatstype_t type; + + if (rdcounter == rdtypecounter_others) + attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE; + else { + if (rdcounter == rdtypecounter_dlv) + rdtype = dns_rdatatype_dlv; + else + rdtype = (dns_rdatatype_t)rdcounter; + } + type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype, + attributes); + dump_fn(type, value, arg); +} + +static void +rdatatype_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { + rdatadumparg_t *rdatadumparg = arg; + + dump_rdentry(counter, value, 0, rdatadumparg->fn, rdatadumparg->arg); +} + +void +dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg0, unsigned int options) +{ + rdatadumparg_t arg; + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); + + arg.fn = dump_fn; + arg.arg = arg0; + isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options); +} + +static void +rdataset_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { + rdatadumparg_t *rdatadumparg = arg; + + if (counter < rdtypecounter_max) { + dump_rdentry(counter, value, 0, rdatadumparg->fn, + rdatadumparg->arg); + } else if (counter < rdtypenxcounter_max) { + dump_rdentry(counter - rdtypecounter_max, value, + DNS_RDATASTATSTYPE_ATTR_NXRRSET, + rdatadumparg->fn, rdatadumparg->arg); + } else { + dump_rdentry(0, value, DNS_RDATASTATSTYPE_ATTR_NXDOMAIN, + rdatadumparg->fn, rdatadumparg->arg); + } +} + +void +dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg0, unsigned int options) +{ + rdatadumparg_t arg; + + REQUIRE(DNS_STATS_VALID(stats) && + stats->type == dns_statstype_rdataset); + + arg.fn = dump_fn; + arg.arg = arg0; + isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options); +} + +static void +opcode_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { + opcodedumparg_t *opcodearg = arg; + + opcodearg->fn((dns_opcode_t)counter, value, opcodearg->arg); +} + +void +dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, + void *arg0, unsigned int options) +{ + opcodedumparg_t arg; + + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); + + arg.fn = dump_fn; + arg.arg = arg0; + isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options); +} + +/*** + *** Obsolete variables and functions follow: + ***/ LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] = { "success", diff --git a/lib/dns/tcpmsg.c b/lib/dns/tcpmsg.c index 018c4ce..49add56 100644 --- a/lib/dns/tcpmsg.c +++ b/lib/dns/tcpmsg.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tcpmsg.c,v 1.25.18.4 2006/08/10 23:59:29 marka Exp $ */ +/* $Id: tcpmsg.c,v 1.31 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/time.c b/lib/dns/time.c index b4e7bee..62414dd 100644 --- a/lib/dns/time.c +++ b/lib/dns/time.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: time.c,v 1.26.18.3 2005/04/29 00:16:06 marka Exp $ */ +/* $Id: time.c,v 1.31.332.2 2009/01/18 23:47:40 tbox Exp $ */ /*! \file */ @@ -145,7 +145,7 @@ dns_time64_fromtext(const char *source, isc_int64_t *target) { RANGE(0, 60, second); /* 60 == leap second. */ /* - * Calulate seconds since epoch. + * Calculate seconds since epoch. */ value = second + (60 * minute) + (3600 * hour) + ((day - 1) * 86400); for (i = 0; i < (month - 1); i++) diff --git a/lib/dns/timer.c b/lib/dns/timer.c index b225722..39e4551 100644 --- a/lib/dns/timer.c +++ b/lib/dns/timer.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: timer.c,v 1.3.18.2 2005/04/29 00:16:06 marka Exp $ */ +/* $Id: timer.c,v 1.7 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index 998ea36..9e59dfa 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +16,7 @@ */ /* - * $Id: tkey.c,v 1.76.18.7 2008/01/02 23:46:02 tbox Exp $ + * $Id: tkey.c,v 1.90 2008/04/03 00:45:23 marka Exp $ */ /*! \file */ #include <config.h> @@ -66,6 +66,20 @@ tkey_log(const char *fmt, ...) { va_end(ap); } +static void +_dns_tkey_dumpmessage(dns_message_t *msg) { + isc_buffer_t outbuf; + unsigned char output[4096]; + isc_result_t result; + + isc_buffer_init(&outbuf, output, sizeof(output)); + result = dns_message_totext(msg, &dns_master_style_debug, 0, + &outbuf); + /* XXXMLG ignore result */ + fprintf(stderr, "%.*s\n", (int)isc_buffer_usedlength(&outbuf), + (char *)isc_buffer_base(&outbuf)); +} + isc_result_t dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp) { @@ -107,6 +121,8 @@ dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) { dns_name_free(tctx->domain, mctx); isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t)); } + if (tctx->gsscred != NULL) + dst_gssapi_releasecred(&tctx->gsscred); isc_entropy_detach(&tctx->ectx); isc_mem_put(mctx, tctx, sizeof(dns_tkeyctx_t)); isc_mem_detach(&mctx); @@ -280,8 +296,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, */ for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL); result == ISC_R_SUCCESS && !found_key; - result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) - { + result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) { keyname = NULL; dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname); keyset = NULL; @@ -292,8 +307,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, for (result = dns_rdataset_first(keyset); result == ISC_R_SUCCESS && !found_key; - result = dns_rdataset_next(keyset)) - { + result = dns_rdataset_next(keyset)) { dns_rdataset_current(keyset, &keyrdata); pubkey = NULL; result = dns_dnssec_keyfromrdata(keyname, &keyrdata, @@ -410,13 +424,15 @@ process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, { isc_result_t result = ISC_R_SUCCESS; dst_key_t *dstkey = NULL; - void *gssctx = NULL; + dns_tsigkey_t *tsigkey = NULL; + dns_fixedname_t principal; isc_stdtime_t now; isc_region_t intoken; - unsigned char array[1024]; - isc_buffer_t outtoken; + isc_buffer_t *outtoken = NULL; + gss_ctx_id_t gss_ctx = NULL; UNUSED(namelist); + UNUSED(signer); if (tctx->gsscred == NULL) return (ISC_R_NOPERM); @@ -424,55 +440,95 @@ process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkeyout->error = dns_tsigerror_badalg; + tkey_log("process_gsstkey(): dns_tsigerror_badalg"); /* XXXSRA */ return (ISC_R_SUCCESS); } + /* + * XXXDCL need to check for key expiry per 4.1.1 + * XXXDCL need a way to check fully established, perhaps w/key_flags + */ + intoken.base = tkeyin->key; intoken.length = tkeyin->keylen; - isc_buffer_init(&outtoken, array, sizeof(array)); - RETERR(dst_gssapi_acceptctx(name, tctx->gsscred, &intoken, - &outtoken, &gssctx)); + result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); + if (result == ISC_R_SUCCESS) + gss_ctx = dst_key_getgssctx(tsigkey->key); - dstkey = NULL; - RETERR(dst_key_fromgssapi(name, gssctx, msg->mctx, &dstkey)); - result = dns_tsigkey_createfromkey(name, &tkeyin->algorithm, - dstkey, ISC_TRUE, signer, - tkeyin->inception, tkeyin->expire, - ring->mctx, ring, NULL); -#if 1 - if (result != ISC_R_SUCCESS) - goto failure; -#else - if (result == ISC_R_NOTFOUND) { - tkeyout->error = dns_tsigerror_badalg; + dns_fixedname_init(&principal); + + result = dst_gssapi_acceptctx(tctx->gsscred, &intoken, + &outtoken, &gss_ctx, + dns_fixedname_name(&principal), + tctx->mctx); + + if (tsigkey != NULL) + dns_tsigkey_detach(&tsigkey); + + if (result == DNS_R_INVALIDTKEY) { + tkeyout->error = dns_tsigerror_badkey; + tkey_log("process_gsstkey(): dns_tsigerror_badkey"); /* XXXSRA */ return (ISC_R_SUCCESS); - } - if (result != ISC_R_SUCCESS) + } else if (result == ISC_R_FAILURE) goto failure; -#endif + ENSURE(result == DNS_R_CONTINUE || result == ISC_R_SUCCESS); + /* + * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times. + */ + + if (tsigkey == NULL) { + RETERR(dst_key_fromgssapi(name, gss_ctx, msg->mctx, &dstkey)); + RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm, + dstkey, ISC_TRUE, + dns_fixedname_name(&principal), + tkeyin->inception, + tkeyin->expire, + ring->mctx, ring, NULL)); + } - /* This key is good for a long time */ isc_stdtime_get(&now); tkeyout->inception = tkeyin->inception; tkeyout->expire = tkeyin->expire; - tkeyout->key = isc_mem_get(msg->mctx, - isc_buffer_usedlength(&outtoken)); - if (tkeyout->key == NULL) { - result = ISC_R_NOMEMORY; - goto failure; + if (outtoken) { + tkeyout->key = isc_mem_get(tkeyout->mctx, + isc_buffer_usedlength(outtoken)); + if (tkeyout->key == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + tkeyout->keylen = isc_buffer_usedlength(outtoken); + memcpy(tkeyout->key, isc_buffer_base(outtoken), + isc_buffer_usedlength(outtoken)); + isc_buffer_free(&outtoken); + } else { + tkeyout->key = isc_mem_get(tkeyout->mctx, tkeyin->keylen); + if (tkeyout->key == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + tkeyout->keylen = tkeyin->keylen; + memcpy(tkeyout->key, tkeyin->key, tkeyin->keylen); } - tkeyout->keylen = isc_buffer_usedlength(&outtoken); - memcpy(tkeyout->key, isc_buffer_base(&outtoken), tkeyout->keylen); + + tkeyout->error = dns_rcode_noerror; + + tkey_log("process_gsstkey(): dns_tsigerror_noerror"); /* XXXSRA */ return (ISC_R_SUCCESS); - failure: +failure: if (dstkey != NULL) dst_key_free(&dstkey); + if (outtoken != NULL) + isc_buffer_free(&outtoken); + + tkey_log("process_gsstkey(): %s", + isc_result_totext(result)); /* XXXSRA */ + return (result); } @@ -564,8 +620,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, */ if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname, dns_rdatatype_tkey, 0, &name, - &tkeyset) != ISC_R_SUCCESS) - { + &tkeyset) != ISC_R_SUCCESS) { result = DNS_R_FORMERR; tkey_log("dns_tkey_processquery: couldn't find a TKEY " "matching the question"); @@ -632,7 +687,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, if (tkeyin.mode != DNS_TKEYMODE_DELETE) { dns_tsigkey_t *tsigkey = NULL; - if (tctx->domain == NULL) { + if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) { tkey_log("dns_tkey_processquery: tkey-domain not set"); result = DNS_R_REFUSED; goto failure; @@ -674,12 +729,22 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, if (result != ISC_R_SUCCESS) goto failure; } - result = dns_name_concatenate(keyname, tctx->domain, - keyname, NULL); - if (result != ISC_R_SUCCESS) - goto failure; + + if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) { + /* Yup. This is a hack */ + result = dns_name_concatenate(keyname, dns_rootname, + keyname, NULL); + if (result != ISC_R_SUCCESS) + goto failure; + } else { + result = dns_name_concatenate(keyname, tctx->domain, + keyname, NULL); + if (result != ISC_R_SUCCESS) + goto failure; + } result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); + if (result == ISC_R_SUCCESS) { tkeyout.error = dns_tsigerror_badname; dns_tsigkey_detach(&tsigkey); @@ -701,6 +766,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, RETERR(process_gsstkey(msg, signer, keyname, &tkeyin, tctx, &tkeyout, ring, &namelist)); + break; case DNS_TKEYMODE_DELETE: tkeyout.error = dns_rcode_noerror; @@ -729,9 +795,9 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, } if (tkeyout.key != NULL) - isc_mem_put(msg->mctx, tkeyout.key, tkeyout.keylen); + isc_mem_put(tkeyout.mctx, tkeyout.key, tkeyout.keylen); if (tkeyout.other != NULL) - isc_mem_put(msg->mctx, tkeyout.other, tkeyout.otherlen); + isc_mem_put(tkeyout.mctx, tkeyout.other, tkeyout.otherlen); if (result != ISC_R_SUCCESS) goto failure; @@ -759,7 +825,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, static isc_result_t buildquery(dns_message_t *msg, dns_name_t *name, - dns_rdata_tkey_t *tkey) + dns_rdata_tkey_t *tkey, isc_boolean_t win2k) { dns_name_t *qname = NULL, *aname = NULL; dns_rdataset_t *question = NULL, *tkeyset = NULL; @@ -780,8 +846,9 @@ buildquery(dns_message_t *msg, dns_name_t *name, dns_rdataset_makequestion(question, dns_rdataclass_any, dns_rdatatype_tkey); - RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 512)); + RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 4096)); RETERR(dns_message_gettemprdata(msg, &rdata)); + RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, dns_rdatatype_tkey, tkey, dynbuf)); dns_message_takebuffer(msg, &dynbuf); @@ -808,7 +875,15 @@ buildquery(dns_message_t *msg, dns_name_t *name, ISC_LIST_APPEND(aname->list, tkeyset, link); dns_message_addname(msg, qname, DNS_SECTION_QUESTION); - dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL); + + /* + * Windows 2000 needs this in the answer section, not the additional + * section where the RFC specifies. + */ + if (win2k) + dns_message_addname(msg, aname, DNS_SECTION_ANSWER); + else + dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL); return (ISC_R_SUCCESS); @@ -823,6 +898,7 @@ buildquery(dns_message_t *msg, dns_name_t *name, } if (dynbuf != NULL) isc_buffer_free(&dynbuf); + printf("buildquery error\n"); return (result); } @@ -869,7 +945,7 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, tkey.other = NULL; tkey.otherlen = 0; - RETERR(buildquery(msg, name, &tkey)); + RETERR(buildquery(msg, name, &tkey, ISC_FALSE)); if (nonce == NULL) isc_mem_put(msg->mctx, r.base, 0); @@ -900,23 +976,25 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, } isc_result_t -dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, - dns_name_t *gname, void *cred, - isc_uint32_t lifetime, void **context) +dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, + isc_buffer_t *intoken, isc_uint32_t lifetime, + gss_ctx_id_t *context, isc_boolean_t win2k) { dns_rdata_tkey_t tkey; isc_result_t result; isc_stdtime_t now; isc_buffer_t token; - unsigned char array[1024]; + unsigned char array[4096]; + + UNUSED(intoken); REQUIRE(msg != NULL); REQUIRE(name != NULL); REQUIRE(gname != NULL); - REQUIRE(context != NULL && *context == NULL); + REQUIRE(context != NULL); isc_buffer_init(&token, array, sizeof(array)); - result = dst_gssapi_initctx(gname, cred, NULL, &token, context); + result = dst_gssapi_initctx(gname, NULL, &token, context); if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) return (result); @@ -925,7 +1003,12 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, ISC_LINK_INIT(&tkey.common, link); tkey.mctx = NULL; dns_name_init(&tkey.algorithm, NULL); - dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); + + if (win2k) + dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); + else + dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); + isc_stdtime_get(&now); tkey.inception = now; tkey.expire = now + lifetime; @@ -936,7 +1019,7 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, tkey.other = NULL; tkey.otherlen = 0; - RETERR(buildquery(msg, name, &tkey)); + RETERR(buildquery(msg, name, &tkey, win2k)); return (ISC_R_SUCCESS); @@ -963,7 +1046,7 @@ dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) { tkey.keylen = tkey.otherlen = 0; tkey.key = tkey.other = NULL; - return (buildquery(msg, &key->name, &tkey)); + return (buildquery(msg, &key->name, &tkey, ISC_FALSE)); } static isc_result_t @@ -1034,10 +1117,9 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN || rtkey.mode != qtkey.mode || !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || - rmsg->rcode != dns_rcode_noerror) - { + rmsg->rcode != dns_rcode_noerror) { tkey_log("dns_tkey_processdhresponse: tkey mode invalid " - "or error set"); + "or error set(1)"); result = DNS_R_INVALIDTKEY; dns_rdata_freestruct(&qtkey); goto failure; @@ -1106,7 +1188,7 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, result = dns_tsigkey_create(tkeyname, &rtkey.algorithm, r.base, r.length, ISC_TRUE, NULL, rtkey.inception, rtkey.expire, - ring->mctx, ring, outkey); + rmsg->mctx, ring, outkey); isc_buffer_free(&shared); dns_rdata_freestruct(&rtkey); dst_key_free(&theirkey); @@ -1127,18 +1209,19 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, isc_result_t dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, - dns_name_t *gname, void *cred, void **context, - dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring) + dns_name_t *gname, gss_ctx_id_t *context, + isc_buffer_t *outtoken, dns_tsigkey_t **outkey, + dns_tsig_keyring_t *ring) { dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; dns_name_t *tkeyname; dns_rdata_tkey_t rtkey, qtkey; - isc_buffer_t outtoken; dst_key_t *dstkey = NULL; - isc_region_t r; + isc_buffer_t intoken; isc_result_t result; unsigned char array[1024]; + REQUIRE(outtoken != NULL); REQUIRE(qmsg != NULL); REQUIRE(rmsg != NULL); REQUIRE(gname != NULL); @@ -1150,31 +1233,42 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); - RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, - DNS_SECTION_ADDITIONAL)); + /* + * Win2k puts the item in the ANSWER section, while the RFC + * specifies it should be in the ADDITIONAL section. Check first + * where it should be, and then where it may be. + */ + result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, + DNS_SECTION_ADDITIONAL); + if (result == ISC_R_NOTFOUND) + result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, + DNS_SECTION_ANSWER); + if (result != ISC_R_SUCCESS) + goto failure; + RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); if (rtkey.error != dns_rcode_noerror || rtkey.mode != DNS_TKEYMODE_GSSAPI || - !dns_name_equal(&rtkey.algorithm, &rtkey.algorithm)) - { - tkey_log("dns_tkey_processdhresponse: tkey mode invalid " - "or error set"); + !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) { + tkey_log("dns_tkey_processgssresponse: tkey mode invalid " + "or error set(2) %d", rtkey.error); + _dns_tkey_dumpmessage(qmsg); + _dns_tkey_dumpmessage(rmsg); result = DNS_R_INVALIDTKEY; goto failure; } - isc_buffer_init(&outtoken, array, sizeof(array)); - r.base = rtkey.key; - r.length = rtkey.keylen; - RETERR(dst_gssapi_initctx(gname, cred, &r, &outtoken, context)); + isc_buffer_init(outtoken, array, sizeof(array)); + isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); + RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context)); dstkey = NULL; RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, &dstkey)); RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME, - dstkey, ISC_TRUE, NULL, + dstkey, ISC_FALSE, NULL, rtkey.inception, rtkey.expire, ring->mctx, ring, outkey)); @@ -1182,6 +1276,9 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, return (result); failure: + /* + * XXXSRA This probably leaks memory from rtkey and qtkey. + */ return (result); } @@ -1212,10 +1309,9 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, rtkey.mode != DNS_TKEYMODE_DELETE || rtkey.mode != qtkey.mode || !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || - rmsg->rcode != dns_rcode_noerror) - { + rmsg->rcode != dns_rcode_noerror) { tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid " - "or error set"); + "or error set(3)"); result = DNS_R_INVALIDTKEY; dns_rdata_freestruct(&qtkey); dns_rdata_freestruct(&rtkey); @@ -1240,3 +1336,84 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, failure: return (result); } + +isc_result_t +dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, + dns_name_t *server, gss_ctx_id_t *context, + dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, + isc_boolean_t win2k) +{ + dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; + dns_name_t *tkeyname; + dns_rdata_tkey_t rtkey, qtkey; + isc_buffer_t intoken, outtoken; + dst_key_t *dstkey = NULL; + isc_result_t result; + unsigned char array[1024]; + + REQUIRE(qmsg != NULL); + REQUIRE(rmsg != NULL); + REQUIRE(server != NULL); + if (outkey != NULL) + REQUIRE(*outkey == NULL); + + if (rmsg->rcode != dns_rcode_noerror) + return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); + + RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); + RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); + + if (win2k == ISC_TRUE) + RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, + DNS_SECTION_ANSWER)); + else + RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, + DNS_SECTION_ADDITIONAL)); + + RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); + + if (rtkey.error != dns_rcode_noerror || + rtkey.mode != DNS_TKEYMODE_GSSAPI || + !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) + { + tkey_log("dns_tkey_processdhresponse: tkey mode invalid " + "or error set(4)"); + result = DNS_R_INVALIDTKEY; + goto failure; + } + + isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); + isc_buffer_init(&outtoken, array, sizeof(array)); + + result = dst_gssapi_initctx(server, &intoken, &outtoken, context); + if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) + return (result); + + dstkey = NULL; + RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, + &dstkey)); + + /* + * XXXSRA This seems confused. If we got CONTINUE from initctx, + * the GSS negotiation hasn't completed yet, so we can't sign + * anything yet. + */ + + RETERR(dns_tsigkey_createfromkey(tkeyname, + (win2k + ? DNS_TSIG_GSSAPIMS_NAME + : DNS_TSIG_GSSAPI_NAME), + dstkey, ISC_TRUE, NULL, + rtkey.inception, rtkey.expire, + ring->mctx, ring, outkey)); + + dns_rdata_freestruct(&rtkey); + return (result); + + failure: + /* + * XXXSRA This probably leaks memory from qtkey. + */ + dns_rdata_freestruct(&rtkey); + return (result); +} diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index f21832f..74a7af3 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -16,7 +16,7 @@ */ /* - * $Id: tsig.c,v 1.117.18.14 2008/01/17 23:46:03 tbox Exp $ + * $Id: tsig.c,v 1.136 2008/11/04 21:23:14 marka Exp $ */ /*! \file */ #include <config.h> @@ -28,10 +28,12 @@ #include <isc/refcount.h> #include <isc/string.h> /* Required for HP/UX (and others?) */ #include <isc/util.h> +#include <isc/time.h> #include <dns/keyvalues.h> #include <dns/log.h> #include <dns/message.h> +#include <dns/fixedname.h> #include <dns/rbt.h> #include <dns/rdata.h> #include <dns/rdatalist.h> @@ -74,7 +76,6 @@ dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5; static unsigned char gsstsig_ndata[] = "\010gss-tsig"; static unsigned char gsstsig_offsets[] = { 0, 9 }; - static dns_name_t gsstsig = { DNS_NAME_MAGIC, gsstsig_ndata, 10, 2, @@ -83,13 +84,14 @@ static dns_name_t gsstsig = { {(void *)-1, (void *)-1}, {NULL, NULL} }; - LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig; -/* It's nice of Microsoft to conform to their own standard. */ +/* + * Since Microsoft doesn't follow its own standard, we will use this + * alternate name as a second guess. + */ static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com"; static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 }; - static dns_name_t gsstsigms = { DNS_NAME_MAGIC, gsstsigms_ndata, 19, 4, @@ -98,7 +100,6 @@ static dns_name_t gsstsigms = { {(void *)-1, (void *)-1}, {NULL, NULL} }; - LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms; static unsigned char hmacsha1_ndata[] = "\011hmac-sha1"; @@ -179,10 +180,16 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); static void +cleanup_ring(dns_tsig_keyring_t *ring); +static void +tsigkey_free(dns_tsigkey_t *key); + +static void tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { va_list ap; char message[4096]; char namestr[DNS_NAME_FORMATSIZE]; + char creatorstr[DNS_NAME_FORMATSIZE]; if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) return; @@ -190,11 +197,22 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { dns_name_format(&key->name, namestr, sizeof(namestr)); else strcpy(namestr, "<null>"); + + if (key != NULL && key->generated) + dns_name_format(key->creator, creatorstr, sizeof(creatorstr)); + va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, - level, "tsig key '%s': %s", namestr, message); + if (key != NULL && key->generated) + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, + level, "tsig key '%s' (%s): %s", + namestr, creatorstr, message); + else + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG, + level, "tsig key '%s': %s", namestr, message); } isc_result_t @@ -330,6 +348,16 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, if (ring != NULL) { RWLOCK(&ring->lock, isc_rwlocktype_write); + ring->writecount++; + + /* + * Do on the fly cleaning. Find some nodes we might not + * want around any more. + */ + if (ring->writecount > 10) { + cleanup_ring(ring); + ring->writecount = 0; + } ret = dns_rbt_addname(ring->keys, name, tkey); if (ret != ISC_R_SUCCESS) { RWUNLOCK(&ring->lock, isc_rwlocktype_write); @@ -338,7 +366,12 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, RWUNLOCK(&ring->lock, isc_rwlocktype_write); } - if (dstkey != NULL && dst_key_size(dstkey) < 64) { + /* + * Ignore this if it's a GSS key, since the key size is meaningless. + */ + if (dstkey != NULL && dst_key_size(dstkey) < 64 && + !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) && + !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(name, namestr, sizeof(namestr)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, @@ -375,6 +408,66 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, return (ret); } +/* + * Find a few nodes to destroy if possible. + */ +static void +cleanup_ring(dns_tsig_keyring_t *ring) +{ + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + isc_stdtime_t now; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + + /* + * Start up a new iterator each time. + */ + isc_stdtime_get(&now); + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fixedorigin); + origin = dns_fixedname_name(&fixedorigin); + + again: + dns_rbtnodechain_init(&chain, ring->mctx); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, + origin); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return; + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + if (tkey != NULL) { + if (tkey->generated + && isc_refcount_current(&tkey->refs) == 1 + && tkey->inception != tkey->expire + && tkey->expire < now) { + tsig_log(tkey, 2, "tsig expire: deleting"); + /* delete the key */ + dns_rbtnodechain_invalidate(&chain); + (void)dns_rbt_deletename(ring->keys, + &tkey->name, + ISC_FALSE); + goto again; + } + } + result = dns_rbtnodechain_next(&chain, &foundname, + origin); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + return; + } + + } +} + isc_result_t dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, unsigned char *secret, int length, isc_boolean_t generated, @@ -540,17 +633,6 @@ dns_tsigkey_setdeleted(dns_tsigkey_t *key) { RWUNLOCK(&key->ring->lock, isc_rwlocktype_write); } -static void -buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) { - isc_uint16_t valhi; - isc_uint32_t vallo; - - valhi = (isc_uint16_t)(val >> 32); - vallo = (isc_uint32_t)(val & 0xFFFFFFFF); - isc_buffer_putuint16(b, valhi); - isc_buffer_putuint32(b, vallo); -} - isc_result_t dns_tsig_sign(dns_message_t *msg) { dns_tsigkey_t *key; @@ -613,7 +695,7 @@ dns_tsig_sign(dns_message_t *msg) { tsig.otherlen = BADTIMELEN; tsig.other = badtimedata; isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen); - buffer_putuint48(&otherbuf, tsig.timesigned); + isc_buffer_putuint48(&otherbuf, tsig.timesigned); } if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { @@ -641,8 +723,7 @@ dns_tsig_sign(dns_message_t *msg) { goto cleanup_context; isc_buffer_putuint16(&databuf, querytsig.siglen); if (isc_buffer_availablelength(&databuf) < - querytsig.siglen) - { + querytsig.siglen) { ret = ISC_R_NOSPACE; goto cleanup_context; } @@ -700,7 +781,7 @@ dns_tsig_sign(dns_message_t *msg) { isc_buffer_clear(&databuf); if (tsig.error == dns_tsigerror_badtime) tsig.timesigned = querytsig.timesigned; - buffer_putuint48(&databuf, tsig.timesigned); + isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(ctx, &r); @@ -852,6 +933,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, REQUIRE(source != NULL); REQUIRE(DNS_MESSAGE_VALID(msg)); tsigkey = dns_message_gettsigkey(msg); + REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey)); msg->verify_attempted = 1; @@ -907,8 +989,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, */ if (is_response(msg) && (!dns_name_equal(keyname, &tsigkey->name) || - !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) - { + !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) { msg->tsigstatus = dns_tsigerror_badkey; tsig_log(msg->tsigkey, 2, "key name and algorithm do not match"); @@ -1084,7 +1165,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, goto cleanup_context; isc_buffer_clear(&databuf); - buffer_putuint48(&databuf, tsig.timesigned); + isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_putuint16(&databuf, tsig.error); isc_buffer_putuint16(&databuf, tsig.otherlen); @@ -1106,15 +1187,14 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, msg->tsigstatus = dns_tsigerror_badsig; ret = DNS_R_TSIGVERIFYFAILURE; tsig_log(msg->tsigkey, 2, - "signature failed to verify"); + "signature failed to verify(1)"); goto cleanup_context; } else if (ret != ISC_R_SUCCESS) goto cleanup_context; dst_context_destroy(&ctx); } else if (tsig.error != dns_tsigerror_badsig && - tsig.error != dns_tsigerror_badkey) - { + tsig.error != dns_tsigerror_badkey) { msg->tsigstatus = dns_tsigerror_badsig; tsig_log(msg->tsigkey, 2, "signature was empty"); return (DNS_R_TSIGVERIFYFAILURE); @@ -1201,8 +1281,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { * Do the key name and algorithm match that of the query? */ if (!dns_name_equal(keyname, &tsigkey->name) || - !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) - { + !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) { msg->tsigstatus = dns_tsigerror_badkey; ret = DNS_R_TSIGVERIFYFAILURE; tsig_log(msg->tsigkey, 2, @@ -1221,8 +1300,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { ret = DNS_R_CLOCKSKEW; goto cleanup_querystruct; } else if (now + msg->timeadjust < - tsig.timesigned - tsig.fudge) - { + tsig.timesigned - tsig.fudge) { msg->tsigstatus = dns_tsigerror_badtime; tsig_log(msg->tsigkey, 2, "signature is in the future"); @@ -1312,7 +1390,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { */ if (has_tsig) { isc_buffer_init(&databuf, data, sizeof(data)); - buffer_putuint48(&databuf, tsig.timesigned); + isc_buffer_putuint48(&databuf, tsig.timesigned); isc_buffer_putuint16(&databuf, tsig.fudge); isc_buffer_usedregion(&databuf, &r); ret = dst_context_adddata(msg->tsigctx, &r); @@ -1339,7 +1417,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { if (ret == DST_R_VERIFYFAILURE) { msg->tsigstatus = dns_tsigerror_badsig; tsig_log(msg->tsigkey, 2, - "signature failed to verify"); + "signature failed to verify(2)"); ret = DNS_R_TSIGVERIFYFAILURE; goto cleanup_context; } @@ -1375,6 +1453,10 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, REQUIRE(name != NULL); REQUIRE(ring != NULL); + RWLOCK(&ring->lock, isc_rwlocktype_write); + cleanup_ring(ring); + RWUNLOCK(&ring->lock, isc_rwlocktype_write); + isc_stdtime_get(&now); RWLOCK(&ring->lock, isc_rwlocktype_read); key = NULL; @@ -1393,7 +1475,7 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name, */ RWUNLOCK(&ring->lock, isc_rwlocktype_read); RWLOCK(&ring->lock, isc_rwlocktype_write); - (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE); + (void)dns_rbt_deletename(ring->keys, name, ISC_FALSE); RWUNLOCK(&ring->lock, isc_rwlocktype_write); return (ISC_R_NOTFOUND); } @@ -1443,6 +1525,7 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) { return (result); } + ring->writecount = 0; ring->mctx = NULL; isc_mem_attach(mctx, &ring->mctx); diff --git a/lib/dns/ttl.c b/lib/dns/ttl.c index 39d2ac3..9d0dec5 100644 --- a/lib/dns/ttl.c +++ b/lib/dns/ttl.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ttl.c,v 1.25.18.2 2005/04/29 00:16:07 marka Exp $ */ +/* $Id: ttl.c,v 1.29 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 685434b..c62b714 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,18 +15,17 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.119.18.41.2.1 2009/03/17 02:23:49 marka Exp $ */ - -/*! \file */ +/* $Id: validator.c,v 1.164.12.9 2009/05/07 23:47:12 tbox Exp $ */ #include <config.h> +#include <isc/base32.h> #include <isc/mem.h> #include <isc/print.h> +#include <isc/sha2.h> #include <isc/string.h> #include <isc/task.h> #include <isc/util.h> -#include <isc/sha2.h> #include <dns/db.h> #include <dns/ds.h> @@ -37,6 +36,7 @@ #include <dns/message.h> #include <dns/ncache.h> #include <dns/nsec.h> +#include <dns/nsec3.h> #include <dns/rdata.h> #include <dns/rdatastruct.h> #include <dns/rdataset.h> @@ -89,7 +89,7 @@ #define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC) #define VALATTR_SHUTDOWN 0x0001 /*%< Shutting down. */ -#define VALATTR_CANCELED 0x0002 /*%< Cancelled. */ +#define VALATTR_CANCELED 0x0002 /*%< Canceled. */ #define VALATTR_TRIEDVERIFY 0x0004 /*%< We have found a key and * have attempted a verify. */ #define VALATTR_INSECURITY 0x0010 /*%< Attempting proveunsecure. */ @@ -98,16 +98,23 @@ /*! * NSEC proofs to be looked for. */ -#define VALATTR_NEEDNOQNAME 0x0100 -#define VALATTR_NEEDNOWILDCARD 0x0200 -#define VALATTR_NEEDNODATA 0x0400 +#define VALATTR_NEEDNOQNAME 0x00000100 +#define VALATTR_NEEDNOWILDCARD 0x00000200 +#define VALATTR_NEEDNODATA 0x00000400 /*! * NSEC proofs that have been found. */ -#define VALATTR_FOUNDNOQNAME 0x1000 -#define VALATTR_FOUNDNOWILDCARD 0x2000 -#define VALATTR_FOUNDNODATA 0x4000 +#define VALATTR_FOUNDNOQNAME 0x00001000 +#define VALATTR_FOUNDNOWILDCARD 0x00002000 +#define VALATTR_FOUNDNODATA 0x00004000 +#define VALATTR_FOUNDCLOSEST 0x00008000 + +/* + * + */ +#define VALATTR_FOUNDOPTOUT 0x00010000 +#define VALATTR_FOUNDUNKNOWN 0x00020000 #define NEEDNODATA(val) ((val->attributes & VALATTR_NEEDNODATA) != 0) #define NEEDNOQNAME(val) ((val->attributes & VALATTR_NEEDNOQNAME) != 0) @@ -250,10 +257,20 @@ static isc_boolean_t isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, isc_result_t dbresult) { - dns_rdataset_t set; + dns_fixedname_t fixed; + dns_label_t hashlabel; + dns_name_t nsec3name; + dns_rdata_nsec3_t nsec3; dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t set; + int order; + int scope; isc_boolean_t found; + isc_buffer_t buffer; isc_result_t result; + unsigned char hash[NSEC3_MAX_HASH_LENGTH]; + unsigned char owner[NSEC3_MAX_HASH_LENGTH]; + unsigned int length; REQUIRE(dbresult == DNS_R_NXRRSET || dbresult == DNS_R_NCACHENXRRSET); @@ -263,6 +280,8 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, else { result = dns_ncache_getrdataset(rdataset, name, dns_rdatatype_nsec, &set); + if (result == ISC_R_NOTFOUND) + goto trynsec3; if (result != ISC_R_SUCCESS) return (ISC_FALSE); } @@ -274,9 +293,78 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, if (result == ISC_R_SUCCESS) { dns_rdataset_current(&set, &rdata); found = dns_nsec_typepresent(&rdata, dns_rdatatype_ns); + dns_rdata_reset(&rdata); } dns_rdataset_disassociate(&set); return (found); + + trynsec3: + /* + * Iterate over the ncache entry. + */ + found = ISC_FALSE; + dns_name_init(&nsec3name, NULL); + dns_fixedname_init(&fixed); + dns_name_downcase(name, dns_fixedname_name(&fixed), NULL); + name = dns_fixedname_name(&fixed); + result = dns_rdataset_first(rdataset); + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + dns_ncache_current(rdataset, &nsec3name, &set); + if (set.type != dns_rdatatype_nsec3) { + dns_rdataset_disassociate(&set); + continue; + } + dns_name_getlabel(&nsec3name, 0, &hashlabel); + isc_region_consume(&hashlabel, 1); + isc_buffer_init(&buffer, owner, sizeof(owner)); + result = isc_base32hex_decoderegion(&hashlabel, &buffer); + if (result != ISC_R_SUCCESS) { + dns_rdataset_disassociate(&set); + continue; + } + for (result = dns_rdataset_first(&set); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&set)) + { + dns_rdata_reset(&rdata); + dns_rdataset_current(&set, &rdata); + (void)dns_rdata_tostruct(&rdata, &nsec3, NULL); + if (nsec3.hash != 1) + continue; + length = isc_iterated_hash(hash, nsec3.hash, + nsec3.iterations, nsec3.salt, + nsec3.salt_length, + name->ndata, name->length); + if (length != isc_buffer_usedlength(&buffer)) + continue; + order = memcmp(hash, owner, length); + if (order == 0) { + found = dns_nsec3_typepresent(&rdata, + dns_rdatatype_ns); + dns_rdataset_disassociate(&set); + return (found); + } + if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) == 0) + continue; + /* + * Does this optout span cover the name? + */ + scope = memcmp(owner, nsec3.next, nsec3.next_length); + if ((scope < 0 && order > 0 && + memcmp(hash, nsec3.next, length) < 0) || + (scope >= 0 && (order > 0 || + memcmp(hash, nsec3.next, length) < 0))) + { + dns_rdataset_disassociate(&set); + return (ISC_TRUE); + } + } + dns_rdataset_disassociate(&set); + } + return (found); } /*% @@ -767,10 +855,317 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, return (ISC_R_SUCCESS); } +static isc_result_t +nsec3noexistnodata(dns_validator_t *val, dns_name_t* name, + dns_name_t *nsec3name, dns_rdataset_t *nsec3set, + dns_name_t *zonename, isc_boolean_t *exists, + isc_boolean_t *data, isc_boolean_t *optout, + isc_boolean_t *unknown, isc_boolean_t *setclosest, + isc_boolean_t *setnearest, dns_name_t *closest, + dns_name_t *nearest) +{ + char namebuf[DNS_NAME_FORMATSIZE]; + dns_fixedname_t fzone; + dns_fixedname_t qfixed; + dns_label_t hashlabel; + dns_name_t *qname; + dns_name_t *zone; + dns_rdata_nsec3_t nsec3; + dns_rdata_t rdata = DNS_RDATA_INIT; + int order; + int scope; + isc_boolean_t atparent; + isc_boolean_t first; + isc_boolean_t ns; + isc_boolean_t soa; + isc_buffer_t buffer; + isc_result_t answer = ISC_R_IGNORE; + isc_result_t result; + unsigned char hash[NSEC3_MAX_HASH_LENGTH]; + unsigned char owner[NSEC3_MAX_HASH_LENGTH]; + unsigned int length; + unsigned int qlabels; + unsigned int zlabels; + + REQUIRE((exists == NULL && data == NULL) || + (exists != NULL && data != NULL)); + REQUIRE(nsec3set != NULL && nsec3set->type == dns_rdatatype_nsec3); + REQUIRE((setclosest == NULL && closest == NULL) || + (setclosest != NULL && closest != NULL)); + REQUIRE((setnearest == NULL && nearest == NULL) || + (setnearest != NULL && nearest != NULL)); + + result = dns_rdataset_first(nsec3set); + if (result != ISC_R_SUCCESS) { + validator_log(val, ISC_LOG_DEBUG(3), + "failure processing NSEC3 set"); + return (result); + } + + dns_rdataset_current(nsec3set, &rdata); + + result = dns_rdata_tostruct(&rdata, &nsec3, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + validator_log(val, ISC_LOG_DEBUG(3), "looking for relevant NSEC3"); + + dns_fixedname_init(&fzone); + zone = dns_fixedname_name(&fzone); + zlabels = dns_name_countlabels(nsec3name); + + /* + * NSEC3 records must have two or more labels to be valid. + */ + if (zlabels < 2) + return (ISC_R_IGNORE); + + /* + * Strip off the NSEC3 hash to get the zone. + */ + zlabels--; + dns_name_split(nsec3name, zlabels, NULL, zone); + + /* + * If not below the zone name we can ignore this record. + */ + if (!dns_name_issubdomain(name, zone)) + return (ISC_R_IGNORE); + + /* + * Is this zone the same or deeper than the current zone? + */ + if (dns_name_countlabels(zonename) == 0 || + dns_name_issubdomain(zone, zonename)) + dns_name_copy(zone, zonename, NULL); + + if (!dns_name_equal(zone, zonename)) + return (ISC_R_IGNORE); + + /* + * Are we only looking for the most enclosing zone? + */ + if (exists == NULL || data == NULL) + return (ISC_R_SUCCESS); + + /* + * Only set unknown once we are sure that this NSEC3 is from + * the deepest covering zone. + */ + if (!dns_nsec3_supportedhash(nsec3.hash)) { + if (unknown != NULL) + *unknown = ISC_TRUE; + return (ISC_R_IGNORE); + } + + /* + * Recover the hash from the first label. + */ + dns_name_getlabel(nsec3name, 0, &hashlabel); + isc_region_consume(&hashlabel, 1); + isc_buffer_init(&buffer, owner, sizeof(owner)); + result = isc_base32hex_decoderegion(&hashlabel, &buffer); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * The hash lengths should match. If not ignore the record. + */ + if (isc_buffer_usedlength(&buffer) != nsec3.next_length) + return (ISC_R_IGNORE); + + /* + * Work out what this NSEC3 covers. + * Inside (<0) or outside (>=0). + */ + scope = memcmp(owner, nsec3.next, nsec3.next_length); + + /* + * Prepare to compute all the hashes. + */ + dns_fixedname_init(&qfixed); + qname = dns_fixedname_name(&qfixed); + dns_name_downcase(name, qname, NULL); + qlabels = dns_name_countlabels(qname); + first = ISC_TRUE; + + while (qlabels >= zlabels) { + length = isc_iterated_hash(hash, nsec3.hash, nsec3.iterations, + nsec3.salt, nsec3.salt_length, + qname->ndata, qname->length); + /* + * The computed hash length should match. + */ + if (length != nsec3.next_length) { + validator_log(val, ISC_LOG_DEBUG(3), + "ignoring NSEC bad length %u vs %u", + length, nsec3.next_length); + return (ISC_R_IGNORE); + } + + order = memcmp(hash, owner, length); + if (first && order == 0) { + /* + * The hashes are the same. + */ + atparent = dns_rdatatype_atparent(val->event->type); + ns = dns_nsec3_typepresent(&rdata, dns_rdatatype_ns); + soa = dns_nsec3_typepresent(&rdata, dns_rdatatype_soa); + if (ns && !soa) { + if (!atparent) { + /* + * This NSEC record is from somewhere + * higher in the DNS, and at the + * parent of a delegation. It can not + * be legitimately used here. + */ + validator_log(val, ISC_LOG_DEBUG(3), + "ignoring parent NSEC3"); + return (ISC_R_IGNORE); + } + } else if (atparent && ns && soa) { + /* + * This NSEC record is from the child. + * It can not be legitimately used here. + */ + validator_log(val, ISC_LOG_DEBUG(3), + "ignoring child NSEC3"); + return (ISC_R_IGNORE); + } + if (val->event->type == dns_rdatatype_cname || + val->event->type == dns_rdatatype_nxt || + val->event->type == dns_rdatatype_nsec || + val->event->type == dns_rdatatype_key || + !dns_nsec3_typepresent(&rdata, dns_rdatatype_cname)) { + *exists = ISC_TRUE; + *data = dns_nsec3_typepresent(&rdata, + val->event->type); + validator_log(val, ISC_LOG_DEBUG(3), + "NSEC3 proves name exists (owner) " + "data=%d", *data); + return (ISC_R_SUCCESS); + } + validator_log(val, ISC_LOG_DEBUG(3), + "NSEC3 proves CNAME exists"); + return (ISC_R_IGNORE); + } + + if (order == 0 && + dns_nsec3_typepresent(&rdata, dns_rdatatype_ns) && + !dns_nsec3_typepresent(&rdata, dns_rdatatype_soa)) + { + /* + * This NSEC3 record is from somewhere higher in + * the DNS, and at the parent of a delegation. + * It can not be legitimately used here. + */ + validator_log(val, ISC_LOG_DEBUG(3), + "ignoring parent NSEC3"); + return (ISC_R_IGNORE); + } + + /* + * Potential closest encloser. + */ + if (order == 0) { + if (closest != NULL && + (dns_name_countlabels(closest) == 0 || + dns_name_issubdomain(qname, closest)) && + !dns_nsec3_typepresent(&rdata, dns_rdatatype_ds) && + !dns_nsec3_typepresent(&rdata, dns_rdatatype_dname) && + (dns_nsec3_typepresent(&rdata, dns_rdatatype_soa) || + !dns_nsec3_typepresent(&rdata, dns_rdatatype_ns))) + { + + dns_name_format(qname, namebuf, + sizeof(namebuf)); + validator_log(val, ISC_LOG_DEBUG(3), + "NSEC3 indicates potential " + "closest encloser: '%s'", + namebuf); + dns_name_copy(qname, closest, NULL); + *setclosest = ISC_TRUE; + } + dns_name_format(qname, namebuf, sizeof(namebuf)); + validator_log(val, ISC_LOG_DEBUG(3), + "NSEC3 at super-domain %s", namebuf); + return (answer); + } + + /* + * Find if the name does not exist. + * + * We continue as we need to find the name closest to the + * closest encloser that doesn't exist. + * + * We also need to continue to ensure that we are not + * proving the non-existence of a record in a sub-zone. + * If that would be the case we will return ISC_R_IGNORE + * above. + */ + if ((scope < 0 && order > 0 && + memcmp(hash, nsec3.next, length) < 0) || + (scope >= 0 && (order > 0 || + memcmp(hash, nsec3.next, length) < 0))) + { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(qname, namebuf, sizeof(namebuf)); + validator_log(val, ISC_LOG_DEBUG(3), "NSEC3 proves " + "name does not exist: '%s'", namebuf); + if (nearest != NULL && + (dns_name_countlabels(nearest) == 0 || + dns_name_issubdomain(nearest, qname))) { + dns_name_copy(qname, nearest, NULL); + *setnearest = ISC_TRUE; + } +#if 0 + /* + * The closest encloser may be the zone name. + */ + if (closest != NULL && + dns_name_countlabels(closest) == 0 && + !dns_nsec3_typepresent(&rdata, dns_rdatatype_ds) && + !dns_nsec3_typepresent(&rdata, dns_rdatatype_dname) && + (dns_nsec3_typepresent(&rdata, dns_rdatatype_soa) || + !dns_nsec3_typepresent(&rdata, dns_rdatatype_ns))) + { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(zone, namebuf, + sizeof(namebuf)); + validator_log(val, ISC_LOG_DEBUG(3), + "NSEC3 potential closest " + "encloser from zone name: '%s'", + namebuf); + dns_name_copy(zone, closest, NULL); + *setclosest = ISC_TRUE; + } +#endif + *exists = ISC_FALSE; + *data = ISC_FALSE; + if (optout != NULL) { + if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0) + validator_log(val, ISC_LOG_DEBUG(3), + "NSEC3 indicates optout"); + *optout = + ISC_TF(nsec3.flags & DNS_NSEC3FLAG_OPTOUT); + } + answer = ISC_R_SUCCESS; + } + + qlabels--; + if (qlabels > 0) + dns_name_split(qname, qlabels, NULL, qname); + first = ISC_FALSE; + } + return (answer); +} + /*% * Callback for when NSEC records have been validated. * - * Looks for NOQNAME and NODATA proofs. + * Looks for NOQNAME, NODATA and OPTOUT proofs. * * Resumes nsecvalidate. */ @@ -779,6 +1174,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; dns_validator_t *val; dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; isc_boolean_t want_destroy; isc_result_t result; isc_boolean_t exists, data; @@ -788,6 +1184,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) { devent = (dns_validatorevent_t *)event; rdataset = devent->rdataset; + sigrdataset = devent->sigrdataset; val = devent->ev_arg; result = devent->result; dns_validator_destroy(&val->subvalidator); @@ -834,11 +1231,18 @@ authvalidated(isc_task_t *task, isc_event_t *event) { } if (!exists) { val->attributes |= VALATTR_FOUNDNOQNAME; + val->attributes |= VALATTR_FOUNDCLOSEST; + /* + * The NSEC noqname proof also contains + * the closest encloser. + + */ if (NEEDNOQNAME(val)) proofs[DNS_VALIDATOR_NOQNAMEPROOF] = devent->name; } } + result = nsecvalidate(val, ISC_TRUE); if (result != DNS_R_WAIT) validator_done(val, result); @@ -992,13 +1396,25 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { * the validation process will stall if looping was to occur. */ static inline isc_boolean_t -check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { +check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ dns_validator_t *parent; for (parent = val; parent != NULL; parent = parent->parent) { if (parent->event != NULL && parent->event->type == type && - dns_name_equal(parent->event->name, name)) + dns_name_equal(parent->event->name, name) && + /* + * As NSEC3 records are meta data you sometimes + * need to prove a NSEC3 record which says that + * itself doesn't exist. + */ + (parent->event->type != dns_rdatatype_nsec3 || + rdataset == NULL || sigrdataset == NULL || + parent->event->message == NULL || + parent->event->rdataset != NULL || + parent->event->sigrdataset != NULL)) { validator_log(val, ISC_LOG_DEBUG(3), "continuing validation would lead to " @@ -1021,7 +1437,7 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, if (dns_rdataset_isassociated(&val->fsigrdataset)) dns_rdataset_disassociate(&val->fsigrdataset); - if (check_deadlock(val, name, type)) + if (check_deadlock(val, name, type, NULL, NULL)) return (DNS_R_NOVALIDSIG); validator_logcreate(val, name, type, caller, "fetch"); @@ -1044,7 +1460,7 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, { isc_result_t result; - if (check_deadlock(val, name, type)) + if (check_deadlock(val, name, type, rdataset, sigrdataset)) return (DNS_R_NOVALIDSIG); validator_logcreate(val, name, type, caller, "validator"); @@ -1128,7 +1544,7 @@ get_dst_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo, } /*% - * Get the key that genertated this signature. + * Get the key that generated this signature. */ static isc_result_t get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { @@ -1141,7 +1557,7 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { * Is the signer name appropriate for this signature? * * The signer name must be at the same level as the owner name - * or closer to the the DNS root. + * or closer to the DNS root. */ namereln = dns_name_fullcompare(val->event->name, &siginfo->signer, &order, &nlabels); @@ -1163,6 +1579,23 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { */ if (dns_rdatatype_atparent(val->event->rdataset->type)) return (DNS_R_CONTINUE); + } else { + /* + * SOA and NS RRsets can only be signed by a key with + * the same name. + */ + if (val->event->rdataset->type == dns_rdatatype_soa || + val->event->rdataset->type == dns_rdatatype_ns) { + const char *typename; + + if (val->event->rdataset->type == dns_rdatatype_soa) + typename = "SOA"; + else + typename = "NS"; + validator_log(val, ISC_LOG_DEBUG(3), + "%s signer mismatch", typename); + return (DNS_R_CONTINUE); + } } /* @@ -1620,6 +2053,7 @@ dlv_validatezonekey(dns_validator_t *val) { break; } if (result != ISC_R_SUCCESS) { + dns_rdataset_disassociate(&trdataset); validator_log(val, ISC_LOG_DEBUG(3), "no DNSKEY matching DLV"); continue; @@ -1734,6 +2168,10 @@ validatezonekey(dns_validator_t *val) { &sigrdata); result = dns_rdata_tostruct(&sigrdata, &sig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if (!dns_name_equal(val->event->name, &sig.signer)) + continue; + result = dns_keytable_findkeynode(val->keytable, val->event->name, sig.algorithm, @@ -1957,6 +2395,7 @@ validatezonekey(dns_validator_t *val) { break; } if (result != ISC_R_SUCCESS) { + dns_rdataset_disassociate(&trdataset); validator_log(val, ISC_LOG_DEBUG(3), "no DNSKEY matching DS"); continue; @@ -1974,7 +2413,11 @@ validatezonekey(dns_validator_t *val) { if (ds.key_tag != sig.keyid || ds.algorithm != sig.algorithm) continue; - + if (!dns_name_equal(val->event->name, &sig.signer)) { + validator_log(val, ISC_LOG_DEBUG(3), + "DNSKEY signer mismatch"); + continue; + } dstkey = NULL; result = dns_dnssec_keyfromrdata(val->event->name, &keyrdata, @@ -2044,7 +2487,8 @@ start_positive_validation(dns_validator_t *val) { * \li ISC_R_SUCCESS */ static isc_result_t -checkwildcard(dns_validator_t *val) { +checkwildcard(dns_validator_t *val, dns_rdatatype_t type, dns_name_t *zonename) +{ dns_name_t *name, *wild; dns_message_t *message = val->event->message; isc_result_t result; @@ -2052,6 +2496,13 @@ checkwildcard(dns_validator_t *val) { char namebuf[DNS_NAME_FORMATSIZE]; wild = dns_fixedname_name(&val->wild); + + if (dns_name_countlabels(wild) == 0) { + validator_log(val, ISC_LOG_DEBUG(3), + "in checkwildcard: no wildcard to check"); + return (ISC_R_SUCCESS); + } + dns_name_format(wild, namebuf, sizeof(namebuf)); validator_log(val, ISC_LOG_DEBUG(3), "in checkwildcard: %s", namebuf); @@ -2068,9 +2519,8 @@ checkwildcard(dns_validator_t *val) { rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { - if (rdataset->type != dns_rdatatype_nsec) + if (rdataset->type != type) continue; - val->nsecset = rdataset; for (sigrdataset = ISC_LIST_HEAD(name->list); sigrdataset != NULL; @@ -2086,7 +2536,8 @@ checkwildcard(dns_validator_t *val) { if (rdataset->trust != dns_trust_secure) continue; - if (((val->attributes & VALATTR_NEEDNODATA) != 0 || + if (rdataset->type == dns_rdatatype_nsec && + ((val->attributes & VALATTR_NEEDNODATA) != 0 || (val->attributes & VALATTR_NEEDNOWILDCARD) != 0) && (val->attributes & VALATTR_FOUNDNODATA) == 0 && (val->attributes & VALATTR_FOUNDNOWILDCARD) == 0 && @@ -2108,6 +2559,31 @@ checkwildcard(dns_validator_t *val) { name; return (ISC_R_SUCCESS); } + + if (rdataset->type == dns_rdatatype_nsec3 && + ((val->attributes & VALATTR_NEEDNODATA) != 0 || + (val->attributes & VALATTR_NEEDNOWILDCARD) != 0) && + (val->attributes & VALATTR_FOUNDNODATA) == 0 && + (val->attributes & VALATTR_FOUNDNOWILDCARD) == 0 && + nsec3noexistnodata(val, wild, name, rdataset, + zonename, &exists, &data, + NULL, NULL, NULL, NULL, NULL, + NULL) == ISC_R_SUCCESS) + { + dns_name_t **proofs = val->event->proofs; + if (exists && !data) + val->attributes |= VALATTR_FOUNDNODATA; + if (exists && !data && NEEDNODATA(val)) + proofs[DNS_VALIDATOR_NODATAPROOF] = + name; + if (!exists) + val->attributes |= + VALATTR_FOUNDNOWILDCARD; + if (!exists && NEEDNOQNAME(val)) + proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = + name; + return (ISC_R_SUCCESS); + } } } if (result == ISC_R_NOMORE) @@ -2115,6 +2591,170 @@ checkwildcard(dns_validator_t *val) { return (result); } + +static isc_result_t +findnsec3proofs(dns_validator_t *val) { + dns_name_t *name; + dns_message_t *message = val->event->message; + isc_result_t result; + isc_boolean_t exists, data, optout, unknown; + isc_boolean_t setclosest, setnearest; + dns_fixedname_t fclosest, fnearest, fzonename; + dns_name_t *closest, *nearest, *zonename; + dns_name_t **proofs = val->event->proofs; + + dns_fixedname_init(&fclosest); + dns_fixedname_init(&fnearest); + dns_fixedname_init(&fzonename); + closest = dns_fixedname_name(&fclosest); + nearest = dns_fixedname_name(&fnearest); + zonename = dns_fixedname_name(&fzonename); + + for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + result == ISC_R_SUCCESS; + result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) + { + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + + name = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); + + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (rdataset->type != dns_rdatatype_nsec3) + continue; + + for (sigrdataset = ISC_LIST_HEAD(name->list); + sigrdataset != NULL; + sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) + { + if (sigrdataset->type == dns_rdatatype_rrsig && + sigrdataset->covers == dns_rdatatype_nsec3) + break; + } + if (sigrdataset == NULL) + continue; + + if (rdataset->trust != dns_trust_secure) + continue; + + result = nsec3noexistnodata(val, val->event->name, + name, rdataset, + zonename, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL); + if (result != ISC_R_IGNORE && result != ISC_R_SUCCESS) + return (result); + } + } + if (result != ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + if (dns_name_countlabels(zonename) == 0) + return (ISC_R_SUCCESS); + + for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + result == ISC_R_SUCCESS; + result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) + { + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + + name = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); + + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { + if (rdataset->type != dns_rdatatype_nsec3) + continue; + + for (sigrdataset = ISC_LIST_HEAD(name->list); + sigrdataset != NULL; + sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) + { + if (sigrdataset->type == dns_rdatatype_rrsig && + sigrdataset->covers == dns_rdatatype_nsec3) + break; + } + if (sigrdataset == NULL) + continue; + + if (rdataset->trust != dns_trust_secure) + continue; + + /* + * We process all NSEC3 records to find the closest + * encloser and nearest name to the closest encloser. + */ + setclosest = setnearest = ISC_FALSE; + optout = ISC_FALSE; + unknown = ISC_FALSE; + result = nsec3noexistnodata(val, val->event->name, + name, rdataset, + zonename, &exists, + &data, &optout, &unknown, + &setclosest, &setnearest, + closest, nearest); + if (setclosest) + proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name; + if (unknown) + val->attributes |= VALATTR_FOUNDUNKNOWN; + if (result != ISC_R_SUCCESS) + continue; + if (exists && !data && NEEDNODATA(val)) { + val->attributes |= VALATTR_FOUNDNODATA; + proofs[DNS_VALIDATOR_NODATAPROOF] = name; + } + if (!exists && setnearest) { + val->attributes |= VALATTR_FOUNDNOQNAME; + proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; + if (optout) + val->attributes |= VALATTR_FOUNDOPTOUT; + } + } + } + if (result != ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + /* + * To know we have a valid noqname and optout proofs we need to also + * have a valid closest encloser. Otherwise we could still be looking + * at proofs from the parent zone. + */ + if (dns_name_countlabels(closest) > 0 && + dns_name_countlabels(nearest) == + dns_name_countlabels(closest) + 1 && + dns_name_issubdomain(nearest, closest)) + { + val->attributes |= VALATTR_FOUNDCLOSEST; + result = dns_name_concatenate(dns_wildcardname, closest, + dns_fixedname_name(&val->wild), + NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } else { + val->attributes &= ~VALATTR_FOUNDNOQNAME; + val->attributes &= ~VALATTR_FOUNDOPTOUT; + proofs[DNS_VALIDATOR_NOQNAMEPROOF] = NULL; + } + + /* + * Do we need to check for the wildcard? + */ + if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 && + (val->attributes & VALATTR_FOUNDCLOSEST) != 0 && + (((val->attributes & VALATTR_NEEDNODATA) != 0 && + (val->attributes & VALATTR_FOUNDNODATA) == 0) || + (val->attributes & VALATTR_NEEDNOWILDCARD) != 0)) { + result = checkwildcard(val, dns_rdatatype_nsec3, zonename); + if (result != ISC_R_SUCCESS) + return (result); + } + return (result); +} + /*% * Prove a negative answer is good or that there is a NOQNAME when the * answer is from a wildcard. @@ -2220,7 +2860,10 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { if ((val->attributes & VALATTR_NEEDNODATA) == 0 && (val->attributes & VALATTR_NEEDNOWILDCARD) == 0 && (val->attributes & VALATTR_NEEDNOQNAME) != 0) { - if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0) { + if ((val->attributes & VALATTR_FOUNDNOQNAME) == 0) + findnsec3proofs(val); + if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 && + (val->attributes & VALATTR_FOUNDCLOSEST) != 0) { validator_log(val, ISC_LOG_DEBUG(3), "noqname proof found"); validator_log(val, ISC_LOG_DEBUG(3), @@ -2228,34 +2871,57 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { val->event->rdataset->trust = dns_trust_secure; val->event->sigrdataset->trust = dns_trust_secure; return (ISC_R_SUCCESS); + } else if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0 && + dns_name_countlabels(dns_fixedname_name(&val->wild)) + != 0) { + validator_log(val, ISC_LOG_DEBUG(3), + "optout proof found"); + val->event->optout = ISC_TRUE; + markanswer(val); + return (ISC_R_SUCCESS); + } else if ((val->attributes & VALATTR_FOUNDUNKNOWN) != 0) { + validator_log(val, ISC_LOG_DEBUG(3), + "unknown NSEC3 hash algorithm found"); + markanswer(val); + return (ISC_R_SUCCESS); } validator_log(val, ISC_LOG_DEBUG(3), "noqname proof not found"); return (DNS_R_NOVALIDNSEC); } + if ((val->attributes & VALATTR_FOUNDNOQNAME) == 0 && + (val->attributes & VALATTR_FOUNDNODATA) == 0) + findnsec3proofs(val); + /* * Do we need to check for the wildcard? */ if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 && + (val->attributes & VALATTR_FOUNDCLOSEST) != 0 && (((val->attributes & VALATTR_NEEDNODATA) != 0 && (val->attributes & VALATTR_FOUNDNODATA) == 0) || (val->attributes & VALATTR_NEEDNOWILDCARD) != 0)) { - result = checkwildcard(val); + result = checkwildcard(val, dns_rdatatype_nsec, NULL); if (result != ISC_R_SUCCESS) return (result); } if (((val->attributes & VALATTR_NEEDNODATA) != 0 && - (val->attributes & VALATTR_FOUNDNODATA) != 0) || + ((val->attributes & VALATTR_FOUNDNODATA) != 0 || + (val->attributes & VALATTR_FOUNDOPTOUT) != 0)) || ((val->attributes & VALATTR_NEEDNOQNAME) != 0 && (val->attributes & VALATTR_FOUNDNOQNAME) != 0 && (val->attributes & VALATTR_NEEDNOWILDCARD) != 0 && - (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0)) { + (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0 && + (val->attributes & VALATTR_FOUNDCLOSEST) != 0)) { + if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0) + val->event->optout = ISC_TRUE; validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof(s) found"); return (ISC_R_SUCCESS); } + findnsec3proofs(val); validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof(s) not found"); @@ -2380,7 +3046,7 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { } /*% - * Start the DLV lookup proccess. + * Start the DLV lookup process. * * Returns * \li ISC_R_SUCCESS @@ -2424,7 +3090,7 @@ startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) { validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found", namebuf); dlv_validator_start(val); return (DNS_R_WAIT); - } + } validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found with no supported " "algorithms", namebuf); markanswer(val); @@ -2566,9 +3232,13 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) dns_name_t *secroot; dns_name_t *tname; char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_t *found; + dns_fixedname_t fixedfound; dns_fixedname_init(&fixedsecroot); secroot = dns_fixedname_name(&fixedsecroot); + dns_fixedname_init(&fixedfound); + found = dns_fixedname_name(&fixedfound); if (val->havedlvsep) dns_name_copy(dns_fixedname_name(&val->dlvsep), secroot, NULL); else { @@ -2676,6 +3346,28 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) goto out; return (DNS_R_WAIT); } + /* + * Zones using NSEC3 don't return a NSEC RRset so + * we need to use dns_view_findzonecut2 to find + * the zone cut. + */ + if (result == DNS_R_NXRRSET && + !dns_rdataset_isassociated(&val->frdataset) && + dns_view_findzonecut2(val->view, tname, found, + 0, 0, ISC_FALSE, ISC_FALSE, + NULL, NULL) == ISC_R_SUCCESS && + dns_name_equal(tname, found)) { + if (val->mustbesecure) { + validator_log(val, ISC_LOG_WARNING, + "must be secure failure"); + return (DNS_R_MUSTBESECURE); + } + if (val->view->dlv == NULL || DLVTRIED(val)) { + markanswer(val); + return (ISC_R_SUCCESS); + } + return (startfinddlvsep(val, tname)); + } if (val->frdataset.trust < dns_trust_secure) { /* * This shouldn't happen, since the negative @@ -2775,6 +3467,15 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) return (DNS_R_WAIT); } } + +/* + if ((val->attributes & VALATTR_NEEDOPTOUT) == 0 && + val->event->message != NULL) { + val->attributes |= VALATTR_NEEDOPTOUT; + return (nsecvalidate(val, ISC_FALSE)); + } +*/ + validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed"); return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */ @@ -2808,7 +3509,7 @@ dlv_validator_start(dns_validator_t *val) { /*% * Start the validation process. * - * Attempt to valididate the answer based on the category it appears to + * Attempt to validate the answer based on the category it appears to * fall in. * \li 1. secure positive answer. * \li 2. unsecure positive answer. @@ -2829,7 +3530,7 @@ validator_start(isc_task_t *task, isc_event_t *event) { vevent = (dns_validatorevent_t *)event; val = vevent->validator; - /* If the validator has been cancelled, val->event == NULL */ + /* If the validator has been canceled, val->event == NULL */ if (val->event == NULL) return; @@ -2955,6 +3656,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, event->sigrdataset = sigrdataset; event->message = message; memset(event->proofs, 0, sizeof(event->proofs)); + event->optout = ISC_FALSE; result = isc_mutex_init(&val->lock); if (result != ISC_R_SUCCESS) goto cleanup_event; @@ -2984,6 +3686,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, dns_rdataset_init(&val->frdataset); dns_rdataset_init(&val->fsigrdataset); dns_fixedname_init(&val->wild); + dns_fixedname_init(&val->nearest); + dns_fixedname_init(&val->closest); ISC_LINK_INIT(val, link); val->magic = VALIDATOR_MAGIC; diff --git a/lib/dns/version.c b/lib/dns/version.c index 1c03774..fbc8889 100644 --- a/lib/dns/version.c +++ b/lib/dns/version.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: version.c,v 1.11.18.2 2005/04/29 00:16:07 marka Exp $ */ +/* $Id: version.c,v 1.15 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/view.c b/lib/dns/view.c index 4851cf0..5f1447a 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,15 +15,16 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.126.18.16 2008/06/17 23:46:03 tbox Exp $ */ +/* $Id: view.c,v 1.150.84.2 2009/01/29 23:47:44 tbox Exp $ */ /*! \file */ #include <config.h> #include <isc/hash.h> -#include <isc/task.h> +#include <isc/stats.h> #include <isc/string.h> /* Required for HP/UX (and others?) */ +#include <isc/task.h> #include <isc/util.h> #include <dns/acache.h> @@ -43,6 +44,7 @@ #include <dns/request.h> #include <dns/resolver.h> #include <dns/result.h> +#include <dns/stats.h> #include <dns/tsig.h> #include <dns/zone.h> #include <dns/zt.h> @@ -151,6 +153,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->delonly = NULL; view->rootdelonly = ISC_FALSE; view->rootexclude = NULL; + view->resstats = NULL; + view->resquerystats = NULL; /* * Initialize configuration data with default values. @@ -165,8 +169,14 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->minimalresponses = ISC_FALSE; view->transfer_format = dns_one_answer; view->queryacl = NULL; + view->queryonacl = NULL; view->recursionacl = NULL; + view->recursiononacl = NULL; view->sortlist = NULL; + view->transferacl = NULL; + view->notifyacl = NULL; + view->updateacl = NULL; + view->upfwdacl = NULL; view->requestixfr = ISC_TRUE; view->provideixfr = ISC_TRUE; view->maxcachettl = 7 * 24 * 3600; @@ -286,10 +296,22 @@ destroy(dns_view_t *view) { dns_acl_detach(&view->matchdestinations); if (view->queryacl != NULL) dns_acl_detach(&view->queryacl); + if (view->queryonacl != NULL) + dns_acl_detach(&view->queryonacl); if (view->recursionacl != NULL) dns_acl_detach(&view->recursionacl); + if (view->recursiononacl != NULL) + dns_acl_detach(&view->recursiononacl); if (view->sortlist != NULL) dns_acl_detach(&view->sortlist); + if (view->transferacl != NULL) + dns_acl_detach(&view->transferacl); + if (view->notifyacl != NULL) + dns_acl_detach(&view->notifyacl); + if (view->updateacl != NULL) + dns_acl_detach(&view->updateacl); + if (view->upfwdacl != NULL) + dns_acl_detach(&view->upfwdacl); if (view->delonly != NULL) { dns_name_t *name; int i; @@ -325,6 +347,10 @@ destroy(dns_view_t *view) { sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH); view->rootexclude = NULL; } + if (view->resstats != NULL) + isc_stats_detach(&view->resstats); + if (view->resquerystats != NULL) + dns_stats_detach(&view->resquerystats); dns_keytable_detach(&view->trustedkeys); dns_keytable_detach(&view->secroots); dns_fwdtable_destroy(&view->fwdtable); @@ -571,6 +597,7 @@ dns_view_createresolver(dns_view_t *view, } result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb); + isc_mem_setname(mctx, "ADB", NULL); isc_mem_detach(&mctx); if (result != ISC_R_SUCCESS) { dns_resolver_shutdown(view->resolver); @@ -1129,6 +1156,55 @@ dns_viewlist_find(dns_viewlist_t *list, const char *name, } isc_result_t +dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name, + isc_boolean_t allclasses, dns_rdataclass_t rdclass, + dns_zone_t **zonep) +{ + dns_view_t *view; + isc_result_t result; + dns_zone_t *zone1 = NULL, *zone2 = NULL; + dns_zone_t **zp = NULL;; + + REQUIRE(list != NULL); + for (view = ISC_LIST_HEAD(*list); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (allclasses == ISC_FALSE && view->rdclass != rdclass) + continue; + + /* + * If the zone is defined in more than one view, + * treat it as not found. + */ + zp = (zone1 == NULL) ? &zone1 : &zone2; + result = dns_zt_find(view->zonetable, name, 0, NULL, zp); + INSIST(result == ISC_R_SUCCESS || + result == ISC_R_NOTFOUND || + result == DNS_R_PARTIALMATCH); + + /* Treat a partial match as no match */ + if (result == DNS_R_PARTIALMATCH) { + dns_zone_detach(zp); + result = ISC_R_NOTFOUND; + } + + if (zone2 != NULL) { + dns_zone_detach(&zone1); + dns_zone_detach(&zone2); + return (ISC_R_NOTFOUND); + } + } + + if (zone1 != NULL) { + dns_zone_attach(zone1, zonep); + dns_zone_detach(&zone1); + return (ISC_R_SUCCESS); + } + + return (ISC_R_NOTFOUND); +} + +isc_result_t dns_view_load(dns_view_t *view, isc_boolean_t stop) { REQUIRE(DNS_VIEW_VALID(view)); @@ -1354,3 +1430,39 @@ dns_view_freezezones(dns_view_t *view, isc_boolean_t value) { REQUIRE(DNS_VIEW_VALID(view)); return (dns_zt_freezezones(view->zonetable, value)); } + +void +dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + REQUIRE(view->resstats == NULL); + + isc_stats_attach(stats, &view->resstats); +} + +void +dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(statsp != NULL && *statsp == NULL); + + if (view->resstats != NULL) + isc_stats_attach(view->resstats, statsp); +} + +void +dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + REQUIRE(view->resquerystats == NULL); + + dns_stats_attach(stats, &view->resquerystats); +} + +void +dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(statsp != NULL && *statsp == NULL); + + if (view->resquerystats != NULL) + dns_stats_attach(view->resquerystats, statsp); +} diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 7171a37..4e3d2c3 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.c,v 1.135.18.23 2008/09/25 04:15:52 marka Exp $ */ +/* $Id: xfrin.c,v 1.166 2008/09/25 04:12:39 marka Exp $ */ /*! \file */ @@ -142,6 +142,11 @@ struct dns_xfrin_ctx { isc_boolean_t is_ixfr; unsigned int nmsg; /*%< Number of messages recvd */ + unsigned int nrecs; /*%< Number of records recvd */ + isc_uint64_t nbytes; /*%< Number of bytes received */ + + isc_time_t start; /*%< Start time of the transfer */ + isc_time_t end; /*%< End time of the transfer */ dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */ isc_buffer_t *lasttsig; /*%< The last TSIG */ @@ -426,6 +431,8 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, { isc_result_t result; + xfr->nrecs++; + if (rdata->type == dns_rdatatype_none || dns_rdatatype_ismeta(rdata->type)) FAIL(DNS_R_FORMERR); @@ -804,6 +811,9 @@ xfrin_create(isc_mem_t *mctx, /* end_serial */ xfr->nmsg = 0; + xfr->nrecs = 0; + xfr->nbytes = 0; + isc_time_now(&xfr->start); xfr->tsigkey = NULL; if (tsigkey != NULL) @@ -865,6 +875,7 @@ xfrin_start(dns_xfrin_ctx_t *xfr) { isc_sockaddr_pf(&xfr->sourceaddr), isc_sockettype_tcp, &xfr->socket)); + isc_socket_setname(xfr->socket, "xfrin", NULL); #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr, ISC_SOCKET_REUSEADDRESS)); @@ -908,8 +919,7 @@ static void xfrin_connect_done(isc_task_t *task, isc_event_t *event) { isc_socket_connev_t *cev = (isc_socket_connev_t *) event; dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg; - isc_result_t evresult = cev->result; - isc_result_t result; + isc_result_t result = cev->result; char sourcetext[ISC_SOCKADDR_FORMATSIZE]; isc_sockaddr_t sockaddr; @@ -926,7 +936,18 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) { return; } - CHECK(evresult); + if (result != ISC_R_SUCCESS) { + dns_zonemgr_t * zmgr = dns_zone_getmgr(xfr->zone); + isc_time_t now; + + if (zmgr != NULL) { + TIME_NOW(&now); + dns_zonemgr_unreachableadd(zmgr, &xfr->masteraddr, + &xfr->sourceaddr, &now); + } + goto failure; + } + result = isc_socket_getsockname(xfr->socket, &sockaddr); if (result == ISC_R_SUCCESS) { isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext)); @@ -1054,6 +1075,9 @@ xfrin_send_request(dns_xfrin_ctx_t *xfr) { xfr->checkid = ISC_TRUE; xfr->id++; xfr->nmsg = 0; + xfr->nrecs = 0; + xfr->nbytes = 0; + isc_time_now(&xfr->start); msg->id = xfr->id; if (xfr->tsigctx != NULL) dst_context_destroy(&xfr->tsigctx); @@ -1308,6 +1332,11 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { xfr->nmsg++; /* + * Update the number of bytes received. + */ + xfr->nbytes += tcpmsg->buffer.used; + + /* * Take the context back. */ INSIST(xfr->tsigctx == NULL); @@ -1373,6 +1402,9 @@ xfrin_timeout(isc_task_t *task, isc_event_t *event) { static void maybe_free(dns_xfrin_ctx_t *xfr) { + isc_uint64_t msecs; + isc_uint64_t persec; + REQUIRE(VALID_XFRIN(xfr)); if (! xfr->shuttingdown || xfr->refcount != 0 || @@ -1380,7 +1412,22 @@ maybe_free(dns_xfrin_ctx_t *xfr) { xfr->recvs != 0) return; - xfrin_log(xfr, ISC_LOG_INFO, "end of transfer"); + /* + * Calculate the length of time the transfer took, + * and print a log message with the bytes and rate. + */ + isc_time_now(&xfr->end); + msecs = isc_time_microdiff(&xfr->end, &xfr->start) / 1000; + if (msecs == 0) + msecs = 1; + persec = (xfr->nbytes * 1000) / msecs; + xfrin_log(xfr, ISC_LOG_INFO, + "Transfer completed: %d messages, %d records, " + "%" ISC_PRINT_QUADFORMAT "u bytes, " + "%u.%03u secs (%u bytes/sec)", + xfr->nmsg, xfr->nrecs, xfr->nbytes, + (unsigned int) (msecs / 1000), (unsigned int) (msecs % 1000), + (unsigned int) persec); if (xfr->socket != NULL) isc_socket_detach(&xfr->socket); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 36f303c..423b005 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,11 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.410.18.55 2008/10/24 01:43:17 tbox Exp $ */ +/* $Id: zone.c,v 1.483.36.6 2009/03/26 22:57:07 marka Exp $ */ /*! \file */ #include <config.h> +#include <errno.h> #include <isc/file.h> #include <isc/mutex.h> @@ -29,6 +30,9 @@ #include <isc/refcount.h> #include <isc/rwlock.h> #include <isc/serial.h> +#include <isc/strerror.h> +#include <isc/stats.h> +#include <isc/stdtime.h> #include <isc/string.h> #include <isc/taskpool.h> #include <isc/timer.h> @@ -40,29 +44,37 @@ #include <dns/callbacks.h> #include <dns/db.h> #include <dns/dbiterator.h> +#include <dns/dnssec.h> #include <dns/events.h> #include <dns/journal.h> +#include <dns/keyvalues.h> #include <dns/log.h> #include <dns/master.h> #include <dns/masterdump.h> #include <dns/message.h> #include <dns/name.h> +#include <dns/nsec.h> +#include <dns/nsec3.h> #include <dns/peer.h> #include <dns/rcode.h> #include <dns/rdataclass.h> #include <dns/rdatalist.h> #include <dns/rdataset.h> +#include <dns/rdatasetiter.h> #include <dns/rdatastruct.h> #include <dns/rdatatype.h> #include <dns/request.h> #include <dns/resolver.h> #include <dns/result.h> -#include <dns/stats.h> +#include <dns/soa.h> #include <dns/ssu.h> +#include <dns/stats.h> #include <dns/tsig.h> #include <dns/xfrin.h> #include <dns/zone.h> +#include <dst/dst.h> + #define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E') #define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC) @@ -90,6 +102,8 @@ #define RANGE(a, min, max) \ (((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max))) +#define NSEC3REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) + /* * Default values. */ @@ -111,6 +125,10 @@ typedef struct dns_load dns_load_t; typedef struct dns_forward dns_forward_t; typedef struct dns_io dns_io_t; typedef ISC_LIST(dns_io_t) dns_iolist_t; +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; #define DNS_ZONE_CHECKLOCK #ifdef DNS_ZONE_CHECKLOCK @@ -178,11 +196,16 @@ struct dns_zone { isc_time_t dumptime; isc_time_t loadtime; isc_time_t notifytime; + isc_time_t resigntime; + isc_time_t keywarntime; + isc_time_t signingtime; + isc_time_t nsec3chaintime; isc_uint32_t serial; isc_uint32_t refresh; isc_uint32_t retry; isc_uint32_t expire; isc_uint32_t minimum; + isc_stdtime_t key_expiry; char *keydirectory; isc_uint32_t maxrefresh; @@ -215,6 +238,7 @@ struct dns_zone { dns_acl_t *forward_acl; dns_acl_t *notify_acl; dns_acl_t *query_acl; + dns_acl_t *queryon_acl; dns_acl_t *xfr_acl; isc_boolean_t update_disabled; isc_boolean_t zero_no_soa_ttl; @@ -232,6 +256,7 @@ struct dns_zone { isc_event_t ctlevent; dns_ssutable_t *ssutable; isc_uint32_t sigvalidityinterval; + isc_uint32_t sigresigninginterval; dns_view_t *view; dns_acache_t *acache; dns_checkmxfunc_t checkmx; @@ -247,17 +272,39 @@ struct dns_zone { ISC_LINK(dns_zone_t) statelink; dns_zonelist_t *statelist; /*% - * Optional per-zone statistics counters (NULL if not present). + * Statistics counters about zone management. */ - isc_uint64_t *counters; + isc_stats_t *stats; + /*% + * Optional per-zone statistics counters. Counted outside of this + * module. + */ + isc_boolean_t requeststats_on; + isc_stats_t *requeststats; isc_uint32_t notifydelay; dns_isselffunc_t isself; void *isselfarg; + char * strnamerd; + char * strname; + char * strrdclass; + char * strviewname; + /*% * Serial number for deferred journal compaction. */ isc_uint32_t compact_serial; + /*% + * Keys that are signing the zone for the first time. + */ + dns_signinglist_t signing; + dns_nsec3chainlist_t nsec3chain; + /*% + * Signing / re-signing quantum stopping parameters. + */ + isc_uint32_t signatures; + isc_uint32_t nodes; + dns_rdatatype_t privatetype; }; #define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0)) @@ -287,7 +334,7 @@ struct dns_zone { * reload */ #define DNS_ZONEFLG_NOMASTERS 0x00001000U /*%< an attempt to refresh a * zone with no masters - * occured */ + * occurred */ #define DNS_ZONEFLG_LOADING 0x00002000U /*%< load from disk in progress*/ #define DNS_ZONEFLG_HAVETIMERS 0x00004000U /*%< timer values have been set * from SOA (if not set, we @@ -310,6 +357,21 @@ struct dns_zone { /* Flags for zone_load() */ #define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */ +#define UNREACH_CHACHE_SIZE 10U +#define UNREACH_HOLD_TIME 600 /* 10 minutes */ + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto failure; \ + } while (0) + +struct dns_unreachable { + isc_sockaddr_t remote; + isc_sockaddr_t local; + isc_uint32_t expire; + isc_uint32_t last; +}; + struct dns_zonemgr { unsigned int magic; isc_mem_t * mctx; @@ -338,6 +400,10 @@ struct dns_zonemgr { isc_uint32_t ioactive; dns_iolist_t high; dns_iolist_t low; + + /* Locked by rwlock. */ + /* LRU cache */ + struct dns_unreachable unreachable[UNREACH_CHACHE_SIZE]; }; /*% @@ -410,6 +476,56 @@ struct dns_io { isc_event_t *event; }; +/*% + * Hold state for when we are signing a zone with a new + * DNSKEY as result of an update. + */ +struct dns_signing { + unsigned int magic; + dns_db_t *db; + dns_dbiterator_t *dbiterator; + dns_secalg_t algorithm; + isc_uint16_t keyid; + isc_boolean_t delete; + isc_boolean_t done; + ISC_LINK(dns_signing_t) link; +}; + +struct dns_nsec3chain { + 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_LINK(dns_nsec3chain_t) link; +}; +/*%< + * 'dbiterator' contains a iterator for the database. If we are creating + * a NSEC3 chain only the non-NSEC3 nodes will be iterated. If we are + * removing a NSEC3 chain then both NSEC3 and non-NSEC3 nodes will be + * iterated. + * + * 'nsec3param' contains the parameters of the NSEC3 chain being created + * or removed. + * + * 'salt' is buffer space and is referenced via 'nsec3param.salt'. + * + * 'seen_nsec' will be set to true if, while iterating the zone to create a + * NSEC3 chain, a NSEC record is seen. + * + * 'delete_nsec' will be set to true if, at the completion of the creation + * of a NSEC3 chain, 'seen_nsec' is true. If 'delete_nsec' is true then we + * are in the process of deleting the NSEC chain. + * + * 'save_delete_nsec' is used to store the initial state of 'delete_nsec' + * so it can be recovered in the event of a error. + */ + + #define SEND_BUFFER_SIZE 2048 static void zone_settimer(dns_zone_t *, isc_time_t *); @@ -436,6 +552,10 @@ static void zone_shutdown(isc_task_t *, isc_event_t *); static void zone_loaddone(void *arg, isc_result_t result); static isc_result_t zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime); +static void zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length); +static void zone_name_tostr(dns_zone_t *zone, char *buf, size_t length); +static void zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length); +static void zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length); #if 0 /* ondestroy example */ @@ -484,6 +604,12 @@ static void zone_saveunique(dns_zone_t *zone, const char *path, static void zone_maintenance(dns_zone_t *zone); static void zone_notify(dns_zone_t *zone, isc_time_t *now); static void dump_done(void *arg, isc_result_t result); +static isc_boolean_t dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, + isc_sockaddr_t *remote, + isc_sockaddr_t *local, + isc_time_t *now); +static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, + isc_uint16_t keyid, isc_boolean_t delete); #define ENTER zone_debuglog(zone, me, 1, "enter") @@ -518,6 +644,15 @@ static const char *dbargv_default[] = { "rbt" }; } \ } while (0) +/*% + * Increment resolver-related statistics counters. Zone must be locked. + */ +static inline void +inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { + if (zone->stats != NULL) + isc_stats_increment(zone->stats, counter); +} + /*** *** Public functions. ***/ @@ -559,8 +694,12 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { goto free_dblock; zone->irefs = 0; dns_name_init(&zone->origin, NULL); + zone->strnamerd = NULL; + zone->strname = NULL; + zone->strrdclass = NULL; + zone->strviewname = NULL; zone->masterfile = NULL; - zone->masterformat = dns_masterformat_none; + zone->masterformat = dns_masterformat_none; zone->keydirectory = NULL; zone->journalsize = -1; zone->journal = NULL; @@ -575,6 +714,10 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { isc_time_settoepoch(&zone->dumptime); isc_time_settoepoch(&zone->loadtime); zone->notifytime = now; + isc_time_settoepoch(&zone->resigntime); + isc_time_settoepoch(&zone->keywarntime); + isc_time_settoepoch(&zone->signingtime); + isc_time_settoepoch(&zone->nsec3chaintime); zone->serial = 0; zone->refresh = DNS_ZONE_DEFAULTREFRESH; zone->retry = DNS_ZONE_DEFAULTRETRY; @@ -597,6 +740,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->forward_acl = NULL; zone->notify_acl = NULL; zone->query_acl = NULL; + zone->queryon_acl = NULL; zone->xfr_acl = NULL; zone->update_disabled = ISC_FALSE; zone->zero_no_soa_ttl = ISC_TRUE; @@ -622,6 +766,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->maxxfrout = MAX_XFER_TIME; zone->ssutable = NULL; zone->sigvalidityinterval = 30 * 24 * 3600; + zone->sigresigninginterval = 7 * 24 * 3600; zone->view = NULL; zone->acache = NULL; zone->checkmx = NULL; @@ -629,10 +774,17 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->checkns = NULL; ISC_LINK_INIT(zone, statelink); zone->statelist = NULL; - zone->counters = NULL; + zone->stats = NULL; + zone->requeststats_on = ISC_FALSE; + zone->requeststats = NULL; zone->notifydelay = 5; zone->isself = NULL; zone->isselfarg = NULL; + ISC_LIST_INIT(zone->signing); + ISC_LIST_INIT(zone->nsec3chain); + zone->signatures = 10; + zone->nodes = 100; + zone->privatetype = (dns_rdatatype_t)0xffffU; zone->magic = ZONE_MAGIC; @@ -669,6 +821,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { static void zone_free(dns_zone_t *zone) { isc_mem_t *mctx = NULL; + dns_signing_t *signing; + dns_nsec3chain_t *nsec3chain; REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(isc_refcount_current(&zone->erefs) == 0); @@ -687,10 +841,26 @@ zone_free(dns_zone_t *zone) { if (zone->task != NULL) isc_task_detach(&zone->task); - if (zone->zmgr) + if (zone->zmgr != NULL) dns_zonemgr_releasezone(zone->zmgr, zone); /* Unmanaged objects */ + for (signing = ISC_LIST_HEAD(zone->signing); + signing != NULL; + signing = ISC_LIST_HEAD(zone->signing)) { + ISC_LIST_UNLINK(zone->signing, signing, link); + dns_db_detach(&signing->db); + dns_dbiterator_destroy(&signing->dbiterator); + isc_mem_put(zone->mctx, signing, sizeof *signing); + } + for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); + nsec3chain != NULL; + nsec3chain = ISC_LIST_HEAD(zone->nsec3chain)) { + ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); + dns_db_detach(&nsec3chain->db); + dns_dbiterator_destroy(&nsec3chain->dbiterator); + isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); + } if (zone->masterfile != NULL) isc_mem_free(zone->mctx, zone->masterfile); zone->masterfile = NULL; @@ -701,8 +871,10 @@ zone_free(dns_zone_t *zone) { if (zone->journal != NULL) isc_mem_free(zone->mctx, zone->journal); zone->journal = NULL; - if (zone->counters != NULL) - dns_stats_freecounters(zone->mctx, &zone->counters); + if (zone->stats != NULL) + isc_stats_detach(&zone->stats); + if (zone->requeststats != NULL) + isc_stats_detach(&zone->requeststats); if (zone->db != NULL) zone_detachdb(zone); if (zone->acache != NULL) @@ -721,10 +893,20 @@ zone_free(dns_zone_t *zone) { dns_acl_detach(&zone->notify_acl); if (zone->query_acl != NULL) dns_acl_detach(&zone->query_acl); + if (zone->queryon_acl != NULL) + dns_acl_detach(&zone->queryon_acl); if (zone->xfr_acl != NULL) dns_acl_detach(&zone->xfr_acl); if (dns_name_dynamic(&zone->origin)) dns_name_free(&zone->origin, zone->mctx); + if (zone->strnamerd != NULL) + isc_mem_free(zone->mctx, zone->strnamerd); + if (zone->strname != NULL) + isc_mem_free(zone->mctx, zone->strname); + if (zone->strrdclass != NULL) + isc_mem_free(zone->mctx, zone->strrdclass); + if (zone->strviewname != NULL) + isc_mem_free(zone->mctx, zone->strviewname); if (zone->ssutable != NULL) dns_ssutable_detach(&zone->ssutable); @@ -743,6 +925,7 @@ zone_free(dns_zone_t *zone) { */ void dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) { + char namebuf[1024]; REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(rdclass != dns_rdataclass_none); @@ -754,11 +937,22 @@ dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) { REQUIRE(zone->rdclass == dns_rdataclass_none || zone->rdclass == rdclass); zone->rdclass = rdclass; + + if (zone->strnamerd != NULL) + isc_mem_free(zone->mctx, zone->strnamerd); + if (zone->strrdclass != NULL) + isc_mem_free(zone->mctx, zone->strrdclass); + + zone_namerd_tostr(zone, namebuf, sizeof namebuf); + zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); + zone_rdclass_tostr(zone, namebuf, sizeof namebuf); + zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf); + UNLOCK_ZONE(zone); } dns_rdataclass_t -dns_zone_getclass(dns_zone_t *zone){ +dns_zone_getclass(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); return (zone->rdclass); @@ -773,6 +967,19 @@ dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) { UNLOCK_ZONE(zone); } +isc_uint32_t +dns_zone_getserial(dns_zone_t *zone) { + isc_uint32_t serial; + + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + serial = zone->serial; + UNLOCK_ZONE(zone); + + return (serial); +} + /* * Single shot. */ @@ -888,12 +1095,24 @@ dns_zone_setdbtype(dns_zone_t *zone, void dns_zone_setview(dns_zone_t *zone, dns_view_t *view) { + char namebuf[1024]; REQUIRE(DNS_ZONE_VALID(zone)); LOCK_ZONE(zone); if (zone->view != NULL) dns_view_weakdetach(&zone->view); dns_view_weakattach(view, &zone->view); + + if (zone->strviewname != NULL) + isc_mem_free(zone->mctx, zone->strviewname); + if (zone->strnamerd != NULL) + isc_mem_free(zone->mctx, zone->strnamerd); + + zone_namerd_tostr(zone, namebuf, sizeof namebuf); + zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); + zone_viewname_tostr(zone, namebuf, sizeof namebuf); + zone->strviewname = isc_mem_strdup(zone->mctx, namebuf); + UNLOCK_ZONE(zone); } @@ -909,6 +1128,7 @@ dns_zone_getview(dns_zone_t *zone) { isc_result_t dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) { isc_result_t result; + char namebuf[1024]; REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(origin != NULL); @@ -919,6 +1139,17 @@ dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) { dns_name_init(&zone->origin, NULL); } result = dns_name_dup(origin, zone->mctx, &zone->origin); + + if (zone->strnamerd != NULL) + isc_mem_free(zone->mctx, zone->strnamerd); + if (zone->strname != NULL) + isc_mem_free(zone->mctx, zone->strname); + + zone_namerd_tostr(zone, namebuf, sizeof namebuf); + zone->strnamerd = isc_mem_strdup(zone->mctx, namebuf); + zone_name_tostr(zone, namebuf, sizeof namebuf); + zone->strname = isc_mem_strdup(zone->mctx, namebuf); + UNLOCK_ZONE(zone); return (result); } @@ -1064,11 +1295,7 @@ zone_isdynamic(dns_zone_t *zone) { zone->type == dns_zone_stub || (!zone->update_disabled && zone->ssutable != NULL) || (!zone->update_disabled && zone->update_acl != NULL && - ! (zone->update_acl->length == 1 && - zone->update_acl->elements[0].negative == ISC_TRUE - && - zone->update_acl->elements[0].type == - dns_aclelementtype_any)))); + !dns_acl_isnone(zone->update_acl)))); } @@ -1243,6 +1470,33 @@ dns_zone_loadnew(dns_zone_t *zone) { return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT)); } +static unsigned int +get_master_options(dns_zone_t *zone) { + unsigned int options; + + options = DNS_MASTER_ZONE; + if (zone->type == dns_zone_slave) + options |= DNS_MASTER_SLAVE; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) + options |= DNS_MASTER_CHECKNS; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) + options |= DNS_MASTER_FATALNS; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) + options |= DNS_MASTER_CHECKNAMES; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) + options |= DNS_MASTER_CHECKNAMESFAIL; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX)) + options |= DNS_MASTER_CHECKMX; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) + options |= DNS_MASTER_CHECKMXFAIL; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD)) + options |= DNS_MASTER_CHECKWILDCARD; + if (zone->type == dns_zone_master && + (zone->update_acl != NULL || zone->ssutable != NULL)) + options |= DNS_MASTER_RESIGN; + return (options); +} + static void zone_gotreadhandle(isc_task_t *task, isc_event_t *event) { dns_load_t *load = event->ev_arg; @@ -1257,28 +1511,14 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) { if (result == ISC_R_CANCELED) goto fail; - options = DNS_MASTER_ZONE; - if (load->zone->type == dns_zone_slave) - options |= DNS_MASTER_SLAVE; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNS)) - options |= DNS_MASTER_CHECKNS; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_FATALNS)) - options |= DNS_MASTER_FATALNS; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMES)) - options |= DNS_MASTER_CHECKNAMES; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMESFAIL)) - options |= DNS_MASTER_CHECKNAMESFAIL; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMX)) - options |= DNS_MASTER_CHECKMX; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMXFAIL)) - options |= DNS_MASTER_CHECKMXFAIL; - if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKWILDCARD)) - options |= DNS_MASTER_CHECKWILDCARD; - result = dns_master_loadfileinc2(load->zone->masterfile, + options = get_master_options(load->zone); + + result = dns_master_loadfileinc3(load->zone->masterfile, dns_db_origin(load->db), dns_db_origin(load->db), load->zone->rdclass, options, + load->zone->sigresigninginterval, &load->callbacks, task, zone_loaddone, load, &load->zone->lctx, load->zone->mctx, @@ -1334,25 +1574,10 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { isc_result_t tresult; unsigned int options; - options = DNS_MASTER_ZONE; + options = get_master_options(zone); + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS)) options |= DNS_MASTER_MANYERRORS; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) - options |= DNS_MASTER_CHECKNS; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) - options |= DNS_MASTER_FATALNS; - if (zone->type == dns_zone_slave) - options |= DNS_MASTER_SLAVE; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) - options |= DNS_MASTER_CHECKNAMES; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) - options |= DNS_MASTER_CHECKNAMESFAIL; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX)) - options |= DNS_MASTER_CHECKMX; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) - options |= DNS_MASTER_CHECKMXFAIL; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD)) - options |= DNS_MASTER_CHECKWILDCARD; if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) { load = isc_mem_get(zone->mctx, sizeof(*load)); @@ -1394,9 +1619,10 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { &callbacks.add_private); if (result != ISC_R_SUCCESS) return (result); - result = dns_master_loadfile2(zone->masterfile, &zone->origin, + result = dns_master_loadfile3(zone->masterfile, &zone->origin, &zone->origin, zone->rdclass, - options, &callbacks, zone->mctx, + options, zone->sigresigninginterval, + &callbacks, zone->mctx, zone->masterformat); tresult = dns_db_endload(db, &callbacks.add_private); if (result == ISC_R_SUCCESS) @@ -1727,7 +1953,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) { dns_rdataset_init(&rdataset); dns_rdata_init(&rdata); - result = dns_db_createiterator(db, ISC_FALSE, &dbiterator); + result = dns_db_createiterator(db, 0, &dbiterator); if (result != ISC_R_SUCCESS) return (ISC_TRUE); @@ -1890,6 +2116,292 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) { } +static void +resume_signingwithkey(dns_zone_t *zone) { + dns_dbnode_t *node = NULL; + dns_dbversion_t *version = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + isc_result_t result; + + result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_db_currentversion(zone->db, &version); + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(zone->db, node, version, + zone->privatetype, + dns_rdatatype_none, 0, + &rdataset, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdataset_current(&rdataset, &rdata); + if (rdata.length != 5 || rdata.data[4] != 0) { + dns_rdata_reset(&rdata); + continue; + } + + result = zone_signwithkey(zone, rdata.data[0], + (rdata.data[1] << 8) | rdata.data[2], ISC_TF(rdata.data[3])); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_signwithkey failed: %s", + dns_result_totext(result)); + } + dns_rdata_reset(&rdata); + } + dns_rdataset_disassociate(&rdataset); + + cleanup: + if (node != NULL) + dns_db_detachnode(zone->db, &node); + if (version != NULL) + dns_db_closeversion(zone->db, &version, ISC_FALSE); + +} + +static isc_result_t +zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { + dns_nsec3chain_t *nsec3chain, *current; + isc_result_t result; + isc_time_t now; + unsigned int options = 0; + + nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain); + if (nsec3chain == NULL) + return (ISC_R_NOMEMORY); + + nsec3chain->magic = 0; + nsec3chain->done = ISC_FALSE; + nsec3chain->db = NULL; + nsec3chain->dbiterator = NULL; + nsec3chain->nsec3param.common.rdclass = nsec3param->common.rdclass; + nsec3chain->nsec3param.common.rdtype = nsec3param->common.rdtype; + nsec3chain->nsec3param.hash = nsec3param->hash; + nsec3chain->nsec3param.iterations = nsec3param->iterations; + nsec3chain->nsec3param.flags = nsec3param->flags; + nsec3chain->nsec3param.salt_length = nsec3param->salt_length; + memcpy(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length); + nsec3chain->nsec3param.salt = nsec3chain->salt; + nsec3chain->seen_nsec = ISC_FALSE; + nsec3chain->delete_nsec = ISC_FALSE; + nsec3chain->save_delete_nsec = ISC_FALSE; + + for (current = ISC_LIST_HEAD(zone->nsec3chain); + current != NULL; + current = ISC_LIST_NEXT(current, link)) { + if (current->db == zone->db && + current->nsec3param.hash == nsec3param->hash && + current->nsec3param.iterations == nsec3param->iterations && + current->nsec3param.salt_length == nsec3param->salt_length + && !memcmp(current->nsec3param.salt, nsec3param->salt, + nsec3param->salt_length)) + current->done = ISC_TRUE; + } + + if (zone->db != NULL) { + dns_db_attach(zone->db, &nsec3chain->db); + if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0) + options = DNS_DB_NONSEC3; + result = dns_db_createiterator(nsec3chain->db, options, + &nsec3chain->dbiterator); + if (result == ISC_R_SUCCESS) + dns_dbiterator_first(nsec3chain->dbiterator); + if (result == ISC_R_SUCCESS) { + dns_dbiterator_pause(nsec3chain->dbiterator); + ISC_LIST_INITANDAPPEND(zone->nsec3chain, + nsec3chain, link); + nsec3chain = NULL; + if (isc_time_isepoch(&zone->nsec3chaintime)) { + TIME_NOW(&now); + zone->nsec3chaintime = now; + if (zone->task != NULL) + zone_settimer(zone, &now); + } + } + } else + result = ISC_R_NOTFOUND; + + if (nsec3chain != NULL) { + if (nsec3chain->db != NULL) + dns_db_detach(&nsec3chain->db); + if (nsec3chain->dbiterator != NULL) + dns_dbiterator_destroy(&nsec3chain->dbiterator); + isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); + } + return (result); +} + +static void +resume_addnsec3chain(dns_zone_t *zone) { + dns_dbnode_t *node = NULL; + dns_dbversion_t *version = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + isc_result_t result; + dns_rdata_nsec3param_t nsec3param; + + result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_db_currentversion(zone->db, &version); + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(zone->db, node, version, + dns_rdatatype_nsec3param, + dns_rdatatype_none, 0, + &rdataset, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 || + (nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) { + result = zone_addnsec3chain(zone, &nsec3param); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_addnsec3chain failed: %s", + dns_result_totext(result)); + } + } + dns_rdata_reset(&rdata); + } + dns_rdataset_disassociate(&rdataset); + + cleanup: + if (node != NULL) + dns_db_detachnode(zone->db, &node); + if (version != NULL) + dns_db_closeversion(zone->db, &version, ISC_FALSE); +} + +static void +set_resigntime(dns_zone_t *zone) { + dns_rdataset_t rdataset; + dns_fixedname_t fixed; + char namebuf[DNS_NAME_FORMATSIZE]; + unsigned int resign; + isc_result_t result; + isc_uint32_t nanosecs; + + dns_rdataset_init(&rdataset); + dns_fixedname_init(&fixed); + result = dns_db_getsigningtime(zone->db, &rdataset, + dns_fixedname_name(&fixed)); + if (result != ISC_R_SUCCESS) { + isc_time_settoepoch(&zone->resigntime); + return; + } + resign = rdataset.resign; + dns_name_format(dns_fixedname_name(&fixed), namebuf, sizeof(namebuf)); + dns_rdataset_disassociate(&rdataset); + isc_random_get(&nanosecs); + nanosecs %= 1000000000; + isc_time_set(&zone->resigntime, resign, nanosecs); +} + +static isc_result_t +check_nsec3param(dns_zone_t *zone, dns_db_t *db) { + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_dbversion_t *version = NULL; + dns_rdata_nsec3param_t nsec3param; + isc_boolean_t ok = ISC_FALSE; + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_boolean_t dynamic = (zone->type == dns_zone_master) ? + zone_isdynamic(zone) : ISC_FALSE; + + dns_rdataset_init(&rdataset); + result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "nsec3param lookup failure: %s", + dns_result_totext(result)); + return (result); + } + dns_db_currentversion(db, &version); + + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, + dns_rdatatype_none, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + goto cleanup; + } + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "nsec3param lookup failure: %s", + dns_result_totext(result)); + goto cleanup; + } + + /* + * For dynamic zones we must support every algorithm so we can + * regenerate all the NSEC3 chains. + * For non-dynamic zones we only need to find a supported algorithm. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) + { + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + dns_rdata_reset(&rdata); + INSIST(result == ISC_R_SUCCESS); + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NSEC3TESTZONE) && + nsec3param.hash == DNS_NSEC3_UNKNOWNALG && !dynamic) + { + dns_zone_log(zone, ISC_LOG_WARNING, + "nsec3 test \"unknown\" hash algorithm found: %u", + nsec3param.hash); + ok = ISC_TRUE; + } else if (!dns_nsec3_supportedhash(nsec3param.hash)) { + if (dynamic) { + dns_zone_log(zone, ISC_LOG_ERROR, + "unsupported nsec3 hash algorithm" + " in dynamic zone: %u", + nsec3param.hash); + result = DNS_R_BADZONE; + /* Stop second error message. */ + ok = ISC_TRUE; + break; + } else + dns_zone_log(zone, ISC_LOG_WARNING, + "unsupported nsec3 hash algorithm: %u", + nsec3param.hash); + } else + ok = ISC_TRUE; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + if (!ok) { + result = DNS_R_BADZONE; + dns_zone_log(zone, ISC_LOG_ERROR, + "no supported nsec3 hash algorithm"); + } + + cleanup: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detachnode(db, &node); + return (result); +} + static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_result_t result) @@ -1901,6 +2413,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_time_t now; isc_boolean_t needdump = ISC_FALSE; isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); + unsigned int options; TIME_NOW(&now); @@ -1945,7 +2458,12 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) && ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { - result = dns_journal_rollforward(zone->mctx, db, + if (zone->type == dns_zone_master && + (zone->update_acl != NULL || zone->ssutable != NULL)) + options = DNS_JOURNALOPT_RESIGN; + else + options = 0; + result = dns_journal_rollforward(zone->mctx, db, options, zone->journal); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND && result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL && @@ -1972,7 +2490,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, zone->loadtime = loadtime; dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded"); - /* * Obtain ns, soa and cname counts for top of zone. */ @@ -2010,6 +2527,11 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, result = DNS_R_BADZONE; goto cleanup; } + if (zone->type != dns_zone_stub) { + result = check_nsec3param(zone, db); + if (result != ISC_R_SUCCESS) + goto cleanup; + } if (zone->type == dns_zone_master && DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) && !integrity_checks(zone, db)) { @@ -2047,6 +2569,17 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, "zone may fail to transfer " "to slaves."); } + + if (zone->type == dns_zone_master && + (zone->update_acl != NULL || zone->ssutable != NULL) && + zone->sigresigninginterval < (3 * refresh) && + dns_db_issecure(db)) + { + dns_zone_log(zone, ISC_LOG_WARNING, + "sig-re-signing-interval less than " + "3 * refresh."); + } + zone->serial = serial; zone->refresh = RANGE(refresh, zone->minrefresh, zone->maxrefresh); @@ -2121,8 +2654,14 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, result = ISC_R_SUCCESS; if (needdump) zone_needdump(zone, DNS_DUMP_DELAY); - if (zone->task != NULL) + if (zone->task != NULL) { + if (zone->type == dns_zone_master) { + set_resigntime(zone); + resume_signingwithkey(zone); + resume_addnsec3chain(zone); + } zone_settimer(zone, &now); + } if (! dns_db_ispersistent(db)) dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", @@ -2809,7 +3348,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone, goto unlock; /* - * masters must countain count elements! + * masters must contain count elements! */ new = isc_mem_get(zone->mctx, count * sizeof(*new)); if (new == NULL) { @@ -2935,6 +3474,2432 @@ was_dumping(dns_zone_t *zone) { return (dumping); } +#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; + isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE; + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_dnskey_t dnskey; + + dns_rdataset_init(&rdataset); + CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); + CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, + &rdataset, NULL)); + CHECK(dns_rdataset_first(&rdataset)); + while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) { + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL)); + if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) + == DNS_KEYOWNER_ZONE) { + if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) + have_ksk = ISC_TRUE; + else + have_nonksk = ISC_TRUE; + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(&rdataset); + } + if (have_ksk && have_nonksk) + ret = ISC_TRUE; + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (ret); +} + +static isc_result_t +find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + isc_mem_t *mctx, unsigned int maxkeys, + dst_key_t **keys, unsigned int *nkeys) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + const char *directory = dns_zone_getkeydirectory(zone); + CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); + result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), + directory, mctx, maxkeys, keys, + nkeys); + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +static isc_result_t +offline(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, dns_name_t *name, + dns_ttl_t ttl, dns_rdata_t *rdata) +{ + isc_result_t result; + + if ((rdata->flags & DNS_RDATA_OFFLINE) != 0) + return (ISC_R_SUCCESS); + result = update_one_rr(db, ver, diff, DNS_DIFFOP_DELRESIGN, + name, ttl, rdata); + if (result != ISC_R_SUCCESS) + return (result); + rdata->flags |= DNS_RDATA_OFFLINE; + result = update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, + name, ttl, rdata); + return (result); +} + +static void +set_key_expiry_warning(dns_zone_t *zone, isc_stdtime_t when, isc_stdtime_t now) +{ + unsigned int delta; + + zone->key_expiry = when; + if (when <= now) { + dns_zone_log(zone, ISC_LOG_ERROR, + "DNSKEY RRSIG(s) have expired"); + isc_time_settoepoch(&zone->keywarntime); + } else if (when < now + 7 * 24 * 3600) { + dns_zone_log(zone, ISC_LOG_WARNING, + "DNSKEY RRSIG(s) will expire at %u", + when); /* XXXMPA convert to date. */ + delta = when - now; + delta--; /* loop prevention */ + delta /= 24 * 3600; /* to whole days */ + delta *= 24 * 3600; /* to seconds */ + isc_time_set(&zone->keywarntime, when - delta, 0); + } else { + dns_zone_log(zone, ISC_LOG_NOTICE, /* XXMPA ISC_LOG_DEBUG(1) */ + "setting keywarntime to %u - 7 days", + when); /* XXXMPA convert to date. */ + isc_time_set(&zone->keywarntime, when - 7 * 24 * 3600, 0); + } +} + +/* + * Delete expired RRsigs and any RRsigs we are about to re-sign. + * See also update.c:del_keysigs(). + */ +static isc_result_t +del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, + unsigned int nkeys, isc_stdtime_t now) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int i; + dns_rdata_rrsig_t rrsig; + isc_boolean_t found; + isc_stdtime_t warn = 0, maybe = 0; + + dns_rdataset_init(&rdataset); + + if (type == dns_rdatatype_nsec3) + result = dns_db_findnsec3node(db, name, ISC_FALSE, &node); + else + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig, type, + (isc_stdtime_t) 0, &rdataset, NULL); + dns_db_detachnode(db, &node); + + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + goto failure; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &rrsig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if (type != dns_rdatatype_dnskey) { + result = update_one_rr(db, ver, diff, + DNS_DIFFOP_DEL, name, + rdataset.ttl, &rdata); + dns_rdata_reset(&rdata); + if (result != ISC_R_SUCCESS) + break; + continue; + } + + /* + * RRSIG(DNSKEY) requires special processing. + */ + found = ISC_FALSE; + for (i = 0; i < nkeys; i++) { + if (rrsig.algorithm == dst_key_alg(keys[i]) && + rrsig.keyid == dst_key_id(keys[i])) { + found = ISC_TRUE; + /* + * Mark offline RRSIG(DNSKEY). + * We want the earliest offline expire time + * iff there is a new offline signature. + */ + if (!dst_key_isprivate(keys[i])) { + if (warn != 0 && + warn > rrsig.timeexpire) + warn = rrsig.timeexpire; + if (rdata.flags & DNS_RDATA_OFFLINE) { + if (maybe == 0 || + maybe > rrsig.timeexpire) + maybe = + rrsig.timeexpire; + break; + } + if (warn == 0) + warn = maybe; + if (warn == 0 || + warn > rrsig.timeexpire) + warn = rrsig.timeexpire; + result = offline(db, ver, diff, name, + rdataset.ttl, &rdata); + break; + } + result = update_one_rr(db, ver, diff, + DNS_DIFFOP_DEL, + name, rdataset.ttl, + &rdata); + break; + } + } + /* + * If there is not a matching DNSKEY then + * delete the RRSIG. + */ + if (!found) + result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, + name, rdataset.ttl, &rdata); + dns_rdata_reset(&rdata); + if (result != ISC_R_SUCCESS) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + if (warn != 0) + set_key_expiry_warning(zone, warn, now); + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +static isc_result_t +add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, + unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, + isc_stdtime_t expire, isc_boolean_t check_ksk) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t sig_rdata = DNS_RDATA_INIT; + unsigned char data[1024]; /* XXX */ + isc_buffer_t buffer; + unsigned int i; + + dns_rdataset_init(&rdataset); + isc_buffer_init(&buffer, data, sizeof(data)); + + if (type == dns_rdatatype_nsec3) + result = dns_db_findnsec3node(db, name, ISC_FALSE, &node); + else + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findrdataset(db, node, ver, type, 0, + (isc_stdtime_t) 0, &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + goto failure; + + for (i = 0; i < nkeys; i++) { + if (check_ksk && type != dns_rdatatype_dnskey && + (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0) + continue; + if (!dst_key_isprivate(keys[i])) + continue; + /* Calculate the signature, creating a RRSIG RDATA. */ + CHECK(dns_dnssec_sign(name, &rdataset, keys[i], + &inception, &expire, + mctx, &buffer, &sig_rdata)); + /* Update the database and journal with the RRSIG. */ + /* XXX inefficient - will cause dataset merging */ + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, + name, rdataset.ttl, &sig_rdata)); + dns_rdata_reset(&sig_rdata); + } + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +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; + dns_fixedname_t fixed; + dns_name_t *name; + dns_rdataset_t rdataset; + dns_rdatatype_t covers; + dst_key_t *zone_keys[MAXZONEKEYS]; + isc_boolean_t check_ksk; + isc_result_t result; + isc_stdtime_t now, inception, soaexpire, expire, stop; + isc_uint32_t jitter; + unsigned int i; + unsigned int nkeys = 0; + unsigned int resign; + + dns_rdataset_init(&rdataset); + dns_fixedname_init(&fixed); + dns_diff_init(zone->mctx, &sig_diff); + sig_diff.resign = zone->sigresigninginterval; + + /* + * Updates are disabled. Pause for 5 minutes. + */ + if (zone->update_disabled) { + result = ISC_R_FAILURE; + goto failure; + } + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + result = dns_db_newversion(db, &version); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:dns_db_newversion -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = find_zone_keys(zone, db, version, zone->mctx, MAXZONEKEYS, + zone_keys, &nkeys); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:find_zone_keys -> %s\n", + dns_result_totext(result)); + goto failure; + } + + isc_stdtime_get(&now); + inception = now - 3600; /* Allow for clock skew. */ + soaexpire = now + dns_zone_getsigvalidityinterval(zone); + /* + * Spread out signatures over time if they happen to be + * clumped. We don't do this for each add_sigs() call as + * we still want some clustering to occur. + */ + isc_random_get(&jitter); + expire = soaexpire - jitter % 3600; + stop = now + 5; + + check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); + if (check_ksk) + check_ksk = ksk_sanity(db, version); + + name = dns_fixedname_name(&fixed); + result = dns_db_getsigningtime(db, &rdataset, name); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:dns_db_getsigningtime -> %s\n", + dns_result_totext(result)); + } + + i = 0; + while (result == ISC_R_SUCCESS) { + resign = rdataset.resign; + covers = rdataset.covers; + /* + * Stop if we hit the SOA as that means we have walked the + * entire zone. The SOA record should always be the most + * recent signature. + */ + /* XXXMPA increase number of RRsets signed pre call */ + if (covers == dns_rdatatype_soa || i++ > zone->signatures || + resign > stop) { + /* + * Ensure that we don't loop resigning the SOA. + */ + if (covers == dns_rdatatype_soa) + dns_db_resigned(db, &rdataset, version); + dns_rdataset_disassociate(&rdataset); + break; + } + + dns_db_resigned(db, &rdataset, version); + dns_rdataset_disassociate(&rdataset); + + result = del_sigs(zone, db, version, name, covers, &sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:del_sigs -> %s\n", + dns_result_totext(result)); + break; + } + result = add_sigs(db, version, name, covers, &sig_diff, + zone_keys, nkeys, zone->mctx, inception, + expire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:add_sigs -> %s\n", + dns_result_totext(result)); + break; + } + result = dns_db_getsigningtime(db, &rdataset, + dns_fixedname_name(&fixed)); + if (nkeys == 0 && result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + break; + } + if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:dns_db_getsigningtime -> %s\n", + dns_result_totext(result)); + } + + if (result != ISC_R_NOMORE && result != ISC_R_SUCCESS) + goto failure; + + result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = increment_soa_serial(db, version, &sig_diff, zone->mctx); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:increment_soa_serial -> %s\n", + dns_result_totext(result)); + goto failure; + } + + /* + * Generate maximum life time signatures so that the above loop + * termination is sensible. + */ + result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, zone->mctx, inception, + soaexpire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_resigninc:add_sigs -> %s\n", + dns_result_totext(result)); + 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; + } + + 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. + */ + dns_db_closeversion(db, &version, ISC_TRUE); + + failure: + dns_diff_clear(&sig_diff); + for (i = 0; i < nkeys; i++) + dst_key_free(&zone_keys[i]); + if (version != NULL) { + dns_db_closeversion(zone->db, &version, ISC_FALSE); + dns_db_detach(&db); + } else if (db != NULL) + dns_db_detach(&db); + if (result == ISC_R_SUCCESS) { + set_resigntime(zone); + LOCK_ZONE(zone); + zone_needdump(zone, DNS_DUMP_DELAY); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); + UNLOCK_ZONE(zone); + } else { + /* + * Something failed. Retry in 5 minutes. + */ + isc_interval_t ival; + isc_interval_set(&ival, 300, 0); + isc_time_nowplusinterval(&zone->resigntime, &ival); + } +} + +static isc_result_t +next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname, + dns_name_t *newname, isc_boolean_t bottom) +{ + isc_result_t result; + dns_dbiterator_t *dbit = NULL; + dns_rdatasetiter_t *rdsit = NULL; + dns_dbnode_t *node = NULL; + + CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit)); + CHECK(dns_dbiterator_seek(dbit, oldname)); + do { + result = dns_dbiterator_next(dbit); + if (result == ISC_R_NOMORE) + CHECK(dns_dbiterator_first(dbit)); + CHECK(dns_dbiterator_current(dbit, &node, newname)); + if (bottom && dns_name_issubdomain(newname, oldname) && + !dns_name_equal(newname, oldname)) { + dns_db_detachnode(db, &node); + continue; + } + /* + * Is this node empty? + */ + CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsit)); + result = dns_rdatasetiter_first(rdsit); + dns_db_detachnode(db, &node); + dns_rdatasetiter_destroy(&rdsit); + if (result != ISC_R_NOMORE) + break; + } while (1); + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + if (dbit != NULL) + dns_dbiterator_destroy(&dbit); + return (result); +} + +static void +set_bit(unsigned char *array, unsigned int index) { + unsigned int shift, mask; + + shift = 7 - (index % 8); + mask = 1 << shift; + + array[index / 8] |= mask; +} + +static isc_boolean_t +signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdatatype_t type, dst_key_t *key) +{ + isc_result_t result; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t rrsig; + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig, + type, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &rrsig, NULL); + INSIST(result == ISC_R_SUCCESS); + if (rrsig.algorithm == dst_key_alg(key) && + rrsig.keyid == dst_key_id(key)) { + dns_rdataset_disassociate(&rdataset); + return (ISC_TRUE); + } + dns_rdata_reset(&rdata); + } + dns_rdataset_disassociate(&rdataset); + return (ISC_FALSE); +} + +static isc_result_t +add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_dbnode_t *node, dns_ttl_t ttl, isc_boolean_t bottom, + dns_diff_t *diff) +{ + dns_fixedname_t fixed; + dns_name_t *next; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result; + unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE]; + + dns_fixedname_init(&fixed); + next = dns_fixedname_name(&fixed); + + CHECK(next_active(db, version, name, next, bottom)); + CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer, + &rdata)); + if (dns_name_equal(dns_db_origin(db), name)) { + /* + * Set the OPT bit to indicate that this is a + * partially secure zone. + */ + isc_region_t region; + + dns_rdata_toregion(&rdata, ®ion); + dns_name_fromregion(next, ®ion); + isc_region_consume(®ion, next->length); + INSIST(region.length > (2 + dns_rdatatype_opt / 8) && + region.base[0] == 0 && + region.base[1] > dns_rdatatype_opt / 8); + set_bit(region.base + 2, dns_rdatatype_opt); + } + CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, ttl, + &rdata)); + failure: + return (result); +} + +static isc_result_t +sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, + dns_dbversion_t *version, isc_boolean_t build_nsec3, + isc_boolean_t build_nsec, dst_key_t *key, + isc_stdtime_t inception, isc_stdtime_t expire, + unsigned int minimum, isc_boolean_t is_ksk, + isc_boolean_t *delegation, dns_diff_t *diff, + isc_int32_t *signatures, isc_mem_t *mctx) +{ + isc_result_t result; + dns_rdatasetiter_t *iterator = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t buffer; + unsigned char data[1024]; + isc_boolean_t seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec, + seen_nsec3, seen_ds; + isc_boolean_t bottom; + + result = dns_db_allrdatasets(db, node, version, 0, &iterator); + if (result != ISC_R_SUCCESS) { + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + return (result); + } + dns_rdataset_init(&rdataset); + isc_buffer_init(&buffer, data, sizeof(data)); + seen_rr = seen_soa = seen_ns = seen_dname = seen_nsec = + seen_nsec3 = seen_ds = ISC_FALSE; + for (result = dns_rdatasetiter_first(iterator); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iterator)) { + dns_rdatasetiter_current(iterator, &rdataset); + if (rdataset.type == dns_rdatatype_soa) + seen_soa = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_ns) + seen_ns = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_ds) + seen_ds = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_dname) + seen_dname = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_nsec) + seen_nsec = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_nsec3) + seen_nsec3 = ISC_TRUE; + seen_rr = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); + } + if (result != ISC_R_NOMORE) + goto failure; + if (seen_ns && !seen_soa) + *delegation = ISC_TRUE; + /* + * Going from insecure to NSEC3. + * Don't generate NSEC3 records for NSEC3 records. + */ + if (build_nsec3 && !seen_nsec3 && seen_rr) { + isc_boolean_t unsecure = !seen_ds && seen_ns && !seen_soa; + CHECK(dns_nsec3_addnsec3s(db, version, name, minimum, + unsecure, diff)); + (*signatures)--; + } + /* + * Going from insecure to NSEC. + * Don't generate NSEC records for NSEC3 records. + */ + if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) { + /* Build and add NSEC. */ + bottom = (seen_ns && !seen_soa) || seen_dname; + CHECK(add_nsec(db, version, name, node, minimum, bottom, diff)); + /* Count a NSEC generation as a signature generation. */ + (*signatures)--; + } + result = dns_rdatasetiter_first(iterator); + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(iterator, &rdataset); + if (rdataset.type == dns_rdatatype_soa || + rdataset.type == dns_rdatatype_rrsig) + goto next_rdataset; + if (is_ksk && rdataset.type != dns_rdatatype_dnskey) + goto next_rdataset; + if (*delegation && + rdataset.type != dns_rdatatype_ds && + rdataset.type != dns_rdatatype_nsec) + goto next_rdataset; + if (signed_with_key(db, node, version, rdataset.type, key)) + goto next_rdataset; + /* Calculate the signature, creating a RRSIG RDATA. */ + CHECK(dns_dnssec_sign(name, &rdataset, key, &inception, + &expire, mctx, &buffer, &rdata)); + /* Update the database and journal with the RRSIG. */ + /* XXX inefficient - will cause dataset merging */ + CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADDRESIGN, + name, rdataset.ttl, &rdata)); + dns_rdata_reset(&rdata); + (*signatures)--; + next_rdataset: + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(iterator); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + if (seen_dname) + *delegation = ISC_TRUE; +failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (iterator != NULL) + dns_rdatasetiter_destroy(&iterator); + return (result); +} + +static isc_result_t +updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_ttl_t minimum, isc_boolean_t *secureupdated, dns_diff_t *diff) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE]; + dns_rdataset_t rdataset; + dns_rdata_nsec_t nsec; + dns_dbnode_t *node = NULL; + + /* + * Check to see if the OPT bit has already been cleared. + */ + CHECK(dns_db_getoriginnode(db, &node)); + dns_rdataset_init(&rdataset); + CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec, + dns_rdatatype_none, 0, &rdataset, NULL)); + CHECK(dns_rdataset_first(&rdataset)); + dns_rdataset_current(&rdataset, &rdata); + + /* + * Find the NEXT name for building the new record. + */ + CHECK(dns_rdata_tostruct(&rdata, &nsec, NULL)); + + /* + * Delete the old NSEC record. + */ + CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DEL, name, minimum, + &rdata)); + dns_rdata_reset(&rdata); + + /* + * Add the new NSEC record. + */ + CHECK(dns_nsec_buildrdata(db, version, node, &nsec.next, nsecbuffer, + &rdata)); + CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, minimum, + &rdata)); + dns_rdata_reset(&rdata); + + if (secureupdated != NULL) + *secureupdated = ISC_TRUE; + + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + return (result); +} + +static isc_result_t +updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version, + dns_name_t *name, dns_rdatatype_t privatetype, + dns_diff_t *diff) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char data[5]; + isc_boolean_t seen_done = ISC_FALSE; + + dns_rdataset_init(&rdataset); + result = dns_db_getoriginnode(signing->db, &node); + if (result != ISC_R_SUCCESS) + goto failure; + + result = dns_db_findrdataset(signing->db, node, version, privatetype, + dns_rdatatype_none, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + result = ISC_R_SUCCESS; + goto failure; + } + if (result != ISC_R_SUCCESS) + goto failure; + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdataset_current(&rdataset, &rdata); + if (rdata.length != 5 || + rdata.data[0] != signing->algorithm || + rdata.data[1] != ((signing->keyid >> 8) & 0xff) || + rdata.data[2] != (signing->keyid & 0xff)) { + dns_rdata_reset(&rdata); + continue; + } + if (!signing->delete && rdata.data[4] != 0) + seen_done = ISC_TRUE; + else + CHECK(update_one_rr(signing->db, version, diff, + DNS_DIFFOP_DEL, name, rdataset.ttl, &rdata)); + dns_rdata_reset(&rdata); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + if (!signing->delete && !seen_done) { + + data[0] = signing->algorithm; + data[1] = (signing->keyid >> 8) & 0xff; + data[2] = signing->keyid & 0xff; + data[3] = 0; + data[4] = 1; + rdata.length = sizeof(data); + rdata.data = data; + rdata.type = privatetype; + rdata.rdclass = dns_db_class(signing->db); + CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD, + name, rdataset.ttl, &rdata)); + } + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(signing->db, &node); + return (result); +} + +static isc_result_t +fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain, + isc_boolean_t active, dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL; + dns_name_t *name = dns_db_origin(db); + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + dns_rdata_nsec3param_t nsec3param; + isc_result_t result; + isc_buffer_t buffer; + unsigned char parambuf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_ttl_t ttl = 0; + + dns_rdataset_init(&rdataset); + + result = dns_db_getoriginnode(db, &node); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, + 0, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto add; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Preserve the existing ttl. + */ + ttl = rdataset.ttl; + + /* + * Delete all NSEC3PARAM records which match that in nsec3chain. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); + + if (nsec3param.hash != chain->nsec3param.hash || + (active && nsec3param.flags != 0) || + nsec3param.iterations != chain->nsec3param.iterations || + nsec3param.salt_length != chain->nsec3param.salt_length || + memcmp(nsec3param.salt, chain->nsec3param.salt, + nsec3param.salt_length)) { + dns_rdata_reset(&rdata); + continue; + } + + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, + name, rdataset.ttl, &rdata)); + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto failure; + + add: + if ((chain->nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) { + result = ISC_R_SUCCESS; + goto failure; + } + + /* + * Add a NSEC3PARAM record which matches that in nsec3chain but + * with all flags bits cleared. + * + * Note: we do not clear chain->nsec3param.flags as this change + * may be reversed. + */ + isc_buffer_init(&buffer, ¶mbuf, sizeof(parambuf)); + CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), + dns_rdatatype_nsec3param, + &chain->nsec3param, &buffer)); + rdata.data[1] = 0; /* Clear flag bits. */ + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, ttl, &rdata)); + + failure: + dns_db_detachnode(db, &node); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + return (result); +} + +static isc_result_t +delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, + dns_name_t *name, dns_diff_t *diff) +{ + dns_rdataset_t rdataset; + isc_result_t result; + + dns_rdataset_init(&rdataset); + + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, + 0, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name, + rdataset.ttl, &rdata)); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + failure: + dns_rdataset_disassociate(&rdataset); + return (result); +} + +static isc_result_t +deletematchingnsec3(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, + dns_name_t *name, const dns_rdata_nsec3param_t *param, + dns_diff_t *diff) +{ + dns_rdataset_t rdataset; + dns_rdata_nsec3_t nsec3; + isc_result_t result; + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, + 0, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &nsec3, NULL)); + if (nsec3.hash != param->hash || + nsec3.iterations != param->iterations || + nsec3.salt_length != param->salt_length || + memcmp(nsec3.salt, param->salt, nsec3.salt_length)) + continue; + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name, + rdataset.ttl, &rdata)); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + failure: + dns_rdataset_disassociate(&rdataset); + return (result); +} + +static isc_result_t +need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, + const dns_rdata_nsec3param_t *param, + isc_boolean_t *answer, isc_boolean_t *updatensec) +{ + dns_dbnode_t *node = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec3param_t myparam; + dns_rdataset_t rdataset; + isc_result_t result; + + *answer = ISC_FALSE; + + result = dns_db_getoriginnode(db, &node); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, + 0, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto check_nsec3param; + + if (result != ISC_R_SUCCESS) + goto failure; + + CHECK(dns_rdataset_first(&rdataset)); + dns_rdataset_current(&rdataset, &rdata); + + if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt)) { + /* + * We have a complete NSEC chain. Signal to update + * the apex NSEC record. + */ + *updatensec = ISC_TRUE; + goto failure; + } + dns_rdataset_disassociate(&rdataset); + dns_rdata_reset(&rdata); + + check_nsec3param: + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, + 0, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + *answer = ISC_TRUE; + dns_db_detachnode(db, &node); + return (ISC_R_SUCCESS); + } + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + return (result); + } + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &myparam, NULL)); + dns_rdata_reset(&rdata); + /* + * Ignore any NSEC3PARAM removals. + */ + if (NSEC3REMOVE(myparam.flags)) + continue; + /* + * Ignore the chain that we are in the process of deleting. + */ + if (myparam.hash == param->hash && + myparam.iterations == param->iterations && + myparam.salt_length == param->salt_length && + !memcmp(myparam.salt, param->salt, myparam.salt_length)) + continue; + /* + * Found an active NSEC3 chain. + */ + break; + } + if (result == ISC_R_NOMORE) { + *answer = ISC_TRUE; + result = ISC_R_SUCCESS; + } + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + return (result); +} + +/* + * Incrementally build and sign a new NSEC3 chain using the parameters + * requested. + */ +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; + dns_diff_t sig_diff; + dns_diff_t nsec_diff; + dns_diff_t nsec3_diff; + dns_diff_t param_diff; + dns_fixedname_t fixed; + dns_fixedname_t nextfixed; + dns_name_t *name, *nextname; + dns_rdataset_t rdataset; + dns_nsec3chain_t *nsec3chain = NULL, *nextnsec3chain; + dns_nsec3chainlist_t cleanup; + dst_key_t *zone_keys[MAXZONEKEYS]; + isc_int32_t signatures; + isc_boolean_t check_ksk, is_ksk; + isc_boolean_t delegation; + isc_boolean_t first; + isc_result_t result; + isc_stdtime_t now, inception, soaexpire, expire, stop; + isc_uint32_t jitter; + unsigned int i; + unsigned int nkeys = 0; + isc_uint32_t nodes; + isc_boolean_t unsecure = ISC_FALSE; + isc_boolean_t seen_soa, seen_ns, seen_dname, seen_ds; + isc_boolean_t seen_nsec, seen_nsec3, seen_rr; + dns_rdatasetiter_t *iterator = NULL; + dns_difftuple_t *tuple; + isc_boolean_t buildnsecchain; + isc_boolean_t updatensec = ISC_FALSE; + + dns_rdataset_init(&rdataset); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_fixedname_init(&nextfixed); + nextname = dns_fixedname_name(&nextfixed); + dns_diff_init(zone->mctx, ¶m_diff); + dns_diff_init(zone->mctx, &nsec3_diff); + dns_diff_init(zone->mctx, &nsec_diff); + dns_diff_init(zone->mctx, &sig_diff); + sig_diff.resign = zone->sigresigninginterval; + ISC_LIST_INIT(cleanup); + + /* + * Updates are disabled. Pause for 5 minutes. + */ + if (zone->update_disabled) { + result = ISC_R_FAILURE; + goto failure; + } + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + result = dns_db_newversion(db, &version); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:dns_db_newversion -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = find_zone_keys(zone, db, version, zone->mctx, + MAXZONEKEYS, zone_keys, &nkeys); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:find_zone_keys -> %s\n", + dns_result_totext(result)); + goto failure; + } + + isc_stdtime_get(&now); + inception = now - 3600; /* Allow for clock skew. */ + soaexpire = now + dns_zone_getsigvalidityinterval(zone); + + /* + * Spread out signatures over time if they happen to be + * clumped. We don't do this for each add_sigs() call as + * we still want some clustering to occur. + */ + isc_random_get(&jitter); + expire = soaexpire - jitter % 3600; + stop = now + 5; + + check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); + if (check_ksk) + check_ksk = ksk_sanity(db, version); + + /* + * We keep pulling nodes off each iterator in turn until + * we have no more nodes to pull off or we reach the limits + * for this quantum. + */ + nodes = zone->nodes; + signatures = zone->signatures; + LOCK_ZONE(zone); + nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); + UNLOCK_ZONE(zone); + first = ISC_TRUE; + + if (nsec3chain != NULL) + nsec3chain->save_delete_nsec = nsec3chain->delete_nsec; + /* + * Generate new NSEC3 chains first. + */ + while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) { + LOCK_ZONE(zone); + nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link); + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (nsec3chain->done || nsec3chain->db != zone->db) { + ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); + ISC_LIST_APPEND(cleanup, nsec3chain, link); + } + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + UNLOCK_ZONE(zone); + if (ISC_LIST_TAIL(cleanup) == nsec3chain) + goto next_addchain; + + /* + * Possible future db. + */ + if (nsec3chain->db != db) { + goto next_addchain; + } + + if (NSEC3REMOVE(nsec3chain->nsec3param.flags)) + goto next_addchain; + + is_ksk = ISC_FALSE; + delegation = ISC_FALSE; + dns_dbiterator_current(nsec3chain->dbiterator, &node, name); + + if (nsec3chain->delete_nsec) { + delegation = ISC_FALSE; + dns_dbiterator_pause(nsec3chain->dbiterator); + CHECK(delete_nsec(db, version, node, name, &nsec_diff)); + goto next_addnode; + } + /* + * On the first pass we need to check if the current node + * has not been obscured. + */ + delegation = ISC_FALSE; + unsecure = ISC_FALSE; + if (first) { + dns_fixedname_t ffound; + dns_name_t *found; + dns_fixedname_init(&ffound); + found = dns_fixedname_name(&ffound); + result = dns_db_find(db, name, version, + dns_rdatatype_soa, + DNS_DBFIND_NOWILD, 0, NULL, found, + NULL, NULL); + if ((result == DNS_R_DELEGATION || + result == DNS_R_DNAME) && + !dns_name_equal(name, found)) { + /* + * Remember the obscuring name so that + * we skip all obscured names. + */ + dns_name_copy(found, name, NULL); + delegation = ISC_TRUE; + goto next_addnode; + } + } + + /* + * Check to see if this is a bottom of zone node. + */ + result = dns_db_allrdatasets(db, node, version, 0, &iterator); + if (result == ISC_R_NOTFOUND) /* Empty node? */ + goto next_addnode; + if (result != ISC_R_SUCCESS) + goto failure; + + seen_soa = seen_ns = seen_dname = seen_ds = seen_nsec = + ISC_FALSE; + for (result = dns_rdatasetiter_first(iterator); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iterator)) { + dns_rdatasetiter_current(iterator, &rdataset); + INSIST(rdataset.type != dns_rdatatype_nsec3); + if (rdataset.type == dns_rdatatype_soa) + seen_soa = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_ns) + seen_ns = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_dname) + seen_dname = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_ds) + seen_ds = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_nsec) + seen_nsec = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); + } + dns_rdatasetiter_destroy(&iterator); + /* + * Is there a NSEC chain than needs to be cleaned up? + */ + if (seen_nsec) + nsec3chain->seen_nsec = ISC_TRUE; + if (seen_ns && !seen_soa && !seen_ds) + unsecure = ISC_TRUE; + if ((seen_ns && !seen_soa) || seen_dname) + delegation = ISC_TRUE; + + /* + * Process one node. + */ + dns_dbiterator_pause(nsec3chain->dbiterator); + CHECK(dns_nsec3_addnsec3(db, version, name, + &nsec3chain->nsec3param, + zone->minimum, unsecure, &nsec3_diff)); + /* + * Treat each call to dns_nsec3_addnsec3() as if it's cost is + * two signatures. Additionally there will, in general, be + * two signature generated below. + * + * If we are only changing the optout flag the cost is half + * that of the cost of generating a completely new chain. + */ + signatures -= 4; + + /* + * Go onto next node. + */ + next_addnode: + first = ISC_FALSE; + dns_db_detachnode(db, &node); + do { + result = dns_dbiterator_next(nsec3chain->dbiterator); + + if (result == ISC_R_NOMORE && nsec3chain->delete_nsec) { + CHECK(fixup_nsec3param(db, version, nsec3chain, + ISC_FALSE, ¶m_diff)); + LOCK_ZONE(zone); + ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, + link); + UNLOCK_ZONE(zone); + ISC_LIST_APPEND(cleanup, nsec3chain, link); + goto next_addchain; + } + if (result == ISC_R_NOMORE) { + dns_dbiterator_pause(nsec3chain->dbiterator); + if (nsec3chain->seen_nsec) { + CHECK(fixup_nsec3param(db, version, + nsec3chain, + ISC_TRUE, + ¶m_diff)); + nsec3chain->delete_nsec = ISC_TRUE; + goto same_addchain; + } + CHECK(fixup_nsec3param(db, version, nsec3chain, + ISC_FALSE, ¶m_diff)); + LOCK_ZONE(zone); + ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, + link); + UNLOCK_ZONE(zone); + ISC_LIST_APPEND(cleanup, nsec3chain, link); + goto next_addchain; + } else if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "dns_dbiterator_next -> %s\n", + dns_result_totext(result)); + goto failure; + } else if (delegation) { + dns_dbiterator_current(nsec3chain->dbiterator, + &node, nextname); + dns_db_detachnode(db, &node); + if (!dns_name_issubdomain(nextname, name)) + break; + } else + break; + } while (1); + continue; + + same_addchain: + CHECK(dns_dbiterator_first(nsec3chain->dbiterator)); + first = ISC_TRUE; + continue; + + next_addchain: + dns_dbiterator_pause(nsec3chain->dbiterator); + nsec3chain = nextnsec3chain; + first = ISC_TRUE; + if (nsec3chain != NULL) + nsec3chain->save_delete_nsec = nsec3chain->delete_nsec; + } + + /* + * Process removals. + */ + LOCK_ZONE(zone); + nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); + UNLOCK_ZONE(zone); + first = ISC_TRUE; + buildnsecchain = ISC_FALSE; + while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) { + LOCK_ZONE(zone); + nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link); + UNLOCK_ZONE(zone); + + if (nsec3chain->db != db) + goto next_removechain; + + if (!NSEC3REMOVE(nsec3chain->nsec3param.flags)) + goto next_removechain; + + /* + * Work out if we need to build a NSEC chain as a consequence + * of removing this NSEC3 chain. + */ + if (first && !updatensec && + (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0) + CHECK(need_nsec_chain(db, version, + &nsec3chain->nsec3param, + &buildnsecchain, &updatensec)); + + dns_dbiterator_current(nsec3chain->dbiterator, &node, name); + delegation = ISC_FALSE; + + if (!buildnsecchain) { + /* + * Delete the NSECPARAM record that matches this chain. + */ + if (first) + CHECK(fixup_nsec3param(db, version, nsec3chain, + ISC_TRUE, ¶m_diff)); + + /* + * Delete the NSEC3 records. + */ + CHECK(deletematchingnsec3(db, version, node, name, + &nsec3chain->nsec3param, + &nsec3_diff)); + goto next_removenode; + } + + if (first) { + dns_fixedname_t ffound; + dns_name_t *found; + dns_fixedname_init(&ffound); + found = dns_fixedname_name(&ffound); + result = dns_db_find(db, name, version, + dns_rdatatype_soa, + DNS_DBFIND_NOWILD, 0, NULL, found, + NULL, NULL); + if ((result == DNS_R_DELEGATION || + result == DNS_R_DNAME) && + !dns_name_equal(name, found)) { + /* + * Remember the obscuring name so that + * we skip all obscured names. + */ + dns_name_copy(found, name, NULL); + delegation = ISC_TRUE; + goto next_removenode; + } + } + + /* + * Check to see if this is a bottom of zone node. + */ + result = dns_db_allrdatasets(db, node, version, 0, &iterator); + if (result == ISC_R_NOTFOUND) /* Empty node? */ + goto next_removenode; + if (result != ISC_R_SUCCESS) + goto failure; + + seen_soa = seen_ns = seen_dname = seen_nsec3 = seen_nsec = + seen_rr = ISC_FALSE; + for (result = dns_rdatasetiter_first(iterator); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iterator)) { + dns_rdatasetiter_current(iterator, &rdataset); + if (rdataset.type == dns_rdatatype_soa) + seen_soa = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_ns) + seen_ns = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_dname) + seen_dname = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_nsec) + seen_nsec = ISC_TRUE; + else if (rdataset.type == dns_rdatatype_nsec3) + seen_nsec3 = ISC_TRUE; + seen_rr = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); + } + dns_rdatasetiter_destroy(&iterator); + + if (!seen_rr || seen_nsec3 || seen_nsec) + goto next_removenode; + if ((seen_ns && !seen_soa) || seen_dname) + delegation = ISC_TRUE; + + CHECK(add_nsec(db, version, name, node, zone->minimum, + delegation, &nsec_diff)); + + next_removenode: + first = ISC_FALSE; + dns_db_detachnode(db, &node); + do { + result = dns_dbiterator_next(nsec3chain->dbiterator); + if (result == ISC_R_NOMORE && buildnsecchain) { + /* + * The NSEC chain should now be built. + * We can now remove the NSEC3 chain. + */ + updatensec = ISC_TRUE; + goto same_removechain; + } + if (result == ISC_R_NOMORE) { + LOCK_ZONE(zone); + ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, + link); + UNLOCK_ZONE(zone); + ISC_LIST_APPEND(cleanup, nsec3chain, link); + dns_dbiterator_pause(nsec3chain->dbiterator); + CHECK(fixup_nsec3param(db, version, nsec3chain, + ISC_FALSE, ¶m_diff)); + goto next_removechain; + } else if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "dns_dbiterator_next -> %s\n", + dns_result_totext(result)); + goto failure; + } else if (delegation) { + dns_dbiterator_current(nsec3chain->dbiterator, + &node, nextname); + dns_db_detachnode(db, &node); + if (!dns_name_issubdomain(nextname, name)) + break; + } else + break; + } while (1); + continue; + + same_removechain: + CHECK(dns_dbiterator_first(nsec3chain->dbiterator)); + buildnsecchain = ISC_FALSE; + first = ISC_TRUE; + continue; + + next_removechain: + dns_dbiterator_pause(nsec3chain->dbiterator); + nsec3chain = nextnsec3chain; + first = ISC_TRUE; + } + + /* + * Add / update signatures for the NSEC3 records. + */ + for (tuple = ISC_LIST_HEAD(nsec3_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_HEAD(nsec3_diff.tuples)) { + /* + * We have changed the NSEC3 RRset above so we need to update + * the signatures. + */ + result = del_sigs(zone, db, version, &tuple->name, + dns_rdatatype_nsec3, &sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + result = add_sigs(db, version, &tuple->name, + dns_rdatatype_nsec3, &sig_diff, zone_keys, + nkeys, zone->mctx, inception, expire, + check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + + do { + dns_difftuple_t *next = ISC_LIST_NEXT(tuple, link); + while (next != NULL && + !dns_name_equal(&tuple->name, &next->name)) + next = ISC_LIST_NEXT(next, link); + ISC_LIST_UNLINK(nsec3_diff.tuples, tuple, link); + dns_diff_appendminimal(&sig_diff, &tuple); + INSIST(tuple == NULL); + tuple = next; + } while (tuple != NULL); + } + + for (tuple = ISC_LIST_HEAD(param_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_HEAD(param_diff.tuples)) { + /* + * We have changed the NSEC3PARAM RRset above so we need to + * update the signatures. + */ + result = del_sigs(zone, db, version, &tuple->name, + dns_rdatatype_nsec3param, &sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + result = add_sigs(db, version, &tuple->name, + dns_rdatatype_nsec3param, &sig_diff, + zone_keys, nkeys, zone->mctx, inception, + expire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + ISC_LIST_UNLINK(param_diff.tuples, tuple, link); + dns_diff_appendminimal(&sig_diff, &tuple); + INSIST(tuple == NULL); + } + + if (updatensec) + CHECK(updatesecure(db, version, &zone->origin, zone->minimum, + NULL, &nsec_diff)); + + for (tuple = ISC_LIST_HEAD(nsec_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_HEAD(nsec_diff.tuples)) { + result = del_sigs(zone, db, version, &tuple->name, + dns_rdatatype_nsec, &sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + result = add_sigs(db, version, &tuple->name, + dns_rdatatype_nsec, &sig_diff, + zone_keys, nkeys, zone->mctx, inception, + expire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + ISC_LIST_UNLINK(nsec_diff.tuples, tuple, link); + dns_diff_appendminimal(&sig_diff, &tuple); + INSIST(tuple == NULL); + } + + /* + * If we made no effective changes to the zone then we can just + * cleanup otherwise we need to increment the serial. + */ + if (ISC_LIST_HEAD(sig_diff.tuples) == NULL) + goto done; + + result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "del_sigs -> %s\n", dns_result_totext(result)); + goto failure; + } + + result = increment_soa_serial(db, version, &sig_diff, zone->mctx); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "increment_soa_serial -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, zone->mctx, inception, + soaexpire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "add_sigs -> %s\n", dns_result_totext(result)); + 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; + } + } + + LOCK_ZONE(zone); + zone_needdump(zone, DNS_DUMP_DELAY); + UNLOCK_ZONE(zone); + + done: + /* + * Pause all iterators so that dns_db_closeversion() can succeed. + */ + LOCK_ZONE(zone); + for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); + nsec3chain != NULL; + nsec3chain = ISC_LIST_NEXT(nsec3chain, link)) + dns_dbiterator_pause(nsec3chain->dbiterator); + UNLOCK_ZONE(zone); + + /* + * Everything has succeeded. Commit the changes. + */ + dns_db_closeversion(db, &version, ISC_TRUE); + + /* + * Everything succeeded so we can clean these up now. + */ + nsec3chain = ISC_LIST_HEAD(cleanup); + while (nsec3chain != NULL) { + ISC_LIST_UNLINK(cleanup, nsec3chain, link); + dns_db_detach(&nsec3chain->db); + dns_dbiterator_destroy(&nsec3chain->dbiterator); + isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); + nsec3chain = ISC_LIST_HEAD(cleanup); + } + + set_resigntime(zone); + + failure: + /* + * On error roll back the current nsec3chain. + */ + if (result != ISC_R_SUCCESS && nsec3chain != NULL) { + if (nsec3chain->done) { + dns_db_detach(&nsec3chain->db); + dns_dbiterator_destroy(&nsec3chain->dbiterator); + isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); + } else { + result = dns_dbiterator_first(nsec3chain->dbiterator); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_dbiterator_pause(nsec3chain->dbiterator); + nsec3chain->delete_nsec = nsec3chain->save_delete_nsec; + } + } + + /* + * Rollback the cleanup list. + */ + nsec3chain = ISC_LIST_TAIL(cleanup); + while (nsec3chain != NULL) { + ISC_LIST_UNLINK(cleanup, nsec3chain, link); + if (nsec3chain->done) { + dns_db_detach(&nsec3chain->db); + dns_dbiterator_destroy(&nsec3chain->dbiterator); + isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain); + } else { + LOCK_ZONE(zone); + ISC_LIST_PREPEND(zone->nsec3chain, nsec3chain, link); + UNLOCK_ZONE(zone); + result = dns_dbiterator_first(nsec3chain->dbiterator); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_dbiterator_pause(nsec3chain->dbiterator); + nsec3chain->delete_nsec = nsec3chain->save_delete_nsec; + } + nsec3chain = ISC_LIST_TAIL(cleanup); + } + + LOCK_ZONE(zone); + for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain); + nsec3chain != NULL; + nsec3chain = ISC_LIST_NEXT(nsec3chain, link)) + dns_dbiterator_pause(nsec3chain->dbiterator); + UNLOCK_ZONE(zone); + + dns_diff_clear(¶m_diff); + dns_diff_clear(&nsec3_diff); + dns_diff_clear(&nsec_diff); + dns_diff_clear(&sig_diff); + + if (iterator != NULL) + dns_rdatasetiter_destroy(&iterator); + + for (i = 0; i < nkeys; i++) + dst_key_free(&zone_keys[i]); + + if (version != NULL) { + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); + } else if (db != NULL) + dns_db_detach(&db); + + LOCK_ZONE(zone); + if (ISC_LIST_HEAD(zone->nsec3chain) != NULL) { + isc_interval_t i; + if (zone->update_disabled || result != ISC_R_SUCCESS) + isc_interval_set(&i, 60, 0); /* 1 minute */ + else + isc_interval_set(&i, 0, 10000000); /* 10 ms */ + isc_time_nowplusinterval(&zone->nsec3chaintime, &i); + } else + isc_time_settoepoch(&zone->nsec3chaintime); + UNLOCK_ZONE(zone); +} + +static isc_result_t +del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_dbnode_t *node, unsigned int nkeys, dns_secalg_t algorithm, + isc_uint16_t keyid, dns_diff_t *diff) +{ + dns_rdata_rrsig_t rrsig; + dns_rdataset_t rdataset; + dns_rdatasetiter_t *iterator = NULL; + isc_result_t result; + + result = dns_db_allrdatasets(db, node, version, 0, &iterator); + if (result != ISC_R_SUCCESS) { + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + return (result); + } + + dns_rdataset_init(&rdataset); + for (result = dns_rdatasetiter_first(iterator); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iterator)) { + dns_rdatasetiter_current(iterator, &rdataset); + if (nkeys == 0 && rdataset.type == dns_rdatatype_nsec) { + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + CHECK(update_one_rr(db, version, diff, + DNS_DIFFOP_DEL, name, + rdataset.ttl, &rdata)); + } + if (result != ISC_R_NOMORE) + goto failure; + dns_rdataset_disassociate(&rdataset); + continue; + } + if (rdataset.type != dns_rdatatype_rrsig) { + dns_rdataset_disassociate(&rdataset); + continue; + } + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &rrsig, NULL)); + if (rrsig.algorithm != algorithm || + rrsig.keyid != keyid) + continue; + CHECK(update_one_rr(db, version, diff, + DNS_DIFFOP_DEL, name, + rdataset.ttl, &rdata)); + } + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_NOMORE) + break; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + dns_rdatasetiter_destroy(&iterator); + return (result); +} + +/* + * Incrementally sign the zone using the keys requested. + * Builds the NSEC chain if required. + */ +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; + dns_diff_t sig_diff; + dns_fixedname_t fixed; + dns_fixedname_t nextfixed; + dns_name_t *name, *nextname; + dns_rdataset_t rdataset; + dns_signing_t *signing, *nextsigning; + dns_signinglist_t cleanup; + dst_key_t *zone_keys[MAXZONEKEYS]; + isc_int32_t signatures; + isc_boolean_t check_ksk, is_ksk; + isc_boolean_t delegation; + isc_boolean_t finishedakey = ISC_FALSE; + isc_boolean_t secureupdated = ISC_FALSE; + isc_boolean_t build_nsec3 = ISC_FALSE, build_nsec = ISC_FALSE; + isc_boolean_t first; + isc_result_t result; + isc_stdtime_t now, inception, soaexpire, expire, stop; + isc_uint32_t jitter; + unsigned int i; + unsigned int nkeys = 0; + isc_uint32_t nodes; + + dns_rdataset_init(&rdataset); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_fixedname_init(&nextfixed); + nextname = dns_fixedname_name(&nextfixed); + dns_diff_init(zone->mctx, &sig_diff); + sig_diff.resign = zone->sigresigninginterval; + ISC_LIST_INIT(cleanup); + + /* + * Updates are disabled. Pause for 5 minutes. + */ + if (zone->update_disabled) { + result = ISC_R_FAILURE; + goto failure; + } + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + result = dns_db_newversion(db, &version); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:dns_db_newversion -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = find_zone_keys(zone, db, version, zone->mctx, + MAXZONEKEYS, zone_keys, &nkeys); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:find_zone_keys -> %s\n", + dns_result_totext(result)); + goto failure; + } + + isc_stdtime_get(&now); + inception = now - 3600; /* Allow for clock skew. */ + soaexpire = now + dns_zone_getsigvalidityinterval(zone); + + /* + * Spread out signatures over time if they happen to be + * clumped. We don't do this for each add_sigs() call as + * we still want some clustering to occur. + */ + isc_random_get(&jitter); + expire = soaexpire - jitter % 3600; + stop = now + 5; + + check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); + if (check_ksk) + check_ksk = ksk_sanity(db, version); + + /* + * We keep pulling nodes off each iterator in turn until + * we have no more nodes to pull off or we reach the limits + * for this quantum. + */ + nodes = zone->nodes; + signatures = zone->signatures; + signing = ISC_LIST_HEAD(zone->signing); + first = ISC_TRUE; + /* + * See if we have a NSEC chain. + */ + result = dns_db_getoriginnode(db, &node); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec, + dns_rdatatype_none, 0, &rdataset, NULL); + dns_db_detachnode(db, &node); + if (result == ISC_R_SUCCESS) { + build_nsec = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); + } else if (result != ISC_R_NOTFOUND) { + goto failure; + } else { + /* + * No NSEC chain present. + * See if we need to build a NSEC3 chain? + */ + result = dns_nsec3_active(db, version, ISC_TRUE, &build_nsec3); + if (result == ISC_R_SUCCESS) { + if (build_nsec3) + build_nsec3 = ISC_FALSE; + else { + result = dns_nsec3_active(db, version, + ISC_FALSE, + &build_nsec3); + if (build_nsec3) + secureupdated = ISC_TRUE; + else + build_nsec = ISC_TRUE; + } + } + } + + while (signing != NULL && nodes-- > 0 && signatures > 0) { + nextsigning = ISC_LIST_NEXT(signing, link); + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (signing->done || signing->db != zone->db) { + /* + * The zone has been reloaded. We will have + * created new signings as part of the reload + * process so we can destroy this one. + */ + ISC_LIST_UNLINK(zone->signing, signing, link); + ISC_LIST_APPEND(cleanup, signing, link); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + goto next_signing; + } + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + if (signing->db != db) + goto next_signing; + + is_ksk = ISC_FALSE; + delegation = ISC_FALSE; + + dns_dbiterator_current(signing->dbiterator, &node, name); + + if (signing->delete) { + dns_dbiterator_pause(signing->dbiterator); + CHECK(del_sig(db, version, name, node, nkeys, + signing->algorithm, signing->keyid, + &sig_diff)); + goto next_node; + } + /* + * On the first pass we need to check if the current node + * has not been obscured. + */ + if (first) { + dns_fixedname_t ffound; + dns_name_t *found; + dns_fixedname_init(&ffound); + found = dns_fixedname_name(&ffound); + result = dns_db_find(db, name, version, + dns_rdatatype_soa, + DNS_DBFIND_NOWILD, 0, NULL, found, + NULL, NULL); + if ((result == DNS_R_DELEGATION || + result == DNS_R_DNAME) && + !dns_name_equal(name, found)) { + /* + * Remember the obscuring name so that + * we skip all obscured names. + */ + dns_name_copy(found, name, NULL); + delegation = ISC_TRUE; + goto next_node; + } + } + + /* + * Process one node. + */ + dns_dbiterator_pause(signing->dbiterator); + for (i = 0; i < nkeys; i++) { + /* + * Find the key we want to sign with. + */ + if (dst_key_alg(zone_keys[i]) != signing->algorithm || + dst_key_id(zone_keys[i]) != signing->keyid || + !dst_key_isprivate(zone_keys[i])) + continue; + /* + * Do we do KSK processing? + */ + if (check_ksk && + (dst_key_flags(zone_keys[i]) & DNS_KEYFLAG_KSK) != 0) + is_ksk = ISC_TRUE; + CHECK(sign_a_node(db, name, node, version, build_nsec3, + build_nsec, zone_keys[i], inception, + expire, zone->minimum, is_ksk, + &delegation, &sig_diff, &signatures, + zone->mctx)); + break; + } + /* + * Go onto next node. + */ + next_node: + first = ISC_FALSE; + dns_db_detachnode(db, &node); + do { + result = dns_dbiterator_next(signing->dbiterator); + if (result == ISC_R_NOMORE) { + ISC_LIST_UNLINK(zone->signing, signing, link); + ISC_LIST_APPEND(cleanup, signing, link); + dns_dbiterator_pause(signing->dbiterator); + finishedakey = ISC_TRUE; + if (!is_ksk && !secureupdated && nkeys != 0 && + build_nsec) { + /* + * We have finished regenerating the + * zone with a zone signing key. + * The NSEC chain is now complete and + * there is a full set of signatures + * for the zone. We can now clear the + * OPT bit from the NSEC record. + */ + result = updatesecure(db, version, + &zone->origin, + zone->minimum, + &secureupdated, + &sig_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, + ISC_LOG_ERROR, + "updatesecure -> %s\n", + dns_result_totext(result)); + goto failure; + } + } + result = updatesignwithkey(signing, version, + &zone->origin, + zone->privatetype, + &sig_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "updatesignwithkey -> %s\n", + dns_result_totext(result)); + goto failure; + } + goto next_signing; + } else if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:dns_dbiterator_next -> %s\n", + dns_result_totext(result)); + goto failure; + } else if (delegation) { + dns_dbiterator_current(signing->dbiterator, + &node, nextname); + dns_db_detachnode(db, &node); + if (!dns_name_issubdomain(nextname, name)) + break; + } else + break; + } while (1); + continue; + + next_signing: + dns_dbiterator_pause(signing->dbiterator); + signing = nextsigning; + first = ISC_TRUE; + } + + if (secureupdated) { + /* + * We have changed the NSEC RRset above so we need to update + * the signatures. + */ + result = del_sigs(zone, db, version, &zone->origin, + dns_rdatatype_nsec, &sig_diff, zone_keys, + nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + result = add_sigs(db, version, &zone->origin, + dns_rdatatype_nsec, &sig_diff, zone_keys, + nkeys, zone->mctx, inception, soaexpire, + check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + } + if (finishedakey) { + /* + * We have changed the RRset above so we need to update + * the signatures. + */ + result = del_sigs(zone, db, version, &zone->origin, + zone->privatetype, &sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + result = add_sigs(db, version, &zone->origin, + zone->privatetype, &sig_diff, + zone_keys, nkeys, zone->mctx, inception, + soaexpire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + } + result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = increment_soa_serial(db, version, &sig_diff, zone->mctx); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:increment_soa_serial -> %s\n", + dns_result_totext(result)); + goto failure; + } + + /* + * Generate maximum life time signatures so that the above loop + * termination is sensible. + */ + result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, zone->mctx, inception, + soaexpire, check_ksk); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:add_sigs -> %s\n", + dns_result_totext(result)); + 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; + } + } + + + /* + * Pause all iterators so that dns_db_closeversion() can succeed. + */ + for (signing = ISC_LIST_HEAD(zone->signing); + signing != NULL; + signing = ISC_LIST_NEXT(signing, link)) + dns_dbiterator_pause(signing->dbiterator); + + for (signing = ISC_LIST_HEAD(cleanup); + signing != NULL; + signing = ISC_LIST_NEXT(signing, link)) + dns_dbiterator_pause(signing->dbiterator); + + /* + * Everything has succeeded. Commit the changes. + */ + dns_db_closeversion(db, &version, ISC_TRUE); + + /* + * Everything succeeded so we can clean these up now. + */ + signing = ISC_LIST_HEAD(cleanup); + while (signing != NULL) { + ISC_LIST_UNLINK(cleanup, signing, link); + dns_db_detach(&signing->db); + dns_dbiterator_destroy(&signing->dbiterator); + isc_mem_put(zone->mctx, signing, sizeof *signing); + signing = ISC_LIST_HEAD(cleanup); + } + + set_resigntime(zone); + + LOCK_ZONE(zone); + zone_needdump(zone, DNS_DUMP_DELAY); + UNLOCK_ZONE(zone); + + failure: + /* + * Rollback the cleanup list. + */ + signing = ISC_LIST_HEAD(cleanup); + while (signing != NULL) { + ISC_LIST_UNLINK(cleanup, signing, link); + ISC_LIST_APPEND(zone->signing, signing, link); + dns_dbiterator_first(signing->dbiterator); + dns_dbiterator_pause(signing->dbiterator); + signing = ISC_LIST_HEAD(cleanup); + } + + for (signing = ISC_LIST_HEAD(zone->signing); + signing != NULL; + signing = ISC_LIST_NEXT(signing, link)) + dns_dbiterator_pause(signing->dbiterator); + + dns_diff_clear(&sig_diff); + + for (i = 0; i < nkeys; i++) + dst_key_free(&zone_keys[i]); + + if (version != NULL) { + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); + } else if (db != NULL) + dns_db_detach(&db); + + if (ISC_LIST_HEAD(zone->signing) != NULL) { + isc_interval_t i; + if (zone->update_disabled || result != ISC_R_SUCCESS) + isc_interval_set(&i, 60, 0); /* 1 minute */ + else + isc_interval_set(&i, 0, 10000000); /* 10 ms */ + isc_time_nowplusinterval(&zone->signingtime, &i); + } else + isc_time_settoepoch(&zone->signingtime); +} + static void zone_maintenance(dns_zone_t *zone) { const char me[] = "zone_maintenance"; @@ -3016,15 +5981,34 @@ zone_maintenance(dns_zone_t *zone) { break; } - /* - * Do we need to send out notify messages? - */ switch (zone->type) { case dns_zone_master: case dns_zone_slave: + /* + * Do we need to send out notify messages? + */ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) && isc_time_compare(&now, &zone->notifytime) >= 0) zone_notify(zone, &now); + /* + * Do we need to sign/resign some RRsets? + */ + if (!isc_time_isepoch(&zone->signingtime) && + isc_time_compare(&now, &zone->signingtime) >= 0) + zone_sign(zone); + else if (!isc_time_isepoch(&zone->resigntime) && + isc_time_compare(&now, &zone->resigntime) >= 0) + zone_resigninc(zone); + else if (!isc_time_isepoch(&zone->nsec3chaintime) && + isc_time_compare(&now, &zone->nsec3chaintime) >= 0) + zone_nsec3chain(zone); + /* + * Do we need to issue a key expiry warning. + */ + if (!isc_time_isepoch(&zone->keywarntime) && + isc_time_compare(&now, &zone->keywarntime) >= 0) + set_key_expiry_warning(zone, zone->key_expiry, + isc_time_seconds(&now)); break; default: break; @@ -3036,6 +6020,7 @@ void dns_zone_markdirty(dns_zone_t *zone) { LOCK_ZONE(zone); + set_resigntime(zone); /* XXXMPA make separate call back */ zone_needdump(zone, DNS_DUMP_DELAY); UNLOCK_ZONE(zone); } @@ -3776,6 +6761,16 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) { timeout * 3, timeout, notify->zone->task, notify_done, notify, ¬ify->request); + if (result == ISC_R_SUCCESS) { + if (isc_sockaddr_pf(¬ify->dst) == AF_INET) { + inc_stats(notify->zone, + dns_zonestatscounter_notifyoutv4); + } else { + inc_stats(notify->zone, + dns_zonestatscounter_notifyoutv6); + } + } + cleanup_key: if (key != NULL) dns_tsigkey_detach(&key); @@ -3975,9 +6970,11 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { RUNTIME_CHECK(result == ISC_R_SUCCESS); dns_rdata_reset(&rdata); /* - * don't notify the master server. + * Don't notify the master server unless explicitly + * configured to do so. */ - if (dns_name_compare(&master, &ns.name) == 0) { + if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOTIFYTOSOA) && + dns_name_compare(&master, &ns.name) == 0) { result = dns_rdataset_next(&nsrdset); continue; } @@ -4163,6 +7160,8 @@ stub_callback(isc_task_t *task, isc_event_t *event) { master, source); goto same_master; } + dns_zonemgr_unreachableadd(zone->zmgr, &zone->masteraddr, + &zone->sourceaddr, &now); dns_zone_log(zone, ISC_LOG_INFO, "could not refresh stub from master %s" " (source %s): %s", master, source, @@ -4424,12 +7423,23 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { "master %s exceeded (source %s)", master, source); /* Try with slave with TCP. */ - if (zone->type == dns_zone_slave) { - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, - DNS_ZONEFLG_SOABEFOREAXFR); - UNLOCK_ZONE(zone); - goto tcp_transfer; + if (zone->type == dns_zone_slave && + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) { + if (!dns_zonemgr_unreachable(zone->zmgr, + &zone->masteraddr, + &zone->sourceaddr, + &now)) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, + DNS_ZONEFLG_SOABEFOREAXFR); + UNLOCK_ZONE(zone); + goto tcp_transfer; + } + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refresh: skipped tcp fallback" + "as master %s (source %s) is " + "unreachable (cached)", + master, source); } } else dns_zone_log(zone, ISC_LOG_INFO, @@ -4479,7 +7489,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { "master %s (source %s)", (int)rb.used, rcode, master, source); /* - * Perhaps AXFR/IXFR is allowed even if SOA queries arn't. + * Perhaps AXFR/IXFR is allowed even if SOA queries aren't. */ if (msg->rcode == dns_rcode_refused && zone->type == dns_zone_slave) @@ -4605,6 +7615,16 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) || DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) || isc_serial_gt(serial, zone->serial)) { + if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, + &zone->sourceaddr, &now)) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: skipping %s as master %s " + "(source %s) is unreachable (cached)", + zone->type == dns_zone_slave ? + "zone transfer" : "NS query", + master, source); + goto next_master; + } tcp_transfer: isc_event_free(&event); LOCK_ZONE(zone); @@ -4820,7 +7840,7 @@ create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, } static isc_result_t -add_opt(dns_message_t *message, isc_uint16_t udpsize) { +add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid) { dns_rdataset_t *rdataset = NULL; dns_rdatalist_t *rdatalist = NULL; dns_rdata_t *rdata = NULL; @@ -4850,11 +7870,21 @@ add_opt(dns_message_t *message, isc_uint16_t udpsize) { */ rdatalist->ttl = 0; - /* - * No EDNS options. - */ - rdata->data = NULL; - rdata->length = 0; + /* Set EDNS options if applicable */ + if (reqnsid) { + unsigned char data[4]; + isc_buffer_t buf; + + isc_buffer_init(&buf, data, sizeof(data)); + isc_buffer_putuint16(&buf, DNS_OPT_NSID); + isc_buffer_putuint16(&buf, 0); + rdata->data = data; + rdata->length = sizeof(data); + } else { + rdata->data = NULL; + rdata->length = 0; + } + rdata->rdclass = rdatalist->rdclass; rdata->type = rdatalist->type; rdata->flags = 0; @@ -4889,7 +7919,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { isc_uint32_t options; isc_boolean_t cancel = ISC_TRUE; int timeout; - isc_boolean_t have_xfrsource; + isc_boolean_t have_xfrsource, reqnsid; isc_uint16_t udpsize = SEND_BUFFER_SIZE; REQUIRE(DNS_ZONE_VALID(zone)); @@ -4941,6 +7971,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { (void)dns_view_getpeertsig(zone->view, &masterip, &key); have_xfrsource = ISC_FALSE; + reqnsid = zone->view->requestnsid; if (zone->view->peers != NULL) { dns_peer_t *peer = NULL; isc_boolean_t edns; @@ -4958,6 +7989,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { udpsize = dns_resolver_getudpsize(zone->view->resolver); (void)dns_peer_getudpsize(peer, &udpsize); + (void)dns_peer_getrequestnsid(peer, &reqnsid); } } @@ -4989,7 +8021,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { DNS_REQUESTOPT_TCP : 0; if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - result = add_opt(message, udpsize); + result = add_opt(message, udpsize, reqnsid); if (result != ISC_R_SUCCESS) zone_debuglog(zone, me, 1, "unable to add opt record: %s", @@ -5011,6 +8043,11 @@ soa_query(isc_task_t *task, isc_event_t *event) { "dns_request_createvia2() failed: %s", dns_result_totext(result)); goto cleanup; + } else { + if (isc_sockaddr_pf(&zone->masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_soaoutv4); + else + inc_stats(zone, dns_zonestatscounter_soaoutv6); } cancel = ISC_FALSE; @@ -5053,7 +8090,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { dns_tsigkey_t *key = NULL; dns_dbnode_t *node = NULL; int timeout; - isc_boolean_t have_xfrsource = ISC_FALSE; + isc_boolean_t have_xfrsource = ISC_FALSE, reqnsid; isc_uint16_t udpsize = SEND_BUFFER_SIZE; REQUIRE(DNS_ZONE_VALID(zone)); @@ -5165,6 +8202,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { if (key == NULL) (void)dns_view_getpeertsig(zone->view, &masterip, &key); + reqnsid = zone->view->requestnsid; if (zone->view->peers != NULL) { dns_peer_t *peer = NULL; isc_boolean_t edns; @@ -5182,11 +8220,12 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { udpsize = dns_resolver_getudpsize(zone->view->resolver); (void)dns_peer_getudpsize(peer, &udpsize); + (void)dns_peer_getrequestnsid(peer, &reqnsid); } } if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - result = add_opt(message, udpsize); + result = add_opt(message, udpsize, reqnsid); if (result != ISC_R_SUCCESS) zone_debuglog(zone, me, 1, "unable to add opt record: %s", @@ -5382,6 +8421,26 @@ zone_settimer(dns_zone_t *zone, isc_time_t *now) { isc_time_compare(&zone->dumptime, &next) < 0) next = zone->dumptime; } + if (!isc_time_isepoch(&zone->resigntime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->resigntime, &next) < 0) + next = zone->resigntime; + } + if (!isc_time_isepoch(&zone->keywarntime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->keywarntime, &next) < 0) + next = zone->keywarntime; + } + if (!isc_time_isepoch(&zone->signingtime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->signingtime, &next) < 0) + next = zone->signingtime; + } + if (!isc_time_isepoch(&zone->nsec3chaintime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->nsec3chaintime, &next) < 0) + next = zone->nsec3chaintime; + } break; case dns_zone_slave: @@ -5651,6 +8710,10 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, * We only handle NOTIFY (SOA) at the present. */ LOCK_ZONE(zone); + if (isc_sockaddr_pf(from) == PF_INET) + inc_stats(zone, dns_zonestatscounter_notifyinv4); + else + inc_stats(zone, dns_zonestatscounter_notifyinv6); if (msg->counts[DNS_SECTION_QUESTION] == 0 || dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin, dns_rdatatype_soa, dns_rdatatype_none, @@ -5705,6 +8768,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, UNLOCK_ZONE(zone); dns_zone_log(zone, ISC_LOG_INFO, "refused notify from non-master: %s", fromtext); + inc_stats(zone, dns_zonestatscounter_notifyrej); return (DNS_R_REFUSED); } @@ -5788,6 +8852,18 @@ dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl) { } void +dns_zone_setqueryonacl(dns_zone_t *zone, dns_acl_t *acl) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->queryon_acl != NULL) + dns_acl_detach(&zone->queryon_acl); + dns_acl_attach(acl, &zone->queryon_acl); + UNLOCK_ZONE(zone); +} + +void dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -5840,6 +8916,14 @@ dns_zone_getqueryacl(dns_zone_t *zone) { } dns_acl_t * +dns_zone_getqueryonacl(dns_zone_t *zone) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->queryon_acl); +} + +dns_acl_t * dns_zone_getupdateacl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -5908,6 +8992,17 @@ dns_zone_clearqueryacl(dns_zone_t *zone) { } void +dns_zone_clearqueryonacl(dns_zone_t *zone) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->queryon_acl != NULL) + dns_acl_detach(&zone->queryon_acl); + UNLOCK_ZONE(zone); +} + +void dns_zone_clearxfracl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -5977,7 +9072,7 @@ dns_zone_getjournalsize(dns_zone_t *zone) { } static void -zone_tostr(dns_zone_t *zone, char *buf, size_t length) { +zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) { isc_result_t result = ISC_R_FAILURE; isc_buffer_t buffer; @@ -6008,29 +9103,88 @@ zone_tostr(dns_zone_t *zone, char *buf, size_t length) { buf[isc_buffer_usedlength(&buffer)] = '\0'; } +static void +zone_name_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_result_t result = ISC_R_FAILURE; + isc_buffer_t buffer; + + REQUIRE(buf != NULL); + REQUIRE(length > 1U); + + /* + * Leave space for terminating '\0'. + */ + isc_buffer_init(&buffer, buf, length - 1); + if (dns_name_dynamic(&zone->origin)) + result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); + if (result != ISC_R_SUCCESS && + isc_buffer_availablelength(&buffer) >= (sizeof("<UNKNOWN>") - 1)) + isc_buffer_putstr(&buffer, "<UNKNOWN>"); + + buf[isc_buffer_usedlength(&buffer)] = '\0'; +} + +static void +zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_buffer_t buffer; + + REQUIRE(buf != NULL); + REQUIRE(length > 1U); + + /* + * Leave space for terminating '\0'. + */ + isc_buffer_init(&buffer, buf, length - 1); + (void)dns_rdataclass_totext(zone->rdclass, &buffer); + + buf[isc_buffer_usedlength(&buffer)] = '\0'; +} + +static void +zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_buffer_t buffer; + + REQUIRE(buf != NULL); + REQUIRE(length > 1U); + + + /* + * Leave space for terminating '\0'. + */ + isc_buffer_init(&buffer, buf, length - 1); + + if (zone->view == NULL) { + isc_buffer_putstr(&buffer, "_none"); + } else if (strlen(zone->view->name) + < isc_buffer_availablelength(&buffer)) { + isc_buffer_putstr(&buffer, zone->view->name); + } else { + isc_buffer_putstr(&buffer, "_toolong"); + } + + buf[isc_buffer_usedlength(&buffer)] = '\0'; +} + void dns_zone_name(dns_zone_t *zone, char *buf, size_t length) { REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(buf != NULL); - zone_tostr(zone, buf, length); + zone_namerd_tostr(zone, buf, length); } static void notify_log(dns_zone_t *zone, int level, const char *fmt, ...) { va_list ap; char message[4096]; - char namebuf[1024+32]; if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) return; - zone_tostr(zone, namebuf, sizeof(namebuf)); - va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY, DNS_LOGMODULE_ZONE, - level, "zone %s: %s", namebuf, message); + level, "zone %s: %s", zone->strnamerd, message); } void @@ -6038,36 +9192,30 @@ dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category, int level, const char *fmt, ...) { va_list ap; char message[4096]; - char namebuf[1024+32]; if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) return; - zone_tostr(zone, namebuf, sizeof(namebuf)); - va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE, - level, "zone %s: %s", namebuf, message); + level, "zone %s: %s", zone->strnamerd, message); } void dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) { va_list ap; char message[4096]; - char namebuf[1024+32]; if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) return; - zone_tostr(zone, namebuf, sizeof(namebuf)); - va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, - level, "zone %s: %s", namebuf, message); + level, "zone %s: %s", zone->strnamerd, message); } static void @@ -6076,19 +9224,16 @@ zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel, { va_list ap; char message[4096]; - char namebuf[1024+32]; int level = ISC_LOG_DEBUG(debuglevel); if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) return; - zone_tostr(zone, namebuf, sizeof(namebuf)); - va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, - level, "%s: zone %s: %s", me, namebuf, message); + level, "%s: zone %s: %s", me, zone->strnamerd, message); } static int @@ -6313,12 +9458,16 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { return (result); } + result = check_nsec3param(zone, db); + if (result != ISC_R_SUCCESS) + return (result); + ver = NULL; dns_db_currentversion(db, &ver); /* * The initial version of a slave zone is always dumped; - * subsequent versions may be journalled instead if this + * subsequent versions may be journaled instead if this * is enabled in the configuration. */ if (zone->db != NULL && zone->journal != NULL && @@ -6401,7 +9550,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { * The in-memory database just changed, and * because 'dump' is set, it didn't change by * being loaded from disk. Also, we have not - * journalled diffs for this change. + * journaled diffs for this change. * Therefore, the on-disk journal is missing * the deltas for this change. Since it can * no longer be used to bring the zone @@ -6411,7 +9560,17 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), "removing journal file"); - (void)remove(zone->journal); + if (remove(zone->journal) < 0 && errno != ENOENT) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, + ISC_LOG_WARNING, + "unable to remove journal " + "'%s': '%s'", + zone->journal, strbuf); + } } } @@ -6568,7 +9727,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { } /* - * This is not neccessary if we just performed a AXFR + * This is not necessary if we just performed a AXFR * however it is necessary for an IXFR / UPTODATE and * won't hurt with an AXFR. */ @@ -6592,6 +9751,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { dns_result_totext(result)); } + inc_stats(zone, dns_zonestatscounter_xfrsuccess); break; case DNS_R_BADIXFR: @@ -6626,6 +9786,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); again = ISC_TRUE; } + inc_stats(zone, dns_zonestatscounter_xfrfail); break; } zone_settimer(zone, &now); @@ -6760,6 +9921,20 @@ dns_zone_getsigvalidityinterval(dns_zone_t *zone) { return (zone->sigvalidityinterval); } +void +dns_zone_setsigresigninginterval(dns_zone_t *zone, isc_uint32_t interval) { + REQUIRE(DNS_ZONE_VALID(zone)); + + zone->sigresigninginterval = interval; +} + +isc_uint32_t +dns_zone_getsigresigninginterval(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->sigresigninginterval); +} + static void queue_xfrin(dns_zone_t *zone) { const char me[] = "queue_xfrin"; @@ -6798,12 +9973,14 @@ static void got_transfer_quota(isc_task_t *task, isc_event_t *event) { isc_result_t result; dns_peer_t *peer = NULL; - char mastertext[256]; + char master[ISC_SOCKADDR_FORMATSIZE]; + char source[ISC_SOCKADDR_FORMATSIZE]; dns_rdatatype_t xfrtype; dns_zone_t *zone = event->ev_arg; isc_netaddr_t masterip; isc_sockaddr_t sourceaddr; isc_sockaddr_t masteraddr; + isc_time_t now; UNUSED(task); @@ -6814,34 +9991,44 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { goto cleanup; } - isc_sockaddr_format(&zone->masteraddr, mastertext, sizeof(mastertext)); + TIME_NOW(&now); + + isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); + if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, + &zone->sourceaddr, &now)) { + isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); + dns_zone_log(zone, ISC_LOG_INFO, + "got_transfer_quota: skipping zone transfer as " + "master %s (source %s) is unreachable (cached)", + master, source); + result = ISC_R_CANCELED; + goto cleanup; + } isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); - (void)dns_peerlist_peerbyaddr(zone->view->peers, - &masterip, &peer); + (void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer); /* * Decide whether we should request IXFR or AXFR. */ if (zone->db == NULL) { dns_zone_log(zone, ISC_LOG_DEBUG(1), - "no database exists yet, " - "requesting AXFR of " - "initial version from %s", mastertext); + "no database exists yet, requesting AXFR of " + "initial version from %s", master); xfrtype = dns_rdatatype_axfr; } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) { dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences " - "set, requesting AXFR from %s", mastertext); + "set, requesting AXFR from %s", master); xfrtype = dns_rdatatype_axfr; } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { dns_zone_log(zone, ISC_LOG_DEBUG(1), "forced reload, requesting AXFR of " - "initial version from %s", mastertext); + "initial version from %s", master); xfrtype = dns_rdatatype_axfr; } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLAG_NOIXFR)) { dns_zone_log(zone, ISC_LOG_DEBUG(1), "retrying with AXFR from %s due to " - "previous IXFR failure", mastertext); + "previous IXFR failure", master); xfrtype = dns_rdatatype_axfr; LOCK_ZONE(zone); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLAG_NOIXFR); @@ -6857,17 +10044,15 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { } if (use_ixfr == ISC_FALSE) { dns_zone_log(zone, ISC_LOG_DEBUG(1), - "IXFR disabled, " - "requesting AXFR from %s", - mastertext); + "IXFR disabled, requesting AXFR from %s", + master); if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) xfrtype = dns_rdatatype_soa; else xfrtype = dns_rdatatype_axfr; } else { dns_zone_log(zone, ISC_LOG_DEBUG(1), - "requesting IXFR from %s", - mastertext); + "requesting IXFR from %s", master); xfrtype = dns_rdatatype_ixfr; } } @@ -6892,8 +10077,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { dns_zone_log(zone, ISC_LOG_ERROR, - "could not get TSIG key " - "for zone transfer: %s", + "could not get TSIG key for zone transfer: %s", isc_result_totext(result)); } @@ -6906,6 +10090,21 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { zone->tsigkey, zone->mctx, zone->zmgr->timermgr, zone->zmgr->socketmgr, zone->task, zone_xfrdone, &zone->xfr); + if (result == ISC_R_SUCCESS) { + LOCK_ZONE(zone); + if (xfrtype == dns_rdatatype_axfr) { + if (isc_sockaddr_pf(&masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_axfrreqv4); + else + inc_stats(zone, dns_zonestatscounter_axfrreqv6); + } else if (xfrtype == dns_rdatatype_ixfr) { + if (isc_sockaddr_pf(&masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_ixfrreqv4); + else + inc_stats(zone, dns_zonestatscounter_ixfrreqv6); + } + UNLOCK_ZONE(zone); + } cleanup: /* * Any failure in this function is handled like a failed @@ -7175,6 +10374,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, ISC_LIST_INIT(zmgr->zones); ISC_LIST_INIT(zmgr->waiting_for_xfrin); ISC_LIST_INIT(zmgr->xfrin_in_progress); + memset(zmgr->unreachable, 0, sizeof(zmgr->unreachable)); result = isc_rwlock_init(&zmgr->rwlock, 0, 0); if (result != ISC_R_SUCCESS) goto free_mem; @@ -7264,8 +10464,10 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { NULL, NULL, zone->task, zone_timer, zone, &zone->timer); + if (result != ISC_R_SUCCESS) goto cleanup_task; + /* * The timer "holds" a iref. */ @@ -7735,7 +10937,7 @@ zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) { } #if 0 -/* Hook for ondestroy notifcation from a database. */ +/* Hook for ondestroy notification from a database. */ static void dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) { @@ -7791,6 +10993,87 @@ dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) { return (zmgr->serialqueryrate); } +static isc_boolean_t +dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now) +{ + unsigned int i; + isc_rwlocktype_t locktype; + isc_result_t result; + isc_uint32_t seconds = isc_time_seconds(now); + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + locktype = isc_rwlocktype_read; + RWLOCK(&zmgr->rwlock, locktype); + for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + if (zmgr->unreachable[i].expire >= seconds && + isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && + isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { + result = isc_rwlock_tryupgrade(&zmgr->rwlock); + if (result == ISC_R_SUCCESS) { + locktype = isc_rwlocktype_write; + zmgr->unreachable[i].last = seconds; + } + break; + } + } + RWUNLOCK(&zmgr->rwlock, locktype); + return (ISC_TF(i < UNREACH_CHACHE_SIZE)); +} + +void +dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now) +{ + isc_uint32_t seconds = isc_time_seconds(now); + isc_uint32_t last = seconds; + unsigned int i, slot = UNREACH_CHACHE_SIZE, oldest = 0; + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + /* Existing entry? */ + if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && + isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) + break; + /* Empty slot? */ + if (zmgr->unreachable[i].expire < seconds) + slot = i; + /* Least recently used slot? */ + if (zmgr->unreachable[i].last < last) { + last = zmgr->unreachable[i].last; + oldest = i; + } + } + if (i < UNREACH_CHACHE_SIZE) { + /* + * Found a existing entry. Update the expire timer and + * last usage timestamps. + */ + zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME; + zmgr->unreachable[i].last = seconds; + } else if (slot != UNREACH_CHACHE_SIZE) { + /* + * Found a empty slot. Add a new entry to the cache. + */ + zmgr->unreachable[slot].expire = seconds + UNREACH_HOLD_TIME; + zmgr->unreachable[slot].last = seconds; + zmgr->unreachable[slot].remote = *remote; + zmgr->unreachable[slot].local = *local; + } else { + /* + * Replace the least recently used entry in the cache. + */ + zmgr->unreachable[oldest].expire = seconds + UNREACH_HOLD_TIME; + zmgr->unreachable[oldest].last = seconds; + zmgr->unreachable[oldest].remote = *remote; + zmgr->unreachable[oldest].local = *local; + } + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); +} + void dns_zone_forcereload(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -7813,26 +11096,66 @@ dns_zone_isforced(dns_zone_t *zone) { isc_result_t dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on) { - isc_result_t result = ISC_R_SUCCESS; + /* + * This function is obsoleted. + */ + UNUSED(zone); + UNUSED(on); + return (ISC_R_NOTIMPLEMENTED); +} + +isc_uint64_t * +dns_zone_getstatscounters(dns_zone_t *zone) { + /* + * This function is obsoleted. + */ + UNUSED(zone); + return (NULL); +} + +void +dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->stats == NULL); LOCK_ZONE(zone); - if (on) { - if (zone->counters != NULL) - goto done; - result = dns_stats_alloccounters(zone->mctx, &zone->counters); - } else { - if (zone->counters == NULL) - goto done; - dns_stats_freecounters(zone->mctx, &zone->counters); + zone->stats = NULL; + isc_stats_attach(stats, &zone->stats); + UNLOCK_ZONE(zone); +} + +void +dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->requeststats_on && stats == NULL) + zone->requeststats_on = ISC_FALSE; + else if (!zone->requeststats_on && stats != NULL) { + if (zone->requeststats == NULL) { + isc_stats_attach(stats, &zone->requeststats); + zone->requeststats_on = ISC_TRUE; + } } - done: UNLOCK_ZONE(zone); - return (result); + + return; } -isc_uint64_t * -dns_zone_getstatscounters(dns_zone_t *zone) { - return (zone->counters); +isc_stats_t * +dns_zone_getrequeststats(dns_zone_t *zone) { + /* + * We don't lock zone for efficiency reason. This is not catastrophic + * because requeststats must always be valid when requeststats_on is + * true. + * Some counters may be incremented while requeststats_on is becoming + * false, or some cannot be incremented just after the statistics are + * installed, but it shouldn't matter much in practice. + */ + if (zone->requeststats_on) + return (zone->requeststats); + else + return (NULL); } void @@ -8043,3 +11366,152 @@ dns_zone_getnotifydelay(dns_zone_t *zone) { return (zone->notifydelay); } + +isc_result_t +dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, + isc_uint16_t keyid, isc_boolean_t delete) +{ + isc_result_t result; + REQUIRE(DNS_ZONE_VALID(zone)); + + dns_zone_log(zone, ISC_LOG_NOTICE, + "dns_zone_signwithkey(algorithm=%u, keyid=%u)", + algorithm, keyid); + LOCK_ZONE(zone); + result = zone_signwithkey(zone, algorithm, keyid, delete); + UNLOCK_ZONE(zone); + + return (result); +} + +static const char *hex = "0123456789ABCDEF"; + +isc_result_t +dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { + isc_result_t result; + char salt[255*2+1]; + unsigned int i, j; + + REQUIRE(DNS_ZONE_VALID(zone)); + + if (nsec3param->salt_length != 0) { + INSIST((nsec3param->salt_length * 2U) < sizeof(salt)); + for (i = 0, j = 0; i < nsec3param->salt_length; i++) { + salt[j++] = hex[(nsec3param->salt[i] >> 4) & 0xf]; + salt[j++] = hex[nsec3param->salt[i] & 0xf]; + } + salt[j] = '\0'; + } else + strcpy(salt, "-"); + dns_zone_log(zone, ISC_LOG_NOTICE, + "dns_zone_addnsec3chain(hash=%u, iterations=%u, salt=%s)", + nsec3param->hash, nsec3param->iterations, + salt); + LOCK_ZONE(zone); + result = zone_addnsec3chain(zone, nsec3param); + UNLOCK_ZONE(zone); + + return (result); +} + +void +dns_zone_setnodes(dns_zone_t *zone, isc_uint32_t nodes) { + REQUIRE(DNS_ZONE_VALID(zone)); + + if (nodes == 0) + nodes = 1; + zone->nodes = nodes; +} + +void +dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures) { + REQUIRE(DNS_ZONE_VALID(zone)); + + /* + * We treat signatures as a signed value so explicitly + * limit its range here. + */ + if (signatures > ISC_INT32_MAX) + signatures = ISC_INT32_MAX; + else if (signatures == 0) + signatures = 1; + zone->signatures = signatures; +} + +void +dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->privatetype = type; +} + +dns_rdatatype_t +dns_zone_getprivatetype(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->privatetype); +} + +static isc_result_t +zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, + isc_boolean_t delete) +{ + dns_signing_t *signing; + dns_signing_t *current; + isc_result_t result = ISC_R_SUCCESS; + isc_time_t now; + + signing = isc_mem_get(zone->mctx, sizeof *signing); + if (signing == NULL) + return (ISC_R_NOMEMORY); + + signing->magic = 0; + signing->db = NULL; + signing->dbiterator = NULL; + signing->algorithm = algorithm; + signing->keyid = keyid; + signing->delete = delete; + signing->done = ISC_FALSE; + + TIME_NOW(&now); + + for (current = ISC_LIST_HEAD(zone->signing); + current != NULL; + current = ISC_LIST_NEXT(current, link)) { + if (current->db == zone->db && + current->algorithm == signing->algorithm && + current->keyid == signing->keyid) { + if (current->delete != signing->delete) + current->done = ISC_TRUE; + else + goto cleanup; + } + } + + if (zone->db != NULL) { + dns_db_attach(zone->db, &signing->db); + result = dns_db_createiterator(signing->db, 0, + &signing->dbiterator); + + if (result == ISC_R_SUCCESS) + result = dns_dbiterator_first(signing->dbiterator); + if (result == ISC_R_SUCCESS) { + dns_dbiterator_pause(signing->dbiterator); + ISC_LIST_INITANDAPPEND(zone->signing, signing, link); + signing = NULL; + if (isc_time_isepoch(&zone->signingtime)) { + zone->signingtime = now; + if (zone->task != NULL) + zone_settimer(zone, &now); + } + } + } else + result = ISC_R_NOTFOUND; + + cleanup: + if (signing != NULL) { + dns_db_detach(&signing->db); + if (signing->dbiterator != NULL) + dns_dbiterator_destroy(&signing->dbiterator); + isc_mem_put(zone->mctx, signing, sizeof *signing); + } + return (result); +} diff --git a/lib/dns/zonekey.c b/lib/dns/zonekey.c index 0ed63bb..bf7474b 100644 --- a/lib/dns/zonekey.c +++ b/lib/dns/zonekey.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001, 2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zonekey.c,v 1.5.18.2 2005/04/29 00:16:08 marka Exp $ */ +/* $Id: zonekey.c,v 1.9 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/zt.c b/lib/dns/zt.c index 4cb8f3f..ed7f28a 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * 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. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zt.c,v 1.38.18.5 2005/11/30 03:44:39 marka Exp $ */ +/* $Id: zt.c,v 1.47 2007/06/19 23:47:16 tbox Exp $ */ /*! \file */ @@ -63,7 +63,8 @@ static isc_result_t freezezones(dns_zone_t *zone, void *uap); isc_result_t -dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) { +dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) +{ dns_zt_t *zt; isc_result_t result; |