diff --git a/CHANGES b/CHANGES index 08e484f196..98d39f8d3f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ + 856. [func] Allow partial rdatasets to be returned in answer and + authority sections to help non-TCP capable clients + recover from truncation. [RT #1301] + 855. [bug] Stop spurious "using RFC 1035 TTL semantics" warnings. 854. [bug] The config parser didn't properly handle config diff --git a/bin/named/client.c b/bin/named/client.c index 0e880ab8fe..deda02f00e 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.170 2001/06/04 19:32:52 tale Exp $ */ +/* $Id: client.c,v 1.171 2001/06/05 09:02:10 marka Exp $ */ #include @@ -865,7 +865,8 @@ ns_client_send(ns_client_t *client) { if (result != ISC_R_SUCCESS) goto done; result = dns_message_rendersection(client->message, - DNS_SECTION_ANSWER, 0); + DNS_SECTION_ANSWER, + DNS_MESSAGERENDER_PARTIAL); if (result == ISC_R_NOSPACE) { client->message->flags |= DNS_MESSAGEFLAG_TC; goto renderend; @@ -873,7 +874,8 @@ ns_client_send(ns_client_t *client) { if (result != ISC_R_SUCCESS) goto done; result = dns_message_rendersection(client->message, - DNS_SECTION_AUTHORITY, 0); + DNS_SECTION_AUTHORITY, + DNS_MESSAGERENDER_PARTIAL); if (result == ISC_R_NOSPACE) { client->message->flags |= DNS_MESSAGEFLAG_TC; goto renderend; diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index eadcfc2d93..d891ccd1f2 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.h,v 1.97 2001/03/28 02:42:56 bwelling Exp $ */ +/* $Id: message.h,v 1.98 2001/06/05 09:02:14 marka Exp $ */ #ifndef DNS_MESSAGE_H #define DNS_MESSAGE_H 1 @@ -157,6 +157,7 @@ typedef int dns_messagetextflag_t; * Control behavior of rendering */ #define DNS_MESSAGERENDER_ORDERED 0x0001 /* don't change order */ +#define DNS_MESSAGERENDER_PARTIAL 0x0002 /* allow a partial rdataset */ typedef struct dns_msgblock dns_msgblock_t; diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index e5b15b75fe..70b3ba00c0 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.h,v 1.39 2001/03/28 00:22:16 gson Exp $ */ +/* $Id: rdataset.h,v 1.40 2001/06/05 09:02:16 marka Exp $ */ #ifndef DNS_RDATASET_H #define DNS_RDATASET_H 1 @@ -355,6 +355,34 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, * that order_arg is NULL if and only if order is NULL. */ +isc_result_t +dns_rdataset_towirepartial(dns_rdataset_t *rdataset, + dns_name_t *owner_name, + dns_compress_t *cctx, + isc_buffer_t *target, + dns_rdatasetorderfunc_t order, + void *order_arg, + unsigned int *countp, + void **state); +/* + * Like dns_rdataset_towiresorted() except that a partial rdataset + * may be written. + * + * Requires: + * All the requirements of dns_rdataset_towiresorted(). + * If 'state' is non NULL then the current position in the + * rdataset will be remembered if the rdataset in not + * completely written and should be passed on on subsequent + * calls (NOT CURRENTLY IMPLEMENTED). + * + * Returns: + * ISC_R_SUCCESS if all of the records were written. + * ISC_R_NOSPACE if unable to fit in all of the records. *countp + * will be updated to reflect the number of records + * written. + */ + + isc_result_t dns_rdataset_additionaldata(dns_rdataset_t *rdataset, dns_additionaldatafunc_t add, void *arg); diff --git a/lib/dns/message.c b/lib/dns/message.c index 979ee6d893..6410fb1341 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.c,v 1.190 2001/04/19 18:28:35 bwelling Exp $ */ +/* $Id: message.c,v 1.191 2001/06/05 09:02:11 marka Exp $ */ /*** *** Imports @@ -1723,6 +1723,7 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, isc_result_t result; isc_buffer_t st; /* for rollbacks */ int pass; + isc_boolean_t partial = ISC_FALSE; REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(msg->buffer != NULL); @@ -1742,6 +1743,8 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, msg->buffer->length -= msg->reserved; total = 0; + if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0) + partial = ISC_TRUE; do { name = ISC_LIST_HEAD(*section); @@ -1771,7 +1774,19 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, st = *(msg->buffer); count = 0; - result = dns_rdataset_towiresorted(rdataset, + if (partial) + result = dns_rdataset_towirepartial( + rdataset, + name, + msg->cctx, + msg->buffer, + msg->order, + msg->order_arg, + &count, + NULL); + else + result = dns_rdataset_towiresorted( + rdataset, name, msg->cctx, msg->buffer, @@ -1794,6 +1809,11 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, * somewhere (probably in the message struct) * to indicate where to continue from. */ + if (partial && result == ISC_R_NOSPACE) { + 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, diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index 96b0f984a1..166c66cf90 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.c,v 1.55 2001/01/09 21:51:23 bwelling Exp $ */ +/* $Id: rdataset.c,v 1.56 2001/06/05 09:02:13 marka Exp $ */ #include @@ -269,19 +269,17 @@ towire_compare(const void *av, const void *bv) { return (a->key - b->key); } -isc_result_t -dns_rdataset_towiresorted(dns_rdataset_t *rdataset, - dns_name_t *owner_name, - dns_compress_t *cctx, - isc_buffer_t *target, - dns_rdatasetorderfunc_t order, - void *order_arg, - unsigned int *countp) +static isc_result_t +towiresorted(dns_rdataset_t *rdataset, dns_name_t *owner_name, + dns_compress_t *cctx, isc_buffer_t *target, + dns_rdatasetorderfunc_t order, void *order_arg, + isc_boolean_t partial, unsigned int *countp, + void **state) { dns_rdata_t rdata = DNS_RDATA_INIT; isc_region_t r; isc_result_t result; - unsigned int i, count; + unsigned int i, count, added; isc_buffer_t savedbuffer, rdlen; unsigned int headlen; isc_boolean_t question = ISC_FALSE; @@ -289,6 +287,8 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, dns_rdata_t shuffled[MAX_SHUFFLE]; struct towire_sort sorted[MAX_SHUFFLE]; + UNUSED(state); + /* * Convert 'rdataset' to wire format, compressing names as specified * in cctx, and storing the result in 'target'. @@ -376,6 +376,7 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, savedbuffer = *target; i = 0; + added = 0; do { /* @@ -422,6 +423,7 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, isc_buffer_putuint16(&rdlen, (isc_uint16_t)(target->used - rdlen.used - 2)); + added++; } if (shuffle) { @@ -443,6 +445,10 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, return (ISC_R_SUCCESS); rollback: + if (partial && result == ISC_R_NOSPACE) { + *countp += added; + return (result); + } INSIST(savedbuffer.used < 65536); dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used); *countp = 0; @@ -451,6 +457,34 @@ dns_rdataset_towiresorted(dns_rdataset_t *rdataset, return (result); } +isc_result_t +dns_rdataset_towiresorted(dns_rdataset_t *rdataset, + dns_name_t *owner_name, + dns_compress_t *cctx, + isc_buffer_t *target, + dns_rdatasetorderfunc_t order, + void *order_arg, + unsigned int *countp) +{ + return (towiresorted(rdataset, owner_name, cctx, target, + order, order_arg, ISC_FALSE, countp, NULL)); +} + +isc_result_t +dns_rdataset_towirepartial(dns_rdataset_t *rdataset, + dns_name_t *owner_name, + dns_compress_t *cctx, + isc_buffer_t *target, + dns_rdatasetorderfunc_t order, + void *order_arg, + unsigned int *countp, + void **state) +{ + REQUIRE(state == NULL); /* XXX remove when implemented */ + return (towiresorted(rdataset, owner_name, cctx, target, + order, order_arg, ISC_TRUE, countp, state)); +} + isc_result_t dns_rdataset_towire(dns_rdataset_t *rdataset, dns_name_t *owner_name, @@ -458,8 +492,8 @@ dns_rdataset_towire(dns_rdataset_t *rdataset, isc_buffer_t *target, unsigned int *countp) { - return (dns_rdataset_towiresorted(rdataset, owner_name, cctx, target, - NULL, NULL, countp)); + return (towiresorted(rdataset, owner_name, cctx, target, + NULL, NULL, ISC_FALSE, countp, NULL)); } isc_result_t