+3867. [func] "rndc nta" can now be used to set a temporary
+ negative trust anchor, which disables DNSSEC
+ validation below a specified name for a specified
+ period of time (not exceeding 24 hours). This
+ can be used when validation for a domain is known
+ to be failing due to a configuration error on
+ the part of the domain owner rather than a
+ spoofing attack. [RT #29358]
+
3866. [bug] Named could die on disk full in generate_session_key.
[RT #36119]
result = ns_server_signing(ns_g_server, command, text);
} else if (command_compare(command, NS_COMMAND_ZONESTATUS)) {
result = ns_server_zonestatus(ns_g_server, command, text);
+ } else if (command_compare(command, NS_COMMAND_NTA)) {
+ result = ns_server_nta(ns_g_server, command, text);
} else {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
#define NS_COMMAND_SYNC "sync"
#define NS_COMMAND_SIGNING "signing"
#define NS_COMMAND_ZONESTATUS "zonestatus"
+#define NS_COMMAND_NTA "nta"
isc_result_t
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
*/
isc_result_t
ns_server_zonestatus(ns_server_t *server, char *args, isc_buffer_t *text);
+
+/*%
+ * Adds a Negative Trust Anchor (NTA) for a specified name and
+ * duration, in a particular view if specified, or in all views.
+ */
+isc_result_t
+ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text);
#endif /* NAMED_SERVER_H */
#include <dns/lib.h>
#include <dns/master.h>
#include <dns/masterdump.h>
+#include <dns/nta.h>
#include <dns/order.h>
#include <dns/peer.h>
#include <dns/portlist.h>
#include <dns/stats.h>
#include <dns/tkey.h>
#include <dns/tsig.h>
+#include <dns/ttl.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zt.h>
return (ISC_R_UNEXPECTED);
}
+ result = dns_view_initntatable(view, mctx);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "couldn't create NTA table");
+ return (ISC_R_UNEXPECTED);
+ }
+
if (auto_dlv && view->rdclass == dns_rdataclass_in) {
const cfg_obj_t *builtin_keys = NULL;
const cfg_obj_t *builtin_managed_keys = NULL;
dns_zone_detach(&zone);
return (result);
}
+
+isc_result_t
+ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
+ dns_view_t *view;
+ dns_ntatable_t *ntatable = NULL;
+ isc_result_t result;
+ char *ptr, *nametext, *viewname;
+ isc_stdtime_t now, when;
+ isc_time_t t;
+ char tbuf[64];
+ const char *msg = NULL;
+ dns_fixedname_t fn;
+ dns_name_t *ntaname;
+ dns_ttl_t ntattl;
+ isc_textregion_t tr;
+
+ dns_fixedname_init(&fn);
+ ntaname = dns_fixedname_name(&fn);
+
+ /* Skip the command name. */
+ ptr = next_token(&args, " \t");
+ if (ptr == NULL)
+ return (ISC_R_UNEXPECTEDEND);
+
+ /* Get the NTA name. */
+ nametext = next_token(&args, " \t");
+ if (nametext == NULL)
+ return (ISC_R_UNEXPECTEDEND);
+
+ if (strcmp(nametext, ".") == 0)
+ ntaname = dns_rootname;
+ else {
+ isc_buffer_t b;
+ isc_buffer_init(&b, nametext, strlen(nametext));
+ isc_buffer_add(&b, strlen(nametext));
+ CHECK(dns_name_fromtext(ntaname, &b, dns_rootname, 0, NULL));
+ }
+
+ /* Get the NTA duration. */
+ ptr = next_token(&args, " \t");
+ if (ptr == NULL)
+ return (ISC_R_UNEXPECTEDEND);
+
+ tr.base = ptr;
+ tr.length = strlen(ptr);
+ CHECK(dns_ttl_fromtext(&tr, &ntattl));
+
+ if (ntattl > 86400) {
+ msg = "NTA cannot exceed one day";
+ CHECK(ISC_R_RANGE);
+ }
+
+ /* Look for the view name. */
+ viewname = next_token(&args, " \t");
+
+ /* Set up the NTA */
+ isc_stdtime_get(&now);
+ when = now + ntattl;
+
+ result = isc_task_beginexclusive(server->task);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ for (view = ISC_LIST_HEAD(server->viewlist);
+ view != NULL;
+ view = ISC_LIST_NEXT(view, link))
+ {
+ if (viewname != NULL &&
+ strcmp(view->name, viewname) != 0)
+ continue;
+
+ if (ntatable != NULL)
+ dns_ntatable_detach(&ntatable);
+
+ result = dns_view_getntatable(view, &ntatable);
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ continue;
+ }
+
+ result = dns_view_flushnode(view, ntaname, ISC_TRUE);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "flush tree '%s' in cache view '%s': %s",
+ nametext, view->name,
+ isc_result_totext(result));
+
+ isc_time_set(&t, when, 0);
+ isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
+
+ if (ntattl > 0) {
+ CHECK(dns_ntatable_add(ntatable, ntaname, when));
+
+ CHECK(putstr(text, "Negative trust anchor added: "));
+ CHECK(putstr(text, nametext));
+ CHECK(putstr(text, "/"));
+ CHECK(putstr(text, view->name));
+ CHECK(putstr(text, ", expires "));
+ CHECK(putstr(text, tbuf));
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "added NTA '%s' (%d sec) in view '%s'",
+ nametext, ntattl, view->name);
+ } else {
+ CHECK(dns_ntatable_delete(ntatable, ntaname));
+
+ CHECK(putstr(text, "Negative trust anchor removed: "));
+ CHECK(putstr(text, nametext));
+ CHECK(putstr(text, "/"));
+ CHECK(putstr(text, view->name));
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "removed NTA '%s' in view %s",
+ nametext, view->name);
+ }
+
+ if (isc_buffer_availablelength(text) == 0)
+ return (ISC_R_NOSPACE);
+
+ isc_buffer_putuint8(text, 0);
+ }
+ isc_task_endexclusive(server->task);
+
+ if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
+ isc_buffer_putstr(text, msg);
+ cleanup:
+ if (ntatable != NULL)
+ dns_ntatable_detach(&ntatable);
+ return (result);
+}
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><userinput>nta <replaceable>domain</replaceable> <replaceable>duration</replaceable> </userinput></term>
+ <listitem>
+ <para>
+ Sets a DNSSEC negative trust anchor (NTA)
+ for <option>domain</option>, with a lifetime of
+ <option>duration</option> (up to a limit of one day).
+ </para>
+ <para>
+ A negative trust anchor selectively disables
+ DNSSEC validation for zones that known to be
+ failing because of misconfiguration rather than
+ an attack. When data to be validated is
+ at or below an active NTA (and above any other
+ configured trust anchors), <command>named</command> will
+ abort the DNSSEC validation process and treat the data as
+ insecure rather than bogus. This continues until the
+ NTA's lifetime is elapsed, or until the server is
+ restarted (NTA's do not persist across restarts).
+ </para>
+ <para>
+ TTL-style suffixes can be used to specify
+ <option>duration</option> in seconds, minutes, or hours.
+ </para>
+ <para>
+ If the specified domain already has an NTA, its duration
+ will be updated to the new value. Setting
+ <option>duration</option> to zero will delete the NTA.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><userinput>tsig-list</userinput></term>
<listitem>
cd ns1 && $SHELL sign.sh
echo "a.bogus.example. A 10.0.0.22" >>../ns3/bogus.example.db.signed
+echo "b.bogus.example. A 10.0.0.23" >>../ns3/bogus.example.db.signed
cd ../ns3 && cp -f siginterval1.conf siginterval.conf
cd ../ns4 && cp -f named1.conf named.conf
$DIG $DIGOPTS ns algroll. @10.53.0.4 > dig.out.ns4.test$n || ret=1
grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking positive and negative validation with negative trust anchors ($n)"
+ret=0
+# check correct initial behavior
+$DIG $DIGOPTS a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.1 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.1 > /dev/null || ret=1
+$DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.2 > /dev/null || ret=1
+# add negative trust anchors
+$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta bogus.example 15s 2>&1 | sed 's/^/I:ns4 /'
+$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta secure.example 15s 2>&1 | sed 's/^/I:ns4 /'
+# check behavior with NTA's in place
+$DIG $DIGOPTS a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.3 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.3 > /dev/null && ret=1
+$DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.4 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 > /dev/null && ret=1
+echo "I: waiting for NTA expiration"
+sleep 15
+# check correct behavior after expiry
+$DIG $DIGOPTS b.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null || ret=1
+$DIG $DIGOPTS b.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.6 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 > /dev/null || ret=1
+n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
level are inherited by all views, but keys defined in a view
are only used within that view.
</para>
+ <para>
+ Validation below specified names can be temporarily disabled
+ by using <command>rndc nta</command>.
+ </para>
</sect2>
<sect2>
iptable.@O@ journal.@O@ keydata.@O@ keytable.@O@ \
lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
- name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ \
- portlist.@O@ private.@O@ \
+ name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ nta.@O@ \
+ order.@O@ peer.@O@ portlist.@O@ private.@O@ \
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \
request.@O@ resolver.@O@ result.@O@ rootns.@O@ \
dlz.c dns64.c dnssec.c ds.c forward.c geoip.c \
iptable.c journal.c keydata.c keytable.c lib.c log.c \
lookup.c master.c masterdump.c message.c \
- name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \
+ name.c ncache.c nsec.c nsec3.c nta.c \
+ order.c peer.c portlist.c \
rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \
rdataset.c rdatasetiter.c rdataslab.c request.c \
resolver.c result.c rootns.c rpz.c rrl.c rriterator.c \
static dst_func_t *dst_t_func[DST_MAX_ALGS];
static isc_entropy_t *dst_entropy_pool = NULL;
static unsigned int dst_entropy_flags = 0;
-static isc_boolean_t dst_initialized = ISC_FALSE;
+
+isc_boolean_t dst_initialized = ISC_FALSE;
void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
isc_result_t
dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
- isc_boolean_t *wantdnssecp);
+ dns_name_t *foundname, isc_boolean_t *wantdnssecp);
/*%<
* Is 'name' at or beneath a trusted key?
*
*
*\li 'name' is a valid absolute name.
*
- *\li '*wantsdnssecp' is a valid isc_boolean_t.
+ *\li 'foundanme' is NULL or is a pointer to an initialized dns_name_t
*
+ *\li '*wantsdnssecp' is a valid isc_boolean_t.
+
* Ensures:
*
*\li On success, *wantsdnssecp will be ISC_TRUE if and only if 'name'
- * is at or beneath a trusted key.
+ * is at or beneath a trusted key. If 'foundname' is not NULL, then
+ * it will be updated to contain the name of the closest enclosing
+ * trust anchor.
*
* Returns:
*
#define DNS_LOGMODULE_DNSSEC (&dns_modules[27])
#define DNS_LOGMODULE_CRYPTO (&dns_modules[28])
#define DNS_LOGMODULE_PACKETS (&dns_modules[29])
+#define DNS_LOGMODULE_NTA (&dns_modules[30])
ISC_LANG_BEGINDECLS
--- /dev/null
+/*
+ * Copyright (C) 2013 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 DNS_NTA_H
+#define DNS_NTA_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file
+ * \brief
+ * The NTA module provides services for storing and retrieving negative
+ * trust anchors, and determine whether a given domain is subject to
+ * DNSSEC validation.
+ */
+
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/refcount.h>
+#include <isc/rwlock.h>
+#include <isc/stdtime.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+struct dns_ntatable {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_rwlock_t rwlock;
+ /* Locked by rwlock. */
+ isc_uint32_t references;
+ dns_rbt_t *table;
+};
+
+#define NTATABLE_MAGIC ISC_MAGIC('N', 'T', 'A', 't')
+#define VALID_NTATABLE(nt) ISC_MAGIC_VALID(nt, NTATABLE_MAGIC)
+
+struct dns_nta {
+ unsigned int magic;
+ isc_refcount_t refcount;
+ isc_stdtime_t expiry;
+};
+
+#define NTA_MAGIC ISC_MAGIC('N', 'T', 'A', 'n')
+#define VALID_NTA(nn) ISC_MAGIC_VALID(nn, NTA_MAGIC)
+
+isc_result_t
+dns_ntatable_create(isc_mem_t *mctx, dns_ntatable_t **ntatablep);
+/*%<
+ * Create an NTA table.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li ntatablep != NULL && *ntatablep == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, *ntatablep is a valid, empty NTA table.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *\li Any other result indicates failure.
+ */
+
+void
+dns_ntatable_attach(dns_ntatable_t *source, dns_ntatable_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid ntatable.
+ *
+ *\li 'targetp' points to a NULL dns_ntatable_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ */
+
+void
+dns_ntatable_detach(dns_ntatable_t **ntatablep);
+/*%<
+ * Detach *ntatablep from its ntatable.
+ *
+ * Requires:
+ *
+ *\li 'ntatablep' points to a valid ntatable.
+ *
+ * Ensures:
+ *
+ *\li *ntatablep is NULL.
+ *
+ *\li If '*ntatablep' is the last reference to the ntatable,
+ * all resources used by the ntatable will be freed
+ */
+
+isc_result_t
+dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name,
+ isc_uint32_t expiry);
+/*%<
+ * Add a negative trust anchor to 'ntatable' for name 'name',
+ * which will expire at time 'expiry'.
+ *
+ * Notes:
+ *
+ *\li If an NTA already exists in the table, its expiry time
+ * is updated.
+ *
+ * Requires:
+ *
+ *\li 'ntatable' points to a valid ntatable.
+ *
+ *\li 'name' points to a valid name.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result indicates failure.
+ */
+
+isc_result_t
+dns_ntatable_delete(dns_ntatable_t *ntatable, dns_name_t *keyname);
+/*%<
+ * Delete node(s) from 'ntatable' matching name 'keyname'
+ *
+ * Requires:
+ *
+ *\li 'ntatable' points to a valid ntatable.
+ *
+ *\li 'name' is not NULL
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result indicates failure.
+ */
+
+isc_result_t
+dns_ntatable_deletenta(dns_ntatable_t *ntatable, dns_name_t *name);
+/*%<
+ * Delete node from 'ntatable' matching the name 'name'
+ *
+ * Requires:
+ *
+ *\li 'ntatable' points to a valid ntatable.
+ *\li 'name' is a valid name.
+ *
+ * Returns:
+ *
+ *\li ISC_R_SUCCESS
+ *
+ *\li Any other result indicates failure.
+ */
+
+isc_boolean_t
+dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
+ dns_name_t *name, dns_name_t *anchor);
+/*%<
+ * Return ISC_TRUE if 'name' is below a non-expired negative trust
+ * anchor which in turn is at or below 'anchor'.
+ *
+ * If 'ntatable' has not been initialized, return ISC_FALSE.
+ *
+ * Requires:
+ *
+ *\li 'ntatable' is NULL or is a valid ntatable.
+ *
+ *\li 'name' is a valid absolute name.
+ */
+
+isc_result_t
+dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp);
+/*%<
+ * Dump the NTA table on fp.
+ */
+
+isc_result_t
+dns_nta_create(isc_mem_t *mctx, dns_nta_t **target);
+/*%<
+ * Allocate space for an NTA
+ */
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_NTA_H */
#define DNS_R_EXPIRED (ISC_RESULTCLASS_DNS + 107)
#define DNS_R_NOTDYNAMIC (ISC_RESULTCLASS_DNS + 108)
#define DNS_R_BADEUI (ISC_RESULTCLASS_DNS + 109)
+#define DNS_R_NTACOVERED (ISC_RESULTCLASS_DNS + 110)
-#define DNS_R_NRESULTS 110 /*%< Number of results */
+#define DNS_R_NRESULTS 111 /*%< Number of results */
/*
* DNS wire format rcodes.
typedef struct dns_lookup dns_lookup_t;
typedef struct dns_name dns_name_t;
typedef ISC_LIST(dns_name_t) dns_namelist_t;
+typedef struct dns_nta dns_nta_t;
+typedef struct dns_ntatable dns_ntatable_t;
typedef isc_uint16_t dns_opcode_t;
typedef unsigned char dns_offsets_t[128];
typedef struct dns_order dns_order_t;
unsigned int depth;
unsigned int authcount;
unsigned int authfail;
+ isc_stdtime_t start;
};
/*%
dns_db_t * hints;
/*
- * security roots.
+ * security roots and negative trust anchors.
* internal use only; access via * dns_view_getsecroots()
*/
dns_keytable_t * secroots_priv;
+ dns_ntatable_t * ntatable_priv;
isc_mutex_t lock;
isc_boolean_t frozen;
*\li #ISC_FALSE otherwise.
*/
+isc_result_t
+dns_view_initntatable(dns_view_t *view, isc_mem_t *mctx);
+/*%<
+ * Initialize the negative trust anchor table for the view.
+ *
+ * Requires:
+ * \li 'view' is valid.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li Any other result indicates failure
+ */
+
+isc_result_t
+dns_view_getntatable(dns_view_t *view, dns_ntatable_t **ntp);
+/*%<
+ * Get the negative trust anchor table for this view. Returns
+ * ISC_R_NOTFOUND if the table not been initialized for the view.
+ *
+ * '*ntp' is attached on success; the caller is responsible for
+ * detaching it with dns_ntatable_detach().
+ *
+ * Requires:
+ * \li 'view' is valid.
+ * \li 'nta' is not NULL and '*nta' is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOTFOUND
+ */
+
isc_result_t
dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx);
/*%<
- * Initialize security roots for the view. (Note that secroots is
+ * Initialize security roots for the view, detaching any previously
+ * existing security roots first. (Note that secroots_priv is
* NULL until this function is called, so any function using
- * secroots must check its validity first. One way to do this is
- * use dns_view_getsecroots() and check its return value.)
+ * security roots must check that they have been initialized first.
+ * One way to do this is use dns_view_getsecroots() and check its
+ * return value.)
*
* Requires:
* \li 'view' is valid.
- * \li 'view->secroots' is NULL.
*
* Returns:
*\li ISC_R_SUCCESS
isc_result_t
dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
- isc_boolean_t *secure_domain);
+ isc_stdtime_t now, isc_boolean_t *secure_domain);
/*%<
- * Is 'name' at or beneath a trusted key? Put answer in
- * '*secure_domain'.
+ * Is 'name' at or beneath a trusted key, and not covered by a valid
+ * negative trust anchor? Put answer in '*secure_domain'.
*
* Requires:
* \li 'view' is valid.
*\li Any other value indicates failure
*/
+isc_boolean_t
+dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now,
+ dns_name_t *name, dns_name_t *anchor);
+/*%<
+ * Is there a current negative trust anchor above 'name' and below 'anchor'?
+ *
+ * Requires:
+ * \li 'view' is valid.
+ *
+ * Returns:
+ *\li ISC_R_TRUE
+ *\li ISC_R_FALSE
+ */
+
void
dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx);
isc_result_t
dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name,
- isc_boolean_t *wantdnssecp)
+ dns_name_t *foundname, isc_boolean_t *wantdnssecp)
{
isc_result_t result;
- void *data;
+ dns_rbtnode_t *node = NULL;
/*
* Is 'name' at or beneath a trusted key?
RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
- data = NULL;
- result = dns_rbt_findname(keytable->table, name, 0, NULL, &data);
-
+ result = dns_rbt_findnode(keytable->table, name, foundname, &node,
+ NULL, DNS_RBTFIND_NOOPTIONS, NULL, NULL);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
- INSIST(data != NULL);
+ INSIST(node->data != NULL);
*wantdnssecp = ISC_TRUE;
result = ISC_R_SUCCESS;
} else if (result == ISC_R_NOTFOUND) {
{ "dns/dnssec", 0 },
{ "dns/crypto", 0 },
{ "dns/packets", 0 },
+ { "dns/nta", 0 },
{ NULL, 0 }
};
--- /dev/null
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/log.h>
+#include <dns/nta.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+static void
+nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
+ unsigned int refs;
+ dns_nta_t *nta = *ntap;
+
+ REQUIRE(VALID_NTA(nta));
+
+ *ntap = NULL;
+ isc_refcount_decrement(&nta->refcount, &refs);
+ if (refs == 0) {
+ isc_refcount_destroy(&nta->refcount);
+ isc_mem_put(mctx, nta, sizeof(dns_nta_t));
+ }
+}
+
+static void
+free_nta(void *data, void *arg) {
+ dns_nta_t *nta = (dns_nta_t *) data;
+ isc_mem_t *mctx = (isc_mem_t *) arg;
+
+ nta_detach(mctx, &nta);
+}
+
+isc_result_t
+dns_ntatable_create(isc_mem_t *mctx, dns_ntatable_t **ntatablep) {
+ dns_ntatable_t *ntatable;
+ isc_result_t result;
+
+ /*
+ * Create an NTA table.
+ */
+
+ REQUIRE(ntatablep != NULL && *ntatablep == NULL);
+
+ ntatable = isc_mem_get(mctx, sizeof(*ntatable));
+ if (ntatable == NULL)
+ return (ISC_R_NOMEMORY);
+
+ ntatable->table = NULL;
+ result = dns_rbt_create(mctx, free_nta, mctx, &ntatable->table);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_ntatable;
+
+ result = isc_rwlock_init(&ntatable->rwlock, 0, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rbt;
+
+ ntatable->mctx = NULL;
+ isc_mem_attach(mctx, &ntatable->mctx);
+ ntatable->references = 1;
+ ntatable->magic = NTATABLE_MAGIC;
+ *ntatablep = ntatable;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_rbt:
+ dns_rbt_destroy(&ntatable->table);
+
+ cleanup_ntatable:
+ isc_mem_put(mctx, ntatable, sizeof(*ntatable));
+
+ return (result);
+}
+
+void
+dns_ntatable_attach(dns_ntatable_t *source, dns_ntatable_t **targetp) {
+ REQUIRE(VALID_NTATABLE(source));
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ RWLOCK(&source->rwlock, isc_rwlocktype_write);
+
+ INSIST(source->references > 0);
+ source->references++;
+ INSIST(source->references != 0);
+
+ RWUNLOCK(&source->rwlock, isc_rwlocktype_write);
+
+ *targetp = source;
+}
+
+void
+dns_ntatable_detach(dns_ntatable_t **ntatablep) {
+ isc_boolean_t destroy = ISC_FALSE;
+ dns_ntatable_t *ntatable;
+
+ REQUIRE(ntatablep != NULL && VALID_NTATABLE(*ntatablep));
+
+ ntatable = *ntatablep;
+ *ntatablep = NULL;
+
+ RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+ INSIST(ntatable->references > 0);
+ ntatable->references--;
+ if (ntatable->references == 0)
+ destroy = ISC_TRUE;
+ RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+
+ if (destroy) {
+ dns_rbt_destroy(&ntatable->table);
+ isc_rwlock_destroy(&ntatable->rwlock);
+ ntatable->magic = 0;
+ isc_mem_putanddetach(&ntatable->mctx,
+ ntatable, sizeof(*ntatable));
+ }
+}
+
+isc_result_t
+dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name,
+ isc_uint32_t expiry)
+{
+ isc_result_t result;
+ dns_nta_t *nta = NULL;
+ dns_rbtnode_t *node;
+
+ REQUIRE(VALID_NTATABLE(ntatable));
+
+ result = dns_nta_create(ntatable->mctx, &nta);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ nta->expiry = expiry;
+
+ RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+
+ node = NULL;
+ result = dns_rbt_addnode(ntatable->table, name, &node);
+ if (result == ISC_R_SUCCESS) {
+ node->data = nta;
+ nta = NULL;
+ } else if (result == ISC_R_EXISTS) {
+ dns_nta_t *n = node->data;
+ if (n == NULL) {
+ node->data = nta;
+ nta = NULL;
+ } else {
+ n->expiry = nta->expiry;
+ nta_detach(ntatable->mctx, &nta);
+ }
+ result = ISC_R_SUCCESS;
+ }
+
+ RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+
+ if (nta != NULL)
+ nta_detach(ntatable->mctx, &nta);
+
+ return (result);
+}
+
+/*
+ * Caller must hold a write lock on rwlock.
+ */
+static isc_result_t
+delete(dns_ntatable_t *ntatable, dns_name_t *name) {
+ isc_result_t result;
+ dns_rbtnode_t *node = NULL;
+
+ REQUIRE(VALID_NTATABLE(ntatable));
+ REQUIRE(name != NULL);
+
+ result = dns_rbt_findnode(ntatable->table, name, NULL, &node, NULL,
+ DNS_RBTFIND_NOOPTIONS, NULL, NULL);
+ if (result == ISC_R_SUCCESS) {
+ if (node->data != NULL)
+ result = dns_rbt_deletenode(ntatable->table,
+ node, ISC_FALSE);
+ else
+ result = ISC_R_NOTFOUND;
+ } else if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_NOTFOUND;
+
+ return (result);
+}
+
+isc_result_t
+dns_ntatable_delete(dns_ntatable_t *ntatable, dns_name_t *name) {
+ isc_result_t result;
+
+ RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+ result = delete(ntatable, name);
+ RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
+
+ return (result);
+}
+
+isc_boolean_t
+dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
+ dns_name_t *name, dns_name_t *anchor)
+{
+ isc_result_t result;
+ dns_fixedname_t fn;
+ dns_rbtnode_t *node;
+ dns_name_t *foundname;
+ dns_nta_t *nta = NULL;
+ isc_boolean_t answer = ISC_FALSE;
+ isc_rwlocktype_t locktype = isc_rwlocktype_read;
+
+ REQUIRE(ntatable == NULL || VALID_NTATABLE(ntatable));
+ REQUIRE(dns_name_isabsolute(name));
+
+ if (ntatable == NULL)
+ return (ISC_FALSE);
+
+ dns_fixedname_init(&fn);
+ foundname = dns_fixedname_name(&fn);
+
+ relock:
+ RWLOCK(&ntatable->rwlock, locktype);
+ again:
+ node = NULL;
+ result = dns_rbt_findnode(ntatable->table, name, foundname, &node, NULL,
+ DNS_RBTFIND_NOOPTIONS, NULL, NULL);
+ if (result == DNS_R_PARTIALMATCH) {
+ if (dns_name_issubdomain(foundname, anchor))
+ result = ISC_R_SUCCESS;
+ }
+ if (result == ISC_R_SUCCESS) {
+ nta = (dns_nta_t *) node->data;
+ answer = ISC_TF(nta->expiry > now);
+ }
+
+ /* Deal with expired NTA */
+ if (result == ISC_R_SUCCESS && !answer) {
+ char nb[DNS_NAME_FORMATSIZE];
+
+ if (locktype == isc_rwlocktype_read) {
+ RWUNLOCK(&ntatable->rwlock, locktype);
+ locktype = isc_rwlocktype_write;
+ goto relock;
+ }
+
+ dns_name_format(foundname, nb, sizeof(nb));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
+ DNS_LOGMODULE_NTA, ISC_LOG_INFO,
+ "deleting expired NTA at %s", nb);
+
+ result = delete(ntatable, foundname);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
+ DNS_LOGMODULE_NTA, ISC_LOG_INFO,
+ "deleting NTA failed: %s",
+ isc_result_totext(result));
+ }
+ goto again;
+ }
+ RWUNLOCK(&ntatable->rwlock, locktype);
+
+ return (answer);
+}
+
+isc_result_t
+dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
+ isc_result_t result;
+ dns_rbtnode_t *node;
+ dns_rbtnodechain_t chain;
+
+ REQUIRE(VALID_NTATABLE(ntatable));
+
+ RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
+ dns_rbtnodechain_init(&chain, ntatable->mctx);
+ result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
+ goto cleanup;
+ for (;;) {
+ dns_rbtnodechain_current(&chain, NULL, NULL, &node);
+ if (node->data != NULL) {
+ dns_nta_t *n = (dns_nta_t *) node->data;
+ char nbuf[DNS_NAME_FORMATSIZE], tbuf[80];
+ dns_name_t name;
+ isc_time_t t;
+
+ dns_name_init(&name, NULL);
+ dns_rbt_namefromnode(node, &name);
+ dns_name_format(&name, nbuf, sizeof(nbuf));
+ isc_time_set(&t, n->expiry, 0);
+ isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
+ fprintf(fp, "%s : expiry %s\n", nbuf, tbuf);
+ }
+ result = dns_rbtnodechain_next(&chain, NULL, NULL);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ break;
+ }
+ }
+
+ cleanup:
+ dns_rbtnodechain_invalidate(&chain);
+ RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
+ return (result);
+}
+
+isc_result_t
+dns_nta_create(isc_mem_t *mctx, dns_nta_t **target) {
+ isc_result_t result;
+ dns_nta_t *nta = NULL;
+
+ REQUIRE(target != NULL && *target == NULL);
+
+ nta = isc_mem_get(mctx, sizeof(dns_nta_t));
+ if (nta == NULL)
+ return (ISC_R_NOMEMORY);
+
+ nta->expiry = 0;
+
+ result = isc_refcount_init(&nta->refcount, 1);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, nta, sizeof(nta));
+ return (result);
+ }
+
+ nta->magic = NTA_MAGIC;
+
+ *target = nta;
+ return (ISC_R_SUCCESS);
+}
}
#endif
+static isc_result_t
+issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
+ isc_stdtime_t now, isc_boolean_t *issecure)
+{
+ dns_name_t suffix;
+ unsigned int labels;
+
+ /*
+ * For DS variants we need to check fom the parent domain,
+ * since there may be a negative trust anchor for the name,
+ * while the enclosing domain where the DS record lives is
+ * under a secure entry point.
+ */
+ labels = dns_name_countlabels(name);
+ if (dns_rdatatype_atparent(type) && labels > 1) {
+ dns_name_init(&suffix, NULL);
+ dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+ name = &suffix;
+ }
+
+ return (dns_view_issecuredomain(view, name, now, issecure));
+}
+
static isc_result_t
resquery_send(resquery_t *query) {
fetchctx_t *fctx;
fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
else if (res->view->enablevalidation &&
((fctx->qmessage->flags & DNS_MESSAGEFLAG_RD) != 0)) {
- result = dns_view_issecuredomain(res->view, &fctx->name,
- &secure_domain);
+ result = issecuredomain(res->view, &fctx->name,
+ fctx->type, query->start.seconds,
+ &secure_domain);
if (result != ISC_R_SUCCESS)
secure_domain = ISC_FALSE;
if (res->view->dlv != NULL)
* Is DNSSEC validation required for this name?
*/
if (res->view->enablevalidation) {
- result = dns_view_issecuredomain(res->view, name,
- &secure_domain);
+ result = issecuredomain(res->view, name, fctx->type,
+ now, &secure_domain);
if (result != ISC_R_SUCCESS)
return (result);
* Is DNSSEC validation required for this name?
*/
if (fctx->res->view->enablevalidation) {
- result = dns_view_issecuredomain(res->view, name,
- &secure_domain);
+ result = issecuredomain(res->view, name, fctx->type,
+ now, &secure_domain);
if (result != ISC_R_SUCCESS)
return (result);
"expired", /*%< 107 DNS_R_EXPIRED */
"not dynamic", /*%< 108 DNS_R_NOTDYNAMIC */
"bad EUI" /*%< 109 DNS_R_BADEUI */
+ "covered by negative trust anchor" /*%< 110 DNS_R_NTACOVERED */
};
static const char *rcode_text[DNS_R_NRCODERESULTS] = {
dnstest.c \
geoip_test.c \
gost_test.c \
+ keytable_test.c \
master_test.c \
nsec3_test.c \
private_test.c \
dispatch_test@EXEEXT@ \
geoip_test@EXEEXT@ \
gost_test@EXEEXT@ \
+ keytable_test@EXEEXT@ \
master_test@EXEEXT@ \
nsec3_test@EXEEXT@ \
private_test@EXEEXT@ \
master_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
+keytable_test@EXEEXT@: keytable_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ keytable_test.@O@ dnstest.@O@ ${DNSLIBS} \
+ ${ISCLIBS} ${LIBS}
+
time_test@EXEEXT@: time_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
time_test.@O@ dnstest.@O@ ${DNSLIBS} \
#include <dns/view.h>
#include <dns/zone.h>
-#include <dst/dst.h>
-
#include "dnstest.h"
isc_mem_t *mctx = NULL;
isc_mem_destroy(&mctx);
}
+/*
+ * Create a view.
+ */
+isc_result_t
+dns_test_makeview(const char *name, dns_view_t **viewp)
+{
+ isc_result_t result;
+ dns_view_t *view = NULL;
+
+ CHECK(dns_view_create(mctx, dns_rdataclass_in, name, &view));
+ *viewp = view;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (view != NULL)
+ dns_view_detach(&view);
+ return (result);
+}
+
/*
* Create a zone with origin 'name', return a pointer to the zone object in
* 'zonep'. If 'view' is set, add the zone to that view; otherwise, create
void
dns_test_end(void);
+isc_result_t
+dns_test_makeview(const char *name, dns_view_t **viewp);
+
isc_result_t
dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
isc_boolean_t keepview);
--- /dev/null
+/*
+ * Copyright (c) 2014 Infoblox Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+#include <stdio.h>
+
+#include <isc/base64.h>
+#include <isc/buffer.h>
+#include <isc/util.h>
+
+#include <dns/name.h>
+#include <dns/fixedname.h>
+#include <dns/keytable.h>
+#include <dns/nta.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatastruct.h>
+#include <dns/rootns.h>
+#include <dns/view.h>
+
+#include <dst/dst.h>
+
+#include "dnstest.h"
+
+dns_keytable_t *keytable = NULL;
+dns_ntatable_t *ntatable = NULL;
+
+static const char *keystr1 = "BQEAAAABok+vaUC9neRv8yeT/FEGgN7svR8s7VBUVSBd8NsAiV8AlaAg O5FHar3JQd95i/puZos6Vi6at9/JBbN8qVmO2AuiXxVqfxMKxIcy+LEB 0Vw4NaSJ3N3uaVREso6aTSs98H/25MjcwLOr7SFfXA7bGhZatLtYY/xu kp6Km5hMfkE=";
+static const dns_keytag_t keytag1 = 30591;
+
+static const char *keystr2 = "BQEAAAABwuHz9Cem0BJ0JQTO7C/a3McR6hMaufljs1dfG/inaJpYv7vH XTrAOm/MeKp+/x6eT4QLru0KoZkvZJnqTI8JyaFTw2OM/ItBfh/hL2lm Cft2O7n3MfeqYtvjPnY7dWghYW4sVfH7VVEGm958o9nfi79532Qeklxh x8pXWdeAaRU=";
+
+/*
+ * Test utilities. In general, these assume input parameters are valid
+ * (checking with ATF_REQUIRE_EQ, thus aborting if not) and unlikely run time
+ * errors (such as memory allocation failure) won't happen. This helps keep
+ * the test code concise.
+ */
+
+/*
+ * Utility to convert C-string to dns_name_t. Return a pointer to
+ * static data, and so is not thread safe.
+ */
+static dns_name_t *
+str2name(const char *namestr) {
+ static dns_fixedname_t fname;
+ static dns_name_t *name;
+ static isc_buffer_t namebuf;
+ void *deconst_namestr;
+
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ DE_CONST(namestr, deconst_namestr); /* OK, since we don't modify it */
+ isc_buffer_init(&namebuf, deconst_namestr, strlen(deconst_namestr));
+ isc_buffer_add(&namebuf, strlen(namestr));
+ ATF_REQUIRE_EQ(dns_name_fromtext(name, &namebuf, dns_rootname, 0,
+ NULL), ISC_R_SUCCESS);
+
+ return (name);
+}
+
+static void
+create_key(isc_uint16_t flags, isc_uint8_t proto, isc_uint8_t alg,
+ const char *keynamestr, const char *keystr, dst_key_t **target)
+{
+ dns_rdata_dnskey_t keystruct;
+ unsigned char keydata[4096];
+ isc_buffer_t keydatabuf;
+ unsigned char rrdata[4096];
+ isc_buffer_t rrdatabuf;
+ isc_region_t r;
+ const dns_rdataclass_t rdclass = dns_rdataclass_in; /* for brevity */
+
+ keystruct.common.rdclass = rdclass;
+ keystruct.common.rdtype = dns_rdatatype_dnskey;
+ keystruct.mctx = NULL;
+ ISC_LINK_INIT(&keystruct.common, link);
+ keystruct.flags = flags;
+ keystruct.protocol = proto;
+ keystruct.algorithm = alg;
+
+ isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
+ isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
+ ATF_REQUIRE_EQ(isc_base64_decodestring(keystr, &keydatabuf),
+ ISC_R_SUCCESS);
+ isc_buffer_usedregion(&keydatabuf, &r);
+ keystruct.datalen = r.length;
+ keystruct.data = r.base;
+ ATF_REQUIRE_EQ(dns_rdata_fromstruct(NULL, keystruct.common.rdclass,
+ keystruct.common.rdtype,
+ &keystruct, &rrdatabuf),
+ ISC_R_SUCCESS);
+
+ ATF_REQUIRE_EQ(dst_key_fromdns(str2name(keynamestr), rdclass,
+ &rrdatabuf, mctx, target),
+ ISC_R_SUCCESS);
+}
+
+/* Common setup: create a keytable and ntatable to test with a few keys */
+static void
+create_tables() {
+ dst_key_t *key = NULL;
+ isc_stdtime_t now;
+
+ ATF_REQUIRE_EQ(dns_keytable_create(mctx, &keytable), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_ntatable_create(mctx, &ntatable), ISC_R_SUCCESS);
+
+ /* Add a normal key */
+ create_key(257, 3, 5, "example.com", keystr1, &key);
+ ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+ ISC_R_SUCCESS);
+
+ /* Add a null key */
+ ATF_REQUIRE_EQ(dns_keytable_marksecure(keytable,
+ str2name("null.example")),
+ ISC_R_SUCCESS);
+
+ /* Add a negative trust anchor, duration 1 hour */
+ isc_stdtime_get(&now);
+ ATF_REQUIRE_EQ(dns_ntatable_add(ntatable,
+ str2name("insecure.example"),
+ now + 3600),
+ ISC_R_SUCCESS);
+}
+
+static void
+destroy_tables() {
+ if (ntatable != NULL)
+ dns_ntatable_detach(&ntatable);
+ if (keytable != NULL)
+ dns_keytable_detach(&keytable);
+}
+
+/*
+ * Individual unit tests
+ */
+
+ATF_TC(add);
+ATF_TC_HEAD(add, tc) {
+ atf_tc_set_md_var(tc, "descr", "add keys to the keytable");
+}
+ATF_TC_BODY(add, tc) {
+ dst_key_t *key = NULL;
+ dns_keynode_t *keynode = NULL;
+ dns_keynode_t *next_keynode = NULL;
+ dns_keynode_t *null_keynode = NULL;
+
+ UNUSED(tc);
+
+ ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS);
+ create_tables();
+
+ /*
+ * Get the keynode for the example.com key. There's no other key for
+ * the name, so nextkeynode() should return NOTFOUND.
+ */
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("example.com"),
+ &keynode), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+ &next_keynode), ISC_R_NOTFOUND);
+
+ /*
+ * Try to add the same key. This should have no effect, so
+ * nextkeynode() should still return NOTFOUND.
+ */
+ create_key(257, 3, 5, "example.com", keystr1, &key);
+ ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+ &next_keynode), ISC_R_NOTFOUND);
+
+ /* Add another key (different keydata) */
+ dns_keytable_detachkeynode(keytable, &keynode);
+ create_key(257, 3, 5, "example.com", keystr2, &key);
+ ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("example.com"),
+ &keynode), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+ &next_keynode), ISC_R_SUCCESS);
+ dns_keytable_detachkeynode(keytable, &next_keynode);
+
+ /*
+ * Add a normal key to a name that has a null key. The null key node
+ * will be updated with the normal key.
+ */
+ dns_keytable_detachkeynode(keytable, &keynode);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("null.example"),
+ &null_keynode), ISC_R_SUCCESS);
+ create_key(257, 3, 5, "null.example", keystr2, &key);
+ ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("null.example"),
+ &keynode), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(keynode, null_keynode); /* should be the same node */
+ ATF_REQUIRE(dns_keynode_key(keynode) != NULL); /* now have a key */
+ dns_keytable_detachkeynode(keytable, &null_keynode);
+
+ /*
+ * Try to add a null key to a name that already has a key. It's
+ * effectively no-op, so the same key node is still there, with no
+ * no next node.
+ * (Note: this and above checks confirm that if a name has a null key
+ * that's the only key for the name).
+ */
+ ATF_REQUIRE_EQ(dns_keytable_marksecure(keytable,
+ str2name("null.example")),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("null.example"),
+ &null_keynode), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(keynode, null_keynode);
+ ATF_REQUIRE(dns_keynode_key(keynode) != NULL);
+ ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+ &next_keynode), ISC_R_NOTFOUND);
+ dns_keytable_detachkeynode(keytable, &null_keynode);
+
+ dns_keytable_detachkeynode(keytable, &keynode);
+ destroy_tables();
+ dns_test_end();
+}
+
+ATF_TC(delete);
+ATF_TC_HEAD(delete, tc) {
+ atf_tc_set_md_var(tc, "descr", "delete keys from the keytable");
+}
+ATF_TC_BODY(delete, tc) {
+ UNUSED(tc);
+
+ ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS);
+ create_tables();
+
+ /* dns_keytable_delete requires exact match */
+ ATF_REQUIRE_EQ(dns_keytable_delete(keytable, str2name("example.org")),
+ ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_delete(keytable, str2name("s.example.com")),
+ ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_delete(keytable, str2name("example.com")),
+ ISC_R_SUCCESS);
+
+ /* works also for nodes with a null key */
+ ATF_REQUIRE_EQ(dns_keytable_delete(keytable, str2name("null.example")),
+ ISC_R_SUCCESS);
+
+ /* or a negative trust anchor */
+ ATF_REQUIRE_EQ(dns_ntatable_delete(ntatable,
+ str2name("insecure.example")),
+ ISC_R_SUCCESS);
+
+ destroy_tables();
+ dns_test_end();
+}
+
+ATF_TC(deletekeynode);
+ATF_TC_HEAD(deletekeynode, tc) {
+ atf_tc_set_md_var(tc, "descr", "delete key nodes from the keytable");
+}
+ATF_TC_BODY(deletekeynode, tc) {
+ dst_key_t *key = NULL;
+
+ UNUSED(tc);
+
+ ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS);
+ create_tables();
+
+ /* key name doesn't match */
+ create_key(257, 3, 5, "example.org", keystr1, &key);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ ISC_R_NOTFOUND);
+ dst_key_free(&key);
+
+ /* subdomain match is the same as no match */
+ create_key(257, 3, 5, "sub.example.com", keystr1, &key);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ ISC_R_NOTFOUND);
+ dst_key_free(&key);
+
+ /* name matches but key doesn't match (resulting in PARTIALMATCH) */
+ create_key(257, 3, 5, "example.com", keystr2, &key);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ DNS_R_PARTIALMATCH);
+ dst_key_free(&key);
+
+ /*
+ * exact match. after deleting the node the internal rbt node will be
+ * empty, and any delete or deletekeynode attempt should result in
+ * NOTFOUND.
+ */
+ create_key(257, 3, 5, "example.com", keystr1, &key);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_delete(keytable, str2name("example.com")),
+ ISC_R_NOTFOUND);
+ dst_key_free(&key);
+
+ /*
+ * The only null key node for a name can be deleted as long as the
+ * passed key name matches.
+ */
+ create_key(257, 3, 5, "null.example", keystr1, &key);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keytable_deletekeynode(keytable, key),
+ ISC_R_NOTFOUND);
+ dst_key_free(&key);
+
+ destroy_tables();
+ dns_test_end();
+}
+
+ATF_TC(find);
+ATF_TC_HEAD(find, tc) {
+ atf_tc_set_md_var(tc, "descr", "check find-variant operations");
+}
+ATF_TC_BODY(find, tc) {
+ dns_keynode_t *keynode = NULL;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+
+ UNUSED(tc);
+
+ ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS);
+ create_tables();
+
+ /*
+ * dns_keytable_find() requires exact name match. It matches node
+ * that has a null key, too. But it doesn't match a negative trust
+ * anchor.
+ */
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("example.org"),
+ &keynode), ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("sub.example.com"),
+ &keynode), ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("example.com"),
+ &keynode), ISC_R_SUCCESS);
+ dns_keytable_detachkeynode(keytable, &keynode);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("null.example"),
+ &keynode), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_keynode_key(keynode), NULL);
+ dns_keytable_detachkeynode(keytable, &keynode);
+ ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("insecure.example"),
+ &keynode), ISC_R_NOTFOUND);
+
+ /*
+ * dns_keytable_finddeepestmatch() allows partial match. Also match
+ * nodes with a null key or a negative trust anchor.
+ */
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ ATF_REQUIRE_EQ(dns_keytable_finddeepestmatch(keytable,
+ str2name("example.com"),
+ name), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_name_equal(name, str2name("example.com")), ISC_TRUE);
+ ATF_REQUIRE_EQ(dns_keytable_finddeepestmatch(keytable,
+ str2name("s.example.com"),
+ name), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_name_equal(name, str2name("example.com")), ISC_TRUE);
+ ATF_REQUIRE_EQ(dns_keytable_finddeepestmatch(keytable,
+ str2name("example.org"),
+ name), ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_finddeepestmatch(keytable,
+ str2name("null.example"),
+ name), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(dns_name_equal(name, str2name("null.example")),
+ ISC_TRUE);
+
+ /*
+ * dns_keytable_findkeynode() requires exact name, algorithm, keytag
+ * match. If algorithm or keytag doesn't match, should result in
+ * PARTIALMATCH. Same for a node with a null key or a negative trust
+ * anchor.
+ */
+ ATF_REQUIRE_EQ(dns_keytable_findkeynode(keytable,
+ str2name("example.org"),
+ 5, keytag1, &keynode),
+ ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_findkeynode(keytable,
+ str2name("sub.example.com"),
+ 5, keytag1, &keynode),
+ ISC_R_NOTFOUND);
+ ATF_REQUIRE_EQ(dns_keytable_findkeynode(keytable,
+ str2name("example.com"),
+ 4, keytag1, &keynode),
+ DNS_R_PARTIALMATCH); /* different algorithm */
+ ATF_REQUIRE_EQ(dns_keytable_findkeynode(keytable,
+ str2name("example.com"),
+ 5, keytag1 + 1, &keynode),
+ DNS_R_PARTIALMATCH); /* different keytag */
+ ATF_REQUIRE_EQ(dns_keytable_findkeynode(keytable,
+ str2name("null.example"),
+ 5, 0, &keynode),
+ DNS_R_PARTIALMATCH); /* null key */
+ ATF_REQUIRE_EQ(dns_keytable_findkeynode(keytable,
+ str2name("example.com"),
+ 5, keytag1, &keynode),
+ ISC_R_SUCCESS); /* complete match */
+ dns_keytable_detachkeynode(keytable, &keynode);
+
+ destroy_tables();
+ dns_test_end();
+}
+
+ATF_TC(issecuredomain);
+ATF_TC_HEAD(issecuredomain, tc) {
+ atf_tc_set_md_var(tc, "descr", "check issecuredomain()");
+}
+ATF_TC_BODY(issecuredomain, tc) {
+ isc_boolean_t issecure;
+ const char **n;
+ const char *names[] = {"example.com", "sub.example.com",
+ "null.example", "sub.null.example", NULL};
+
+ UNUSED(tc);
+ ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS);
+ create_tables();
+
+ /*
+ * Domains that are an exact or partial match of a key name are
+ * considered secure. It's the case even if the key is null
+ * (validation will then fail, but that's actually the intended effect
+ * of installing a null key).
+ */
+ for (n = names; *n != NULL; n++) {
+ ATF_REQUIRE_EQ(dns_keytable_issecuredomain(keytable,
+ str2name(*n),
+ NULL,
+ &issecure),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(issecure, ISC_TRUE);
+ }
+
+ /*
+ * Domains that are an exact or partial match of a negative trust
+ * anchor are considered insecure.
+ */
+ ATF_REQUIRE_EQ(dns_keytable_issecuredomain(keytable,
+ str2name("insecure.example"),
+ NULL,
+ &issecure),
+ ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(issecure, ISC_FALSE);
+ ATF_REQUIRE_EQ(dns_keytable_issecuredomain(
+ keytable, str2name("sub.insecure.example"),
+ NULL, &issecure), ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(issecure, ISC_FALSE);
+
+ destroy_tables();
+ dns_test_end();
+}
+
+ATF_TC(dump);
+ATF_TC_HEAD(dump, tc) {
+ atf_tc_set_md_var(tc, "descr", "check dns_keytable_dump()");
+}
+ATF_TC_BODY(dump, tc) {
+ UNUSED(tc);
+
+ ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS);
+ create_tables();
+
+ /*
+ * Right now, we only confirm the dump attempt doesn't cause disruption
+ * (so we don't check the dump content).
+ */
+ ATF_REQUIRE_EQ(dns_keytable_dump(keytable, stdout), ISC_R_SUCCESS);
+
+ destroy_tables();
+ dns_test_end();
+}
+
+ATF_TC(nta);
+ATF_TC_HEAD(nta, tc) {
+ atf_tc_set_md_var(tc, "descr", "check negative trust anchors");
+}
+ATF_TC_BODY(nta, tc) {
+ isc_result_t result;
+ dst_key_t *key = NULL;
+ isc_boolean_t issecure, covered;
+ dns_view_t *view = NULL;
+ isc_stdtime_t now;
+
+ UNUSED(tc);
+
+ result = dns_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_test_makeview("view", &view);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_view_initsecroots(view, mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_view_getsecroots(view, &keytable);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_view_initntatable(view, mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_view_getntatable(view, &ntatable);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ create_key(257, 3, 5, "example", keystr1, &key);
+ result = dns_keytable_add(keytable, ISC_FALSE, &key);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_stdtime_get(&now);
+ result = dns_ntatable_add(ntatable,
+ str2name("insecure.example"), now + 1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* Should be secure */
+ result = dns_view_issecuredomain(view,
+ str2name("test.secure.example"),
+ now, &issecure);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(issecure);
+
+ /* Should not be secure */
+ result = dns_view_issecuredomain(view,
+ str2name("test.insecure.example"),
+ now, &issecure);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(!issecure);
+
+ /* NTA covered */
+ covered = dns_view_ntacovers(view, now, str2name("insecure.example"),
+ dns_rootname);
+ ATF_CHECK(covered);
+
+ /* Not NTA covered */
+ covered = dns_view_ntacovers(view, now, str2name("secure.example"),
+ dns_rootname);
+ ATF_CHECK(!covered);
+
+ /* As of now + 2, the NTA should be clear */
+ result = dns_view_issecuredomain(view,
+ str2name("test.insecure.example"),
+ now + 2, &issecure);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(issecure);
+
+ /* Now check deletion */
+ result = dns_ntatable_add(ntatable,
+ str2name("new.example"), now + 3600);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_view_issecuredomain(view, str2name("test.new.example"),
+ now, &issecure);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(!issecure);
+
+ result = dns_ntatable_delete(ntatable, str2name("new.example"));
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_view_issecuredomain(view, str2name("test.new.example"),
+ now, &issecure);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(issecure);
+
+ /* Clean up */
+ dns_ntatable_detach(&ntatable);
+ dns_keytable_detach(&keytable);
+ dns_view_detach(&view);
+
+ dns_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, add);
+ ATF_TP_ADD_TC(tp, delete);
+ ATF_TP_ADD_TC(tp, deletekeynode);
+ ATF_TP_ADD_TC(tp, find);
+ ATF_TP_ADD_TC(tp, issecuredomain);
+ ATF_TP_ADD_TC(tp, dump);
+ ATF_TP_ADD_TC(tp, nta);
+
+ return (atf_no_error());
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id$ */
-
#include <config.h>
#include <isc/base32.h>
validator_log(val, ISC_LOG_DEBUG(3),
"failed to verify rdataset");
else {
- isc_stdtime_t now;
-
- isc_stdtime_get(&now);
dns_rdataset_trimttl(event->rdataset,
event->sigrdataset,
- val->siginfo, now,
+ val->siginfo, val->start,
val->view->acceptexpired);
}
markanswer(val, "startfinddlvsep (1)");
return (ISC_R_SUCCESS);
}
+ if (result == DNS_R_NTACOVERED) {
+ validator_log(val, ISC_LOG_DEBUG(3), "DLV covered by NTA");
+ validator_done(val, ISC_R_SUCCESS);
+ return (ISC_R_SUCCESS);
+ }
if (result != ISC_R_SUCCESS) {
validator_log(val, ISC_LOG_DEBUG(3), "DLV lookup: %s",
dns_result_totext(result));
return (DNS_R_NOVALIDSIG);
}
+ if (dns_view_ntacovers(val->view, val->start, dlvname, val->view->dlv))
+ return (DNS_R_NTACOVERED);
+
while (dns_name_countlabels(dlvname) >=
dns_name_countlabels(val->view->dlv) + val->dlvlabels) {
dns_name_format(dlvname, namebuf, sizeof(namebuf));
dns_fixedname_init(&val->wild);
dns_fixedname_init(&val->nearest);
dns_fixedname_init(&val->closest);
+ isc_stdtime_get(&val->start);
ISC_LINK_INIT(val, link);
val->magic = VALIDATOR_MAGIC;
#include <dns/keyvalues.h>
#include <dns/master.h>
#include <dns/masterdump.h>
+#include <dns/nta.h>
#include <dns/order.h>
#include <dns/peer.h>
#include <dns/rrl.h>
}
}
view->secroots_priv = NULL;
+ view->ntatable_priv = NULL;
view->fwdtable = NULL;
result = dns_fwdtable_create(mctx, &view->fwdtable);
if (result != ISC_R_SUCCESS) {
dns_stats_detach(&view->resquerystats);
if (view->secroots_priv != NULL)
dns_keytable_detach(&view->secroots_priv);
+ if (view->ntatable_priv != NULL)
+ dns_ntatable_detach(&view->ntatable_priv);
for (dns64 = ISC_LIST_HEAD(view->dns64);
dns64 != NULL;
dns64 = ISC_LIST_HEAD(view->dns64)) {
dns_stats_attach(view->resquerystats, statsp);
}
+isc_result_t
+dns_view_initntatable(dns_view_t *view, isc_mem_t *mctx) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ if (view->ntatable_priv != NULL)
+ dns_ntatable_detach(&view->ntatable_priv);
+ return (dns_ntatable_create(mctx, &view->ntatable_priv));
+}
+
+isc_result_t
+dns_view_getntatable(dns_view_t *view, dns_ntatable_t **ntp) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(ntp != NULL && *ntp == NULL);
+ if (view->ntatable_priv == NULL)
+ return (ISC_R_NOTFOUND);
+ dns_ntatable_attach(view->ntatable_priv, ntp);
+ return (ISC_R_SUCCESS);
+}
+
isc_result_t
dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
REQUIRE(DNS_VIEW_VALID(view));
return (ISC_R_SUCCESS);
}
+isc_boolean_t
+dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now,
+ dns_name_t *name, dns_name_t *anchor)
+{
+ REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->ntatable_priv == NULL)
+ return (ISC_FALSE);
+
+ return (dns_ntatable_covered(view->ntatable_priv, now, name, anchor));
+}
+
isc_result_t
dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
- isc_boolean_t *secure_domain) {
+ isc_stdtime_t now, isc_boolean_t *secure_domain)
+{
+ isc_result_t result;
+ isc_boolean_t secure = ISC_FALSE;
+ dns_fixedname_t fn;
+ dns_name_t *anchor;
+
REQUIRE(DNS_VIEW_VALID(view));
if (view->secroots_priv == NULL)
return (ISC_R_NOTFOUND);
- return (dns_keytable_issecuredomain(view->secroots_priv, name,
- secure_domain));
+
+ dns_fixedname_init(&fn);
+ anchor = dns_fixedname_name(&fn);
+
+ result = dns_keytable_issecuredomain(view->secroots_priv, name,
+ anchor, &secure);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (secure && view->ntatable_priv != NULL &&
+ dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
+ secure = ISC_FALSE;
+
+ *secure_domain = secure;
+ return (ISC_R_SUCCESS);
}
void
dns_nsec_nseconly
dns_nsec_setbit
dns_nsec_typepresent
+dns_nta_create
+dns_ntatable_add
+dns_ntatable_attach
+dns_ntatable_covered
+dns_ntatable_create
+dns_ntatable_delete
+dns_ntatable_detach
+dns_ntatable_dump
dns_opcode_totext
dns_opcodestats_create
dns_opcodestats_dump
# End Source File
# Begin Source File
+SOURCE=..\include\dns\nta.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\dns\order.h
# End Source File
# Begin Source File
# End Source File
# Begin Source File
+SOURCE=..\nta.c
+# End Source File
+# Begin Source File
+
SOURCE=..\order.c
# End Source File
# Begin Source File
-@erase "$(INTDIR)\ncache.obj"
-@erase "$(INTDIR)\nsec.obj"
-@erase "$(INTDIR)\nsec3.obj"
+ -@erase "$(INTDIR)\nta.obj"
@IF OPENSSL
-@erase "$(INTDIR)\openssl_link.obj"
-@erase "$(INTDIR)\openssldh_link.obj"
"$(INTDIR)\ncache.obj" \
"$(INTDIR)\nsec.obj" \
"$(INTDIR)\nsec3.obj" \
+ "$(INTDIR)\nta.obj" \
"$(INTDIR)\order.obj" \
"$(INTDIR)\peer.obj" \
"$(INTDIR)\portlist.obj" \
-@erase "$(INTDIR)\nsec.sbr"
-@erase "$(INTDIR)\nsec3.obj"
-@erase "$(INTDIR)\nsec3.sbr"
+ -@erase "$(INTDIR)\nta.obj"
+ -@erase "$(INTDIR)\nta.sbr"
@IF OPENSSL
-@erase "$(INTDIR)\openssl_link.obj"
-@erase "$(INTDIR)\openssl_link.sbr"
"$(INTDIR)\ncache.sbr" \
"$(INTDIR)\nsec.sbr" \
"$(INTDIR)\nsec3.sbr" \
+ "$(INTDIR)\nta.sbr" \
"$(INTDIR)\order.sbr" \
"$(INTDIR)\peer.sbr" \
"$(INTDIR)\portlist.sbr" \
"$(INTDIR)\ncache.obj" \
"$(INTDIR)\nsec.obj" \
"$(INTDIR)\nsec3.obj" \
+ "$(INTDIR)\nta.obj" \
"$(INTDIR)\order.obj" \
"$(INTDIR)\peer.obj" \
"$(INTDIR)\portlist.obj" \
$(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+SOURCE=..\nta.c
+
+!IF "$(CFG)" == "libdns - @PLATFORM@ Release"
+
+
+"$(INTDIR)\nta.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libdns - @PLATFORM@ Debug"
+
+
+"$(INTDIR)\nta.obj" "$(INTDIR)\nta.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
!ENDIF
SOURCE=..\order.c
<ClCompile Include="..\nsec3.c">\r
<Filter>Library Source Files</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\nta.c">\r
+ <Filter>Library Source Files</Filter>\r
+ </ClCompile>\r
<ClCompile Include="..\order.c">\r
<Filter>Library Source Files</Filter>\r
</ClCompile>\r
<ClInclude Include="..\include\dns\nsec3.h">\r
<Filter>Library Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\include\dns\nta.h">\r
+ <Filter>Library Header Files</Filter>\r
+ </ClInclude>\r
<ClInclude Include="..\include\dns\opcode.h">\r
<Filter>Library Header Files</Filter>\r
</ClInclude>\r
<Filter>Dst Header Files</Filter>\r
</ClInclude>\r
</ItemGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
<ClCompile Include="..\ncache.c" />\r
<ClCompile Include="..\nsec.c" />\r
<ClCompile Include="..\nsec3.c" />\r
+ <ClCompile Include="..\nta.c" />\r
@IF OPENSSL\r
<ClCompile Include="..\openssldh_link.c" />\r
<ClCompile Include="..\openssldsa_link.c" />\r
<ClInclude Include="..\include\dns\ncache.h" />\r
<ClInclude Include="..\include\dns\nsec.h" />\r
<ClInclude Include="..\include\dns\nsec3.h" />\r
+ <ClInclude Include="..\include\dns\nta.h" />\r
<ClInclude Include="..\include\dns\opcode.h" />\r
<ClInclude Include="..\include\dns\order.h" />\r
<ClInclude Include="..\include\dns\peer.h" />\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
<ImportGroup Label="ExtensionTargets">\r
</ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r