|
|
|
|
@@ -22,6 +22,8 @@
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
|
|
#include <isc/buffer.h>
|
|
|
|
|
#include <isc/hash.h>
|
|
|
|
|
#include <isc/ht.h>
|
|
|
|
|
#include <isc/mem.h>
|
|
|
|
|
#include <isc/print.h>
|
|
|
|
|
#include <isc/result.h>
|
|
|
|
|
@@ -493,9 +495,11 @@ msgresetsigs(dns_message_t *msg, bool replying) {
|
|
|
|
|
} else {
|
|
|
|
|
dns_rdataset_disassociate(msg->tsig);
|
|
|
|
|
isc_mempool_put(msg->rdspool, msg->tsig);
|
|
|
|
|
msg->tsig = NULL;
|
|
|
|
|
if (msg->querytsig != NULL) {
|
|
|
|
|
dns_rdataset_disassociate(msg->querytsig);
|
|
|
|
|
isc_mempool_put(msg->rdspool, msg->querytsig);
|
|
|
|
|
msg->querytsig = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dns_message_puttempname(msg, &msg->tsigname);
|
|
|
|
|
@@ -790,6 +794,18 @@ dns_message_detach(dns_message_t **messagep) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
name_hash_add(isc_ht_t *ht, dns_name_t *name, dns_name_t **foundp) {
|
|
|
|
|
isc_result_t result = isc_ht_find(ht, name->ndata, name->length,
|
|
|
|
|
(void **)foundp);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
return (ISC_R_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
result = isc_ht_add(ht, name->ndata, name->length, (void *)name);
|
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
findname(dns_name_t **foundname, const dns_name_t *target,
|
|
|
|
|
dns_namelist_t *section) {
|
|
|
|
|
@@ -809,29 +825,26 @@ findname(dns_name_t **foundname, const dns_name_t *target,
|
|
|
|
|
return (ISC_R_NOTFOUND);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
|
dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
|
|
|
|
|
dns_rdatatype_t type, dns_rdatatype_t covers,
|
|
|
|
|
dns_rdataset_t **rdataset) {
|
|
|
|
|
dns_rdataset_t *curr;
|
|
|
|
|
typedef struct __attribute__((__packed__)) rds_key {
|
|
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
|
dns_rdatatype_t type;
|
|
|
|
|
dns_rdatatype_t covers;
|
|
|
|
|
} rds_key_t;
|
|
|
|
|
|
|
|
|
|
REQUIRE(name != NULL);
|
|
|
|
|
REQUIRE(rdataset == NULL || *rdataset == NULL);
|
|
|
|
|
|
|
|
|
|
for (curr = ISC_LIST_TAIL(name->list); curr != NULL;
|
|
|
|
|
curr = ISC_LIST_PREV(curr, link))
|
|
|
|
|
{
|
|
|
|
|
if (curr->rdclass == rdclass && curr->type == type &&
|
|
|
|
|
curr->covers == covers)
|
|
|
|
|
{
|
|
|
|
|
if (rdataset != NULL) {
|
|
|
|
|
*rdataset = curr;
|
|
|
|
|
}
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
static isc_result_t
|
|
|
|
|
rds_hash_add(isc_ht_t *ht, dns_rdataset_t *rds, dns_rdataset_t **foundp) {
|
|
|
|
|
rds_key_t key = { .rdclass = rds->rdclass,
|
|
|
|
|
.type = rds->type,
|
|
|
|
|
.covers = rds->covers };
|
|
|
|
|
isc_result_t result = isc_ht_find(ht, (const unsigned char *)&key,
|
|
|
|
|
sizeof(key), (void **)foundp);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
return (ISC_R_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (ISC_R_NOTFOUND);
|
|
|
|
|
result = isc_ht_add(ht, (const unsigned char *)&key, sizeof(key),
|
|
|
|
|
(void *)rds);
|
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
|
@@ -958,6 +971,18 @@ getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
cleanup_name_hashmaps(dns_namelist_t *section) {
|
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
for (name = ISC_LIST_HEAD(*section); name != NULL;
|
|
|
|
|
name = ISC_LIST_NEXT(name, link))
|
|
|
|
|
{
|
|
|
|
|
if (name->ht != NULL) {
|
|
|
|
|
isc_ht_destroy(&name->ht);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
|
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
unsigned int options) {
|
|
|
|
|
@@ -967,13 +992,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
dns_name_t *name2 = NULL;
|
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
dns_rdatatype_t rdtype;
|
|
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
|
dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION];
|
|
|
|
|
bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
|
|
|
|
|
bool seen_problem = false;
|
|
|
|
|
bool free_name = false;
|
|
|
|
|
bool free_ht = false;
|
|
|
|
|
isc_ht_t *name_map = NULL;
|
|
|
|
|
|
|
|
|
|
if (msg->counts[DNS_SECTION_QUESTION] > 1) {
|
|
|
|
|
isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
|
|
|
|
|
name = NULL;
|
|
|
|
|
@@ -994,13 +1025,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there is only one QNAME, skip the duplicity checks */
|
|
|
|
|
if (name_map == NULL) {
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
goto skip_name_check;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Run through the section, looking to see if this name
|
|
|
|
|
* is already there. If it is found, put back the allocated
|
|
|
|
|
* name since we no longer need it, and set our name pointer
|
|
|
|
|
* to point to the name we found.
|
|
|
|
|
*/
|
|
|
|
|
result = findname(&name2, name, section);
|
|
|
|
|
result = name_hash_add(name_map, name, &name2);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If it is the first name in the section, accept it.
|
|
|
|
|
@@ -1012,19 +1049,25 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
* this should be legal or not. In either case we no longer
|
|
|
|
|
* need this name pointer.
|
|
|
|
|
*/
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
skip_name_check:
|
|
|
|
|
switch (result) {
|
|
|
|
|
case ISC_R_SUCCESS:
|
|
|
|
|
if (!ISC_LIST_EMPTY(*section)) {
|
|
|
|
|
DO_ERROR(DNS_R_FORMERR);
|
|
|
|
|
}
|
|
|
|
|
ISC_LIST_APPEND(*section, name, link);
|
|
|
|
|
free_name = false;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
case ISC_R_EXISTS:
|
|
|
|
|
dns_message_puttempname(msg, &name);
|
|
|
|
|
name = name2;
|
|
|
|
|
name2 = NULL;
|
|
|
|
|
free_name = false;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free_name = false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get type and class.
|
|
|
|
|
*/
|
|
|
|
|
@@ -1054,14 +1097,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
msg->tkey = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Can't ask the same question twice.
|
|
|
|
|
*/
|
|
|
|
|
result = dns_message_find(name, rdclass, rdtype, 0, NULL);
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
DO_ERROR(DNS_R_FORMERR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Allocate a new rdatalist.
|
|
|
|
|
*/
|
|
|
|
|
@@ -1071,6 +1106,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
rdataset = isc_mempool_get(msg->rdspool);
|
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert rdatalist to rdataset, and attach the latter to
|
|
|
|
|
@@ -1078,8 +1114,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
*/
|
|
|
|
|
rdatalist->type = rdtype;
|
|
|
|
|
rdatalist->rdclass = rdclass;
|
|
|
|
|
|
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
|
result = dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
|
goto cleanup;
|
|
|
|
|
@@ -1087,14 +1121,46 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
|
|
|
|
|
rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Skip the duplicity check for first rdataset
|
|
|
|
|
*/
|
|
|
|
|
if (ISC_LIST_EMPTY(name->list)) {
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
goto skip_rds_check;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Can't ask the same question twice.
|
|
|
|
|
*/
|
|
|
|
|
if (name->ht == NULL) {
|
|
|
|
|
isc_ht_init(&name->ht, msg->mctx, 1,
|
|
|
|
|
ISC_HT_CASE_SENSITIVE);
|
|
|
|
|
free_ht = true;
|
|
|
|
|
|
|
|
|
|
INSIST(ISC_LIST_HEAD(name->list) ==
|
|
|
|
|
ISC_LIST_TAIL(name->list));
|
|
|
|
|
|
|
|
|
|
dns_rdataset_t *old_rdataset =
|
|
|
|
|
ISC_LIST_HEAD(name->list);
|
|
|
|
|
|
|
|
|
|
result = rds_hash_add(name->ht, old_rdataset, NULL);
|
|
|
|
|
|
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
result = rds_hash_add(name->ht, rdataset, NULL);
|
|
|
|
|
if (result == ISC_R_EXISTS) {
|
|
|
|
|
DO_ERROR(DNS_R_FORMERR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skip_rds_check:
|
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
|
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seen_problem) {
|
|
|
|
|
return (DNS_R_RECOVERABLE);
|
|
|
|
|
result = DNS_R_RECOVERABLE;
|
|
|
|
|
}
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
if (rdataset != NULL) {
|
|
|
|
|
@@ -1105,6 +1171,14 @@ cleanup:
|
|
|
|
|
dns_message_puttempname(msg, &name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (free_ht) {
|
|
|
|
|
cleanup_name_hashmaps(section);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name_map != NULL) {
|
|
|
|
|
isc_ht_destroy(&name_map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1184,17 +1258,24 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
dns_name_t *name2 = NULL;
|
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
|
dns_rdataset_t *found_rdataset = NULL;
|
|
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
dns_rdatatype_t rdtype, covers;
|
|
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
|
dns_ttl_t ttl;
|
|
|
|
|
dns_namelist_t *section = &msg->sections[sectionid];
|
|
|
|
|
bool free_name = false, free_rdataset = false, seen_problem = false;
|
|
|
|
|
bool free_name = false, seen_problem = false;
|
|
|
|
|
bool free_ht = false;
|
|
|
|
|
bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
|
|
|
|
|
bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
|
|
|
|
|
bool isedns, issigzero, istsig;
|
|
|
|
|
isc_ht_t *name_map = NULL;
|
|
|
|
|
|
|
|
|
|
if (msg->counts[sectionid] > 1) {
|
|
|
|
|
isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (count = 0; count < msg->counts[sectionid]; count++) {
|
|
|
|
|
int recstart = source->current;
|
|
|
|
|
@@ -1202,7 +1283,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
|
|
|
|
|
skip_name_search = false;
|
|
|
|
|
skip_type_search = false;
|
|
|
|
|
free_rdataset = false;
|
|
|
|
|
isedns = false;
|
|
|
|
|
issigzero = false;
|
|
|
|
|
istsig = false;
|
|
|
|
|
@@ -1245,8 +1325,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
if (msg->rdclass_set == 0 &&
|
|
|
|
|
rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
|
|
|
|
|
rdtype != dns_rdatatype_tsig && /* class is ANY */
|
|
|
|
|
rdtype != dns_rdatatype_tkey)
|
|
|
|
|
{ /* class is undefined */
|
|
|
|
|
rdtype != dns_rdatatype_tkey) /* class is undefined */
|
|
|
|
|
{
|
|
|
|
|
msg->rdclass = rdclass;
|
|
|
|
|
msg->rdclass_set = 1;
|
|
|
|
|
}
|
|
|
|
|
@@ -1445,61 +1525,124 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
free_name = false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (name_map == NULL) {
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
goto skip_name_check;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Run through the section, looking to see if this name
|
|
|
|
|
* is already there. If it is found, put back the
|
|
|
|
|
* allocated name since we no longer need it, and set
|
|
|
|
|
* our name pointer to point to the name we found.
|
|
|
|
|
*/
|
|
|
|
|
result = findname(&name2, name, section);
|
|
|
|
|
result = name_hash_add(name_map, name, &name2);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If it is a new name, append to the section.
|
|
|
|
|
*/
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
skip_name_check:
|
|
|
|
|
switch (result) {
|
|
|
|
|
case ISC_R_SUCCESS:
|
|
|
|
|
ISC_LIST_APPEND(*section, name, link);
|
|
|
|
|
break;
|
|
|
|
|
case ISC_R_EXISTS:
|
|
|
|
|
dns_message_puttempname(msg, &name);
|
|
|
|
|
name = name2;
|
|
|
|
|
} else {
|
|
|
|
|
ISC_LIST_APPEND(*section, name, link);
|
|
|
|
|
name2 = NULL;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
free_name = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdatalist = newrdatalist(msg);
|
|
|
|
|
rdatalist->type = rdtype;
|
|
|
|
|
rdatalist->covers = covers;
|
|
|
|
|
rdatalist->rdclass = rdclass;
|
|
|
|
|
rdatalist->ttl = ttl;
|
|
|
|
|
|
|
|
|
|
dns_message_gettemprdataset(msg, &rdataset);
|
|
|
|
|
RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
|
|
|
|
|
ISC_R_SUCCESS);
|
|
|
|
|
dns_rdataset_setownercase(rdataset, name);
|
|
|
|
|
rdatalist = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Search name for the particular type and class.
|
|
|
|
|
* Skip this stage if in update mode or this is a meta-type.
|
|
|
|
|
*/
|
|
|
|
|
if (preserve_order || msg->opcode == dns_opcode_update ||
|
|
|
|
|
skip_type_search)
|
|
|
|
|
if (isedns || istsig || issigzero) {
|
|
|
|
|
/* Skip adding the rdataset to the tables */
|
|
|
|
|
} else if (preserve_order || msg->opcode == dns_opcode_update ||
|
|
|
|
|
skip_type_search)
|
|
|
|
|
{
|
|
|
|
|
result = ISC_R_NOTFOUND;
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* If this is a type that can only occur in
|
|
|
|
|
* the question section, fail.
|
|
|
|
|
*/
|
|
|
|
|
if (dns_rdatatype_questiononly(rdtype)) {
|
|
|
|
|
dns_message_puttemprdataset(msg, &rdataset);
|
|
|
|
|
DO_ERROR(DNS_R_FORMERR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
result = dns_message_find(name, rdclass, rdtype, covers,
|
|
|
|
|
&rdataset);
|
|
|
|
|
}
|
|
|
|
|
if (ISC_LIST_EMPTY(name->list)) {
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
goto skip_rds_check;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name->ht == NULL) {
|
|
|
|
|
isc_ht_init(&name->ht, msg->mctx, 1,
|
|
|
|
|
ISC_HT_CASE_SENSITIVE);
|
|
|
|
|
free_ht = true;
|
|
|
|
|
|
|
|
|
|
INSIST(ISC_LIST_HEAD(name->list) ==
|
|
|
|
|
ISC_LIST_TAIL(name->list));
|
|
|
|
|
|
|
|
|
|
dns_rdataset_t *old_rdataset =
|
|
|
|
|
ISC_LIST_HEAD(name->list);
|
|
|
|
|
|
|
|
|
|
result = rds_hash_add(name->ht, old_rdataset,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
found_rdataset = NULL;
|
|
|
|
|
result = rds_hash_add(name->ht, rdataset,
|
|
|
|
|
&found_rdataset);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we found an rdataset that matches, we need to
|
|
|
|
|
* append this rdata to that set. If we did not, we
|
|
|
|
|
* need to create a new rdatalist, store the important
|
|
|
|
|
* bits there, convert it to an rdataset, and link the
|
|
|
|
|
* latter to the name. Yuck. When appending, make
|
|
|
|
|
* certain that the type isn't a singleton type, such as
|
|
|
|
|
* SOA or CNAME.
|
|
|
|
|
*
|
|
|
|
|
* Note that this check will be bypassed when preserving
|
|
|
|
|
* order, the opcode is an update, or the type search is
|
|
|
|
|
* skipped.
|
|
|
|
|
*/
|
|
|
|
|
skip_rds_check:
|
|
|
|
|
switch (result) {
|
|
|
|
|
case ISC_R_EXISTS:
|
|
|
|
|
/* Free the rdataset we used as the key */
|
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
|
isc_mempool_put(msg->rdspool, rdataset);
|
|
|
|
|
rdataset = found_rdataset;
|
|
|
|
|
|
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
|
|
if (!dns_rdatatype_issingleton(rdtype)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we found an rdataset that matches, we need to
|
|
|
|
|
* append this rdata to that set. If we did not, we need
|
|
|
|
|
* to create a new rdatalist, store the important bits there,
|
|
|
|
|
* convert it to an rdataset, and link the latter to the name.
|
|
|
|
|
* Yuck. When appending, make certain that the type isn't
|
|
|
|
|
* a singleton type, such as SOA or CNAME.
|
|
|
|
|
*
|
|
|
|
|
* Note that this check will be bypassed when preserving order,
|
|
|
|
|
* the opcode is an update, or the type search is skipped.
|
|
|
|
|
*/
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
if (dns_rdatatype_issingleton(rdtype)) {
|
|
|
|
|
dns_rdata_t *first;
|
|
|
|
|
dns_rdatalist_fromrdataset(rdataset,
|
|
|
|
|
&rdatalist);
|
|
|
|
|
@@ -1508,33 +1651,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
if (dns_rdata_compare(rdata, first) != 0) {
|
|
|
|
|
DO_ERROR(DNS_R_FORMERR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
|
rdataset = isc_mempool_get(msg->rdspool);
|
|
|
|
|
free_rdataset = true;
|
|
|
|
|
|
|
|
|
|
rdatalist = newrdatalist(msg);
|
|
|
|
|
if (rdatalist == NULL) {
|
|
|
|
|
result = ISC_R_NOMEMORY;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdatalist->type = rdtype;
|
|
|
|
|
rdatalist->covers = covers;
|
|
|
|
|
rdatalist->rdclass = rdclass;
|
|
|
|
|
rdatalist->ttl = ttl;
|
|
|
|
|
|
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
|
RUNTIME_CHECK(
|
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset) ==
|
|
|
|
|
ISC_R_SUCCESS);
|
|
|
|
|
dns_rdataset_setownercase(rdataset, name);
|
|
|
|
|
|
|
|
|
|
if (!isedns && !istsig && !issigzero) {
|
|
|
|
|
break;
|
|
|
|
|
case ISC_R_SUCCESS:
|
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
|
free_rdataset = false;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1570,7 +1692,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
|
|
|
|
|
msg->opt = rdataset;
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
free_rdataset = false;
|
|
|
|
|
ercode = (dns_rcode_t)((msg->opt->ttl &
|
|
|
|
|
DNS_MESSAGE_EDNSRCODE_MASK) >>
|
|
|
|
|
20);
|
|
|
|
|
@@ -1582,7 +1703,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
msg->sig0name = name;
|
|
|
|
|
msg->sigstart = recstart;
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
free_rdataset = false;
|
|
|
|
|
free_name = false;
|
|
|
|
|
} else if (istsig) {
|
|
|
|
|
msg->tsig = rdataset;
|
|
|
|
|
@@ -1593,7 +1713,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
*/
|
|
|
|
|
msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
free_rdataset = false;
|
|
|
|
|
free_name = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1601,13 +1720,11 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
if (free_name) {
|
|
|
|
|
dns_message_puttempname(msg, &name);
|
|
|
|
|
}
|
|
|
|
|
if (free_rdataset) {
|
|
|
|
|
isc_mempool_put(msg->rdspool, rdataset);
|
|
|
|
|
}
|
|
|
|
|
free_name = free_rdataset = false;
|
|
|
|
|
free_name = false;
|
|
|
|
|
}
|
|
|
|
|
INSIST(!free_name);
|
|
|
|
|
INSIST(!free_rdataset);
|
|
|
|
|
|
|
|
|
|
rdataset = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -1625,16 +1742,20 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (seen_problem) {
|
|
|
|
|
return (DNS_R_RECOVERABLE);
|
|
|
|
|
result = DNS_R_RECOVERABLE;
|
|
|
|
|
}
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
if (free_name) {
|
|
|
|
|
dns_message_puttempname(msg, &name);
|
|
|
|
|
}
|
|
|
|
|
if (free_rdataset) {
|
|
|
|
|
isc_mempool_put(msg->rdspool, rdataset);
|
|
|
|
|
|
|
|
|
|
if (free_ht) {
|
|
|
|
|
cleanup_name_hashmaps(section);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name_map != NULL) {
|
|
|
|
|
isc_ht_destroy(&name_map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
|
@@ -2452,7 +2573,7 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
|
|
|
|
|
const dns_name_t *target, dns_rdatatype_t type,
|
|
|
|
|
dns_rdatatype_t covers, dns_name_t **name,
|
|
|
|
|
dns_rdataset_t **rdataset) {
|
|
|
|
|
dns_name_t *foundname;
|
|
|
|
|
dns_name_t *foundname = NULL;
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -2499,22 +2620,6 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_message_movename(dns_message_t *msg, dns_name_t *name,
|
|
|
|
|
dns_section_t fromsection, dns_section_t tosection) {
|
|
|
|
|
REQUIRE(msg != NULL);
|
|
|
|
|
REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
|
|
|
|
|
REQUIRE(name != NULL);
|
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(fromsection));
|
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(tosection));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Unlink the name from the old section
|
|
|
|
|
*/
|
|
|
|
|
ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
|
|
|
|
|
ISC_LIST_APPEND(msg->sections[tosection], name, link);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_message_addname(dns_message_t *msg, dns_name_t *name,
|
|
|
|
|
dns_section_t section) {
|
|
|
|
|
@@ -2591,6 +2696,10 @@ dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
|
|
|
|
|
REQUIRE(!ISC_LINK_LINKED(item, link));
|
|
|
|
|
REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
|
|
|
|
|
|
|
|
|
|
if (item->ht != NULL) {
|
|
|
|
|
isc_ht_destroy(&item->ht);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* we need to check this in case dns_name_dup() was used.
|
|
|
|
|
*/
|
|
|
|
|
|