diff --git a/lib/dns/message.c b/lib/dns/message.c index db2090aaad..992f025792 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -1253,17 +1253,21 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx, bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0); bool isedns, issigzero, istsig; - if (msg->counts[sectionid] == 0) { + isc_lhashmap_t name_map; + isc_lhashmap_t name_rdtype_map; + + size_t section_count = msg->counts[sectionid]; + if (section_count == 0) { return ISC_R_SUCCESS; + } else if (section_count >= 2) { + char* lhashmap_buffer = thread_local_name_buffer(); + name_map = isc_lhashmap_init(section_count, sizeof(dns_name_t*), lhashmap_buffer, name_hash, name_match); + + char* lhashmap_rd_buffer = thread_local_rd_buffer(); + name_rdtype_map = isc_lhashmap_init(section_count, sizeof(name_and_rdtype_t), lhashmap_rd_buffer, name_and_rdtype_hash, name_and_rdtype_match); } - char* lhashmap_buffer = thread_local_name_buffer(); - isc_lhashmap_t name_map = isc_lhashmap_init(msg->counts[sectionid], sizeof(dns_name_t*), lhashmap_buffer, name_hash, name_match); - - char* lhashmap_rd_buffer = thread_local_rd_buffer(); - isc_lhashmap_t name_rdtype_map = isc_lhashmap_init(msg->counts[sectionid], sizeof(name_and_rdtype_t), lhashmap_rd_buffer, name_and_rdtype_hash, name_and_rdtype_match); - - for (count = 0; count < msg->counts[sectionid]; count++) { + for (count = 0; count < section_count; count++) { int recstart = source->current; bool skip_name_search, skip_type_search; @@ -1499,7 +1503,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx, * to the end of the message. */ if (preserve_order || msg->opcode == dns_opcode_update || - skip_name_search) + skip_name_search || section_count <= 1) { if (!isedns && !istsig && !issigzero) { ISC_LIST_APPEND(*section, name, link); @@ -1546,6 +1550,18 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx, { result = ISC_R_SUCCESS; + ISC_LIST_APPEND(name->list, rdataset, link); + } else if (section_count <= 1) { + /* + * If this is a type that can only occur in + * the question section, fail. + */ + if (dns_rdatatype_questiononly(rdtype)) { + DO_ERROR(DNS_R_FORMERR); + } + + result = ISC_R_SUCCESS; + ISC_LIST_APPEND(name->list, rdataset, link); } else { /*