diff --git a/CHANGES b/CHANGES index 65a8c6a1a6..7344cc2caf 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3461. [bug] Negative responses could incorrectly have AD=1 + set. [RT #32237] + 3458. [bug] Return FORMERR when presented with a overly long domain named in a request. [RT #29682] diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index 76d83bd2a7..d5362a39af 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -136,6 +136,7 @@ EXTERN isc_boolean_t ns_g_memstatistics INIT(ISC_FALSE); EXTERN isc_boolean_t ns_g_clienttest INIT(ISC_FALSE); EXTERN isc_boolean_t ns_g_nosoa INIT(ISC_FALSE); EXTERN isc_boolean_t ns_g_noaa INIT(ISC_FALSE); +EXTERN isc_boolean_t ns_g_nonearest INIT(ISC_FALSE); #undef EXTERN #undef INIT diff --git a/bin/named/main.c b/bin/named/main.c index ce11e3c921..8de92faa55 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -464,6 +464,8 @@ parse_command_line(int argc, char *argv[]) { ns_g_noaa = ISC_TRUE; else if (!strcmp(isc_commandline_argument, "nosyslog")) ns_g_nosyslog = ISC_TRUE; + else if (!strcmp(isc_commandline_argument, "nonearest")) + ns_g_nonearest = ISC_TRUE; else fprintf(stderr, "unknown -T flag '%s\n", isc_commandline_argument); diff --git a/bin/named/query.c b/bin/named/query.c index a2e2789bea..067e1bf6c4 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -4313,7 +4313,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) */ if (found && dns_rdataset_isassociated(rdataset) && - !dns_name_equal(qname, found)) + !dns_name_equal(qname, found) && + !(ns_g_nonearest && + qtype != dns_rdatatype_ds)) { unsigned int count; unsigned int skip; diff --git a/bin/tests/system/dnssec/clean.sh b/bin/tests/system/dnssec/clean.sh index 5f8986d2f2..a1589a4923 100644 --- a/bin/tests/system/dnssec/clean.sh +++ b/bin/tests/system/dnssec/clean.sh @@ -47,3 +47,8 @@ rm -f signer/example.db.after signer/example.db.before rm -f signer/example.db.changed rm -f ns3/lower.example.db ns3/upper.example.db ns3/upper.example.db.lower rm -f ns3/secure.below-cname.example.db +rm -f ns3/expiring.example.db +rm -f ns6/optout-tld.db +rm -f nosign.before +rm -f signing.out* +rm -f canonical?.* diff --git a/bin/tests/system/dnssec/ns1/root.db.in b/bin/tests/system/dnssec/ns1/root.db.in index b11fa0c109..5e98cd8dc2 100644 --- a/bin/tests/system/dnssec/ns1/root.db.in +++ b/bin/tests/system/dnssec/ns1/root.db.in @@ -32,3 +32,5 @@ dlv. NS ns2.dlv. ns2.dlv. A 10.53.0.2 algroll NS ns2.algroll ns2.algroll. A 10.53.0.2 +optout-tld NS ns6.optout-tld. +ns6.optout-tld. A 10.53.0.6 diff --git a/bin/tests/system/dnssec/ns1/sign.sh b/bin/tests/system/dnssec/ns1/sign.sh index 1f5b955001..78204f9a4e 100644 --- a/bin/tests/system/dnssec/ns1/sign.sh +++ b/bin/tests/system/dnssec/ns1/sign.sh @@ -27,14 +27,16 @@ infile=root.db.in zonefile=root.db (cd ../ns2 && sh sign.sh ) +(cd ../ns6 && sh sign.sh ) cp ../ns2/dsset-example. . cp ../ns2/dsset-dlv. . grep "8 [12] " ../ns2/dsset-algroll. > dsset-algroll. +cp ../ns6/dsset-optout-tld. . keyname=`$KEYGEN -r $RANDFILE -a RSAMD5 -b 768 -n zone $zone` -cat $infile $keyname.key dsset-example. dsset-dlv. dsset-algroll. > $zonefile +cat $infile $keyname.key dsset-example. dsset-dlv. dsset-algroll. dsset-optout-tld. > $zonefile $SIGNER -P -r $RANDFILE -o $zone $zonefile > /dev/null diff --git a/bin/tests/system/dnssec/ns6/named.args b/bin/tests/system/dnssec/ns6/named.args new file mode 100644 index 0000000000..340fbaf54a --- /dev/null +++ b/bin/tests/system/dnssec/ns6/named.args @@ -0,0 +1 @@ +-m record,size,mctx -c named.conf -d 99 -g -T nonearest -T clienttest diff --git a/bin/tests/system/dnssec/ns6/named.conf b/bin/tests/system/dnssec/ns6/named.conf index eb35680ef2..54221cefbd 100644 --- a/bin/tests/system/dnssec/ns6/named.conf +++ b/bin/tests/system/dnssec/ns6/named.conf @@ -42,4 +42,9 @@ zone "." { file "../../common/root.hint"; }; +zone "optout-tld" { + type master; + file "optout-tld.db.signed"; +}; + include "trusted.conf"; diff --git a/bin/tests/system/dnssec/ns6/optout-tld.db.in b/bin/tests/system/dnssec/ns6/optout-tld.db.in new file mode 100644 index 0000000000..8cdb0aab36 --- /dev/null +++ b/bin/tests/system/dnssec/ns6/optout-tld.db.in @@ -0,0 +1,26 @@ +; Copyright (C) 2010 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: example.db.in,v 1.2 2010/06/03 06:29:03 marka Exp $ +$TTL 60 +optout-tld. 60 IN SOA example. . 0 0 0 0 0 +optout-tld. 60 IN NS ns6.optout-tld. +ns6.optout-tld. 60 IN A 10.53.0.6 +a 60 PTR example. +b 60 PTR example. +a.b.c.d 60 NS example. +e 60 PTR example. +f 60 PTR example. +g 60 PTR example. +h 60 PTR example. diff --git a/bin/tests/system/dnssec/ns6/sign.sh b/bin/tests/system/dnssec/ns6/sign.sh new file mode 100644 index 0000000000..6441a191ec --- /dev/null +++ b/bin/tests/system/dnssec/ns6/sign.sh @@ -0,0 +1,33 @@ +#!/bin/sh -e +# +# Copyright (C) 2004, 2006-2012 Internet Systems Consortium, Inc. ("ISC") +# 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 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: sign.sh,v 1.43 2011/11/04 05:36:28 each Exp $ + +SYSTEMTESTTOP=../.. +. $SYSTEMTESTTOP/conf.sh + +RANDFILE=../random.data + +zone=optout-tld +infile=optout-tld.db.in +zonefile=optout-tld.db + +keyname=`$KEYGEN -r $RANDFILE -a RSASHA256 -b 768 -n zone $zone` + +cat $infile $keyname.key >$zonefile + +$SIGNER -P -3 - -A -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1 diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 7403d1c9a7..d312804874 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -1290,5 +1290,25 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:check against against missing nearest provable proof ($n)" +$DIG $DIGOPTS +norec b.c.d.optout-tld. \ + @10.53.0.6 ds > dig.out.ds.ns6.test$n || ret=1 +nsec3=`grep "IN.NSEC3" dig.out.ds.ns6.test$n | wc -l` +[ $nsec3 -eq 2 ] || ret=1 +$DIG $DIGOPTS +norec b.c.d.optout-tld. \ + @10.53.0.6 A > dig.out.ns6.test$n || ret=1 +nsec3=`grep "IN.NSEC3" dig.out.ns6.test$n | wc -l` +[ $nsec3 -eq 1 ] || ret=1 +$DIG $DIGOPTS optout-tld. \ + @10.53.0.4 SOA > dig.out.soa.ns4.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.soa.ns4.test$n > /dev/null || ret=1 +$DIG $DIGOPTS b.c.d.optout-tld. \ + @10.53.0.4 A > dig.out.ns4.test$n || ret=1 +grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" 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:exit status: $status" exit $status diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h index 8497c307e5..2569bda3cd 100644 --- a/lib/dns/include/dns/ncache.h +++ b/lib/dns/include/dns/ncache.h @@ -73,6 +73,11 @@ dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, * rdataset, and store it in 'cache' at 'node' with a TTL limited to * 'maxttl'. * + * \li dns_ncache_add produces a negative cache entry with a trust of no + * more than answer + * \li dns_ncache_addoptout produces a negative cache entry which will have + * a trust of secure if all the records that make up the entry are secure. + * * The 'covers' argument is the RR type whose nonexistence we are caching, * or dns_rdatatype_any when caching a NXDOMAIN response. * diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h index 265e498924..fd888b3042 100644 --- a/lib/dns/include/dns/validator.h +++ b/lib/dns/include/dns/validator.h @@ -104,6 +104,10 @@ typedef struct dns_validatorevent { * Optout proof seen. */ isc_boolean_t optout; + /* + * Answer is secure. + */ + isc_boolean_t secure; } dns_validatorevent_t; #define DNS_VALIDATOR_NOQNAMEPROOF 0 diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c index 077a217dd7..e7fdbd38e6 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -47,6 +47,12 @@ * */ +static isc_result_t +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, isc_boolean_t secure, + dns_rdataset_t *addedrdataset); + static inline isc_result_t copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) { isc_result_t result; @@ -96,8 +102,8 @@ 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)); + return (addoptout(message, cache, node, covers, now, maxttl, + ISC_FALSE, ISC_FALSE, addedrdataset)); } isc_result_t @@ -105,6 +111,16 @@ 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) +{ + return (addoptout(message, cache, node, covers, now, maxttl, + optout, ISC_TRUE, addedrdataset)); +} + +static isc_result_t +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, isc_boolean_t secure, + dns_rdataset_t *addedrdataset) { isc_result_t result; isc_buffer_t buffer; @@ -293,6 +309,8 @@ dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, dns_rdataset_init(&ncrdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) == ISC_R_SUCCESS); + if (!secure && trust > dns_trust_answer) + trust = dns_trust_answer; ncrdataset.trust = trust; ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE; if (message->rcode == dns_rcode_nxdomain) diff --git a/lib/dns/nsec.c b/lib/dns/nsec.c index 5e1d5d7d6f..65969f0948 100644 --- a/lib/dns/nsec.c +++ b/lib/dns/nsec.c @@ -312,7 +312,7 @@ dns_nsec_noexistnodata(dns_rdatatype_t type, dns_name_t *name, } dns_rdataset_current(nsecset, &rdata); - (*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant nsec"); + (*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC"); relation = dns_name_fullcompare(name, nsecname, &order, &olabels); if (order < 0) { diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index ca9f6d3ba3..24288e3b25 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -448,6 +448,7 @@ static isc_result_t ncache_adderesult(dns_message_t *message, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, isc_boolean_t optout, + isc_boolean_t secure, dns_rdataset_t *ardataset, isc_result_t *eresultp); static void validated(isc_task_t *task, isc_event_t *event); @@ -4224,7 +4225,7 @@ validated(isc_task_t *task, isc_event_t *event) { result = ncache_adderesult(fctx->rmessage, fctx->cache, node, covers, now, ttl, vevent->optout, - ardataset, &eresult); + vevent->secure, ardataset, &eresult); if (result != ISC_R_SUCCESS) goto noanswer_response; goto answer_response; @@ -4966,8 +4967,8 @@ cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) 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) + isc_boolean_t optout, isc_boolean_t secure, + dns_rdataset_t *ardataset, isc_result_t *eresultp) { isc_result_t result; dns_rdataset_t rdataset; @@ -4976,8 +4977,12 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdataset_init(&rdataset); ardataset = &rdataset; } - result = dns_ncache_addoptout(message, cache, node, covers, now, - maxttl, optout, ardataset); + if (secure) + result = dns_ncache_addoptout(message, cache, node, covers, + now, maxttl, optout, ardataset); + else + result = dns_ncache_add(message, cache, node, covers, now, + maxttl, ardataset); if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) { /* * If the cache now contains a negative entry and we @@ -5144,7 +5149,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = ncache_adderesult(fctx->rmessage, fctx->cache, node, covers, now, ttl, ISC_FALSE, - ardataset, &eresult); + ISC_FALSE, ardataset, &eresult); if (result != ISC_R_SUCCESS) goto unlock; diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 4a497b449a..0191dc051a 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -195,6 +195,7 @@ marksecure(dns_validatorevent_t *event) { dns_rdataset_settrust(event->rdataset, dns_trust_secure); if (event->sigrdataset != NULL) dns_rdataset_settrust(event->sigrdataset, dns_trust_secure); + event->secure = ISC_TRUE; } static void @@ -2818,6 +2819,8 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { "nonexistence proof(s) found"); if (val->event->message == NULL) marksecure(val->event); + else + val->event->secure = ISC_TRUE; return (ISC_R_SUCCESS); } findnsec3proofs(val); @@ -3676,6 +3679,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, event->message = message; memset(event->proofs, 0, sizeof(event->proofs)); event->optout = ISC_FALSE; + event->secure = ISC_FALSE; result = isc_mutex_init(&val->lock); if (result != ISC_R_SUCCESS) goto cleanup_event;