diff --git a/CHANGES b/CHANGES index dee6211117..849f5716af 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +4371. [func] New "minimal-any" option reduces the size of UDP + responses for qtype ANY by returning a single + arbitrarily selected RRset instead of all RRsets. + Thanks to Tony Finch. [RT #41615] + 4370. [bug] Address python3 compatibility issues with RNDC module. [RT #42499] diff --git a/bin/named/config.c b/bin/named/config.c index b0af1be2c3..43c253e30a 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -141,6 +141,7 @@ options {\n\ # sortlist \n\ # topology \n\ auth-nxdomain false;\n\ + minimal-any false;\n\ minimal-responses false;\n\ recursion true;\n\ provide-ixfr true;\n\ diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook index bd7bb4057e..b919a628c7 100644 --- a/bin/named/named.conf.docbook +++ b/bin/named/named.conf.docbook @@ -248,6 +248,7 @@ options { sortlist { address_match_element; ... }; topology { address_match_element; ... }; // not implemented auth-nxdomain boolean; // default changed + minimal-any boolean; minimal-responses boolean; recursion boolean; rrset-order { @@ -446,6 +447,7 @@ view string optional_class sortlist { address_match_element; ... }; topology { address_match_element; ... }; // not implemented auth-nxdomain boolean; // default changed + minimal-any boolean; minimal-responses boolean; recursion boolean; rrset-order { diff --git a/bin/named/query.c b/bin/named/query.c index faa39d6354..599de05d92 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -8339,6 +8339,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) #endif if (type == dns_rdatatype_any) { + /* + * For minimal-any, we only add records that + * match this type or cover this type. + */ + dns_rdatatype_t onetype = 0; #ifdef ALLOW_FILTER_AAAA isc_boolean_t have_aaaa, have_a, have_sig; @@ -8402,6 +8407,21 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * ANY queries. */ dns_rdataset_disassociate(rdataset); + } else if (client->view->minimal_any && + !TCP(client) && !WANTDNSSEC(client) && + qtype == dns_rdatatype_any && + (rdataset->type == dns_rdatatype_sig || + rdataset->type == dns_rdatatype_rrsig)) { + CTRACE(ISC_LOG_DEBUG(5), "query_find: " + "minimal-any skip signature"); + dns_rdataset_disassociate(rdataset); + } else if (client->view->minimal_any && + !TCP(client) && onetype != 0 && + rdataset->type != onetype && + rdataset->covers != onetype) { + CTRACE(ISC_LOG_DEBUG(5), "query_find: " + "minimal-any skip rdataset"); + dns_rdataset_disassociate(rdataset); } else if ((qtype == dns_rdatatype_any || rdataset->type == qtype) && rdataset->type != 0) { #ifdef ALLOW_FILTER_AAAA @@ -8421,6 +8441,15 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) name = (fname != NULL) ? fname : tname; query_prefetch(client, name, rdataset); } + /* + * Remember the first RRtype we find so we + * can skip others with minimal-any. + */ + if (rdataset->type == dns_rdatatype_sig || + rdataset->type == dns_rdatatype_rrsig) + onetype = rdataset->covers; + else + onetype = rdataset->type; query_addrrset(client, fname != NULL ? &fname : &tname, &rdataset, NULL, @@ -9096,6 +9125,14 @@ ns_query_start(ns_client_t *client) { client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY | NS_QUERYATTR_NOADDITIONAL); + /* + * Maybe turn on minimal responses for ANY queries. + */ + if (qtype == dns_rdatatype_any && + client->view->minimal_any && !TCP(client)) + client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY | + NS_QUERYATTR_NOADDITIONAL); + /* * Turn on minimal responses for EDNS/UDP bufsize 512 queries. */ diff --git a/bin/named/server.c b/bin/named/server.c index c622a0fc56..f06678d078 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -3545,6 +3545,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, INSIST(result == ISC_R_SUCCESS); view->auth_nxdomain = cfg_obj_asboolean(obj); + obj = NULL; + result = ns_config_get(maps, "minimal-any", &obj); + INSIST(result == ISC_R_SUCCESS); + view->minimal_any = cfg_obj_asboolean(obj); + obj = NULL; result = ns_config_get(maps, "minimal-responses", &obj); INSIST(result == ISC_R_SUCCESS); diff --git a/bin/tests/system/additional/ns1/named3.conf b/bin/tests/system/additional/ns1/named3.conf new file mode 100644 index 0000000000..52f21b8738 --- /dev/null +++ b/bin/tests/system/additional/ns1/named3.conf @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 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. + */ + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + recursion no; + additional-from-auth no; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + notify no; + minimal-any yes; +}; + +include "../../common/rndc.key"; + +controls { + inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; }; +}; + +zone "rt.example" { + type master; + file "rt.db"; +}; diff --git a/bin/tests/system/additional/tests.sh b/bin/tests/system/additional/tests.sh index 70ebbe5505..51e4ded31b 100644 --- a/bin/tests/system/additional/tests.sh +++ b/bin/tests/system/additional/tests.sh @@ -118,4 +118,25 @@ echo "I:testing with 'minimal-responses no;'" minimal=no dotests +echo "I:testing with 'minimal-any no;'" +n=`expr $n + 1` +$DIG -t ANY www.rt.example @10.53.0.1 -p 5300 > dig.out.$n || ret=1 +grep "ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 2" dig.out.$n > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + +echo "I:reconfiguring server" +cp ns1/named3.conf ns1/named.conf +$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 reconfig 2>&1 | sed 's/^/I:ns1 /' +sleep 2 + +echo "I:testing with 'minimal-any yes;'" +n=`expr $n + 1` +$DIG -t ANY www.rt.example @10.53.0.1 -p 5300 > dig.out.$n || ret=1 +grep "ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1" dig.out.$n > /dev/null || ret=1 +if [ $ret -eq 1 ] ; then + echo "I: failed"; status=1 +fi + exit $status diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 427c14967e..d14538e79b 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -4438,6 +4438,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] has-old-clients yes_or_no; host-statistics yes_or_no; host-statistics-max number; + minimal-any yes_or_no; minimal-responses yes_or_no; multiple-cnames yes_or_no; notify yes_or_no | explicit | master-only; @@ -6196,6 +6197,30 @@ options { + + minimal-any + + + If set to yes, then when + generating a positive response to a query of type + ANY over UDP, the server will reply with only one + of the RRsets for the query name, and its covering + RRSIGs if any, instead of replying with all known + RRsets for the name. Similarly, a query for type + RRSIG will be answered with the RRSIG records covering + only one type. This can reduce the impact of some kinds + of attack traffic, without harming legitimate + clients. (Note, however, that the RRset returned is the + first one found in the database; it is not necessarily + the smallest available RRset.) + Additionally, is + turned on for these queries, so no unnecessary records + will be added to the authority or additional sections. + The default is no. + + + + multiple-cnames diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index e0eb3bd2f4..4e7341d5d6 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -484,6 +484,16 @@ when a system's clock needs to be reset backwards. + + + The new minimal-any reduces the size of + answers to UDP queries for type ANY by implementing one of + the strategies in "draft-ietf-dnsop-refuse-any": returning + a single arbitrarily-selected RRset that matches the query + name rather than returning all of the matching RRsets. + Thanks to Tony Finch for the contribution. [RT #41615] + + diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index cb8e91ee5e..9156e82e0a 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -124,6 +124,7 @@ struct dns_view { isc_boolean_t auth_nxdomain; isc_boolean_t additionalfromcache; isc_boolean_t additionalfromauth; + isc_boolean_t minimal_any; isc_boolean_t minimalresponses; isc_boolean_t enablednssec; isc_boolean_t enablevalidation; diff --git a/lib/dns/view.c b/lib/dns/view.c index 67dcf71125..402c89b63b 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -190,6 +190,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->enablednssec = ISC_TRUE; view->enablevalidation = ISC_TRUE; view->acceptexpired = ISC_FALSE; + view->minimal_any = ISC_FALSE; view->minimalresponses = ISC_FALSE; view->transfer_format = dns_one_answer; view->cacheacl = NULL; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 8e39a476ea..d23365ba27 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -1685,6 +1685,7 @@ view_clauses[] = { { "max-recursion-queries", &cfg_type_uint32, 0 }, { "max-udp-size", &cfg_type_uint32, 0 }, { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, + { "minimal-any", &cfg_type_boolean, 0 }, { "minimal-responses", &cfg_type_boolean, 0 }, { "nta-recheck", &cfg_type_ttlval, 0 }, { "nta-lifetime", &cfg_type_ttlval, 0 },