diff --git a/CHANGES b/CHANGES index b2fa4d3545..a31feab484 100644 --- a/CHANGES +++ b/CHANGES @@ -54,7 +54,9 @@ 1805. [bug] Pending status was not being cleared when DLV was active. [RT #13501] -1804. [placeholder] rt10114 +1804. [bug] Ensure that if we are queried for glue that it fits + in the additional section or TC is set to tell the + client to retry using TCP. [RT #10114] 1803. [placeholder] rt13483 diff --git a/bin/named/query.c b/bin/named/query.c index 62f9ffacea..119ecbc476 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.262 2004/12/21 10:45:15 jinmei Exp $ */ +/* $Id: query.c,v 1.263 2005/03/15 01:29:09 marka Exp $ */ #include @@ -2886,6 +2886,34 @@ query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) { query_releasename(client, &fname); } +static inline void +answer_in_glue(ns_client_t *client, dns_rdatatype_t qtype) { + dns_name_t *name; + dns_message_t *msg; + dns_section_t section = DNS_SECTION_ADDITIONAL; + dns_rdataset_t *rdataset = NULL; + + msg = client->message; + for (name = ISC_LIST_HEAD(msg->sections[section]); + name != NULL; + name = ISC_LIST_NEXT(name, link)) + if (dns_name_equal(name, client->query.qname)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + if (rdataset->type == qtype) + break; + break; + } + if (rdataset != NULL) { + ISC_LIST_UNLINK(msg->sections[section], name, link); + ISC_LIST_PREPEND(msg->sections[section], name, link); + ISC_LIST_UNLINK(name->list, rdataset, link); + ISC_LIST_PREPEND(name->list, rdataset, link); + rdataset->attributes |= DNS_RDATASETATTR_REQUIREDGLUE; + } +} + /* * Do the bulk of query processing for the current query of 'client'. * If 'event' is non-NULL, we are returning from recursion and 'qtype' @@ -3906,6 +3934,16 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) */ setup_query_sortlist(client); + /* + * If this is a referral and the answer to the question + * is in the glue sort it to the start of the additional + * section. + */ + if (client->message->counts[DNS_SECTION_ANSWER] == 0 && + client->message->rcode == dns_rcode_noerror && + (qtype == dns_rdatatype_a || qtype == dns_rdatatype_aaaa)) + answer_in_glue(client, qtype); + if (client->message->rcode == dns_rcode_nxdomain && client->view->auth_nxdomain == ISC_TRUE) client->message->flags |= DNS_MESSAGEFLAG_AA; diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index a286600bad..1b932d8e19 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.h,v 1.52 2004/12/21 10:45:19 jinmei Exp $ */ +/* $Id: rdataset.h,v 1.53 2005/03/15 01:29:10 marka Exp $ */ #ifndef DNS_RDATASET_H #define DNS_RDATASET_H 1 @@ -161,22 +161,23 @@ struct dns_rdataset { * Used by message.c to indicate that the rdataset's rdata had differing * TTL values, and the rdataset->ttl holds the smallest. */ -#define DNS_RDATASETATTR_QUESTION 0x0001 -#define DNS_RDATASETATTR_RENDERED 0x0002 /* Used by message.c */ -#define DNS_RDATASETATTR_ANSWERED 0x0004 /* Used by server. */ -#define DNS_RDATASETATTR_CACHE 0x0008 /* Used by resolver. */ -#define DNS_RDATASETATTR_ANSWER 0x0010 /* Used by resolver. */ -#define DNS_RDATASETATTR_ANSWERSIG 0x0020 /* Used by resolver. */ -#define DNS_RDATASETATTR_EXTERNAL 0x0040 /* Used by resolver. */ -#define DNS_RDATASETATTR_NCACHE 0x0080 /* Used by resolver. */ -#define DNS_RDATASETATTR_CHAINING 0x0100 /* Used by resolver. */ -#define DNS_RDATASETATTR_TTLADJUSTED 0x0200 /* Used by message.c */ -#define DNS_RDATASETATTR_FIXEDORDER 0x0400 -#define DNS_RDATASETATTR_RANDOMIZE 0x0800 -#define DNS_RDATASETATTR_CHASE 0x1000 /* Used by resolver. */ -#define DNS_RDATASETATTR_NXDOMAIN 0x2000 -#define DNS_RDATASETATTR_NOQNAME 0x4000 -#define DNS_RDATASETATTR_CHECKNAMES 0x8000 /* Used by resolver. */ +#define DNS_RDATASETATTR_QUESTION 0x00000001 +#define DNS_RDATASETATTR_RENDERED 0x00000002 /* Used by message.c */ +#define DNS_RDATASETATTR_ANSWERED 0x00000004 /* Used by server. */ +#define DNS_RDATASETATTR_CACHE 0x00000008 /* Used by resolver. */ +#define DNS_RDATASETATTR_ANSWER 0x00000010 /* Used by resolver. */ +#define DNS_RDATASETATTR_ANSWERSIG 0x00000020 /* Used by resolver. */ +#define DNS_RDATASETATTR_EXTERNAL 0x00000040 /* Used by resolver. */ +#define DNS_RDATASETATTR_NCACHE 0x00000080 /* Used by resolver. */ +#define DNS_RDATASETATTR_CHAINING 0x00000100 /* Used by resolver. */ +#define DNS_RDATASETATTR_TTLADJUSTED 0x00000200 /* Used by message.c */ +#define DNS_RDATASETATTR_FIXEDORDER 0x00000400 +#define DNS_RDATASETATTR_RANDOMIZE 0x00000800 +#define DNS_RDATASETATTR_CHASE 0x00001000 /* Used by resolver. */ +#define DNS_RDATASETATTR_NXDOMAIN 0x00002000 +#define DNS_RDATASETATTR_NOQNAME 0x00004000 +#define DNS_RDATASETATTR_CHECKNAMES 0x00008000 /* Used by resolver. */ +#define DNS_RDATASETATTR_REQUIREDGLUE 0x00010000 /* * _OMITDNSSEC: diff --git a/lib/dns/message.c b/lib/dns/message.c index e13c544f98..735e72b038 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.c,v 1.223 2004/05/05 01:32:58 marka Exp $ */ +/* $Id: message.c,v 1.224 2005/03/15 01:29:09 marka Exp $ */ /*** *** Imports @@ -1783,6 +1783,57 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0) partial = ISC_TRUE; + /* + * Render required glue first. Set TC if it won't fit. + */ + name = ISC_LIST_HEAD(*section); + if (name != NULL) { + rdataset = ISC_LIST_HEAD(name->list); + if (rdataset != NULL && + (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 && + (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) { + void *order_arg = msg->order_arg; + st = *(msg->buffer); + count = 0; + if (partial) + result = dns_rdataset_towirepartial(rdataset, + name, + msg->cctx, + msg->buffer, + msg->order, + order_arg, + rd_options, + &count, + NULL); + else + result = dns_rdataset_towiresorted(rdataset, + name, + msg->cctx, + msg->buffer, + msg->order, + order_arg, + rd_options, + &count); + total += count; + if (partial && result == ISC_R_NOSPACE) { + msg->flags |= DNS_MESSAGEFLAG_TC; + msg->buffer->length += msg->reserved; + msg->counts[sectionid] += total; + return (result); + } + if (result != ISC_R_SUCCESS) { + INSIST(st.used < 65536); + dns_compress_rollback(msg->cctx, + (isc_uint16_t)st.used); + *(msg->buffer) = st; /* rollback */ + msg->buffer->length += msg->reserved; + msg->counts[sectionid] += total; + return (result); + } + rdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } + } + do { name = ISC_LIST_HEAD(*section); if (name == NULL) {