From c95819d75d6ac0e5cc9cb5848445c727eec869db Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Wed, 23 Jun 1999 19:18:51 +0000 Subject: [PATCH] If the first record in a header chain was marked IGNORE, add() would incorrectly treat it as if the IGNORE attribute were not set, and the add would not work correctly. Rdatasets marked IGNORE are now ignored. subtractrdataset() also failed to ignore rdatasets, and didn't cover the case where the rdataset was marked as nonexistent. --- lib/dns/rbtdb.c | 123 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 36 deletions(-) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 987fe06e60..18b0199544 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -88,7 +88,12 @@ typedef struct rdatasetheader { #define RDATASET_ATTR_STALE 0x02 #define RDATASET_ATTR_IGNORE 0x04 -#define IGNORE(header) (((header)->attributes & RDATASET_ATTR_IGNORE) != 0) +#define EXISTS(header) \ + (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0) +#define NONEXISTENT(header) \ + (((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0) +#define IGNORE(header) \ + (((header)->attributes & RDATASET_ATTR_IGNORE) != 0) #define DEFAULT_NODE_LOCK_COUNT 7 /* Should be prime. */ @@ -2275,7 +2280,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, dns_rdataset_t *addedrdataset, isc_stdtime_t now) { rbtdb_changed_t *changed = NULL; - rdatasetheader_t *header, *header_prev; + rdatasetheader_t *topheader, *topheader_prev, *header; unsigned char *merged; dns_result_t result; isc_boolean_t force = ISC_FALSE; @@ -2303,18 +2308,26 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, } } - newheader_nx = ((newheader->attributes & RDATASET_ATTR_NONEXISTENT) - != 0 ? ISC_TRUE : ISC_FALSE); + newheader_nx = NONEXISTENT(newheader) ? ISC_TRUE : ISC_FALSE; - header_prev = NULL; - for (header = rbtnode->data; header != NULL; header = header->next) { - if (header->type == newheader->type) + topheader_prev = NULL; + for (topheader = rbtnode->data; + topheader != NULL; + topheader = topheader->next) { + if (topheader->type == newheader->type) break; - header_prev = header; + topheader_prev = topheader; } + /* + * If header isn't NULL, we've found the right type. There may be + * IGNORE rdatasets between the top of the chain and the first real + * data. We skip over them. + */ + header = topheader; + while (header != NULL && IGNORE(header)) + header = header->down; if (header != NULL) { - header_nx = ((header->attributes & RDATASET_ATTR_NONEXISTENT) - != 0 ? ISC_TRUE : ISC_FALSE); + header_nx = NONEXISTENT(header) ? ISC_TRUE : ISC_FALSE; /* * Deleting an already non-existent rdataset has no effect. @@ -2340,7 +2353,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, merge = ISC_FALSE; /* - * XXXRTH We should turn off merging for rdata types that + * XXXRTH We need to turn off merging for rdata types that * cannot be merged, e.g. SOA, CNAME, WKS. */ @@ -2383,12 +2396,12 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, } } INSIST(rbtversion == NULL || - rbtversion->serial >= header->serial); - if (header_prev != NULL) - header_prev->next = newheader; + rbtversion->serial >= topheader->serial); + if (topheader_prev != NULL) + topheader_prev->next = newheader; else rbtnode->data = newheader; - newheader->next = header->next; + newheader->next = topheader->next; if (loading) { /* * There are no other references to 'header' when @@ -2399,28 +2412,56 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, newheader->down = NULL; free_rdataset(rbtdb->common.mctx, header); } else { - newheader->down = header; - header->next = newheader; + newheader->down = topheader; + topheader->next = newheader; rbtnode->dirty = 1; if (changed != NULL) changed->dirty = ISC_TRUE; } } else { /* - * The rdataset type doesn't exist at this node. + * No non-IGNORED rdatasets of the given type exist at + * this node. */ /* - * If we're trying to delete it, don't bother. + * If we're trying to delete the type, don't bother. */ if (newheader_nx) { free_rdataset(rbtdb->common.mctx, newheader); return (DNS_R_UNCHANGED); } - - newheader->next = rbtnode->data; - newheader->down = NULL; - rbtnode->data = newheader; + + if (topheader != NULL) { + /* + * We have an list of rdatasets of the given type, + * but they're all marked IGNORE. We simply insert + * the new rdataset at the head of the list. + * + * Ignored rdatasets cannot occur during loading, so + * we INSIST on it. + */ + INSIST(!loading); + INSIST(rbtversion == NULL || + rbtversion->serial >= topheader->serial); + if (topheader_prev != NULL) + topheader_prev->next = newheader; + else + rbtnode->data = newheader; + newheader->next = topheader->next; + newheader->down = topheader; + topheader->next = newheader; + rbtnode->dirty = 1; + if (changed != NULL) + changed->dirty = ISC_TRUE; + } else { + /* + * No rdatasets of the given type exist at the node. + */ + newheader->next = rbtnode->data; + newheader->down = NULL; + rbtnode->data = newheader; + } } if (addedrdataset != NULL) @@ -2518,7 +2559,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; rbtdb_version_t *rbtversion = version; - rdatasetheader_t *header, *header_prev, *newheader; + rdatasetheader_t *topheader, *topheader_prev, *header, *newheader; unsigned char *subresult; isc_region_t region; dns_result_t result; @@ -2546,13 +2587,23 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, return (DNS_R_NOMEMORY); } - header_prev = NULL; - for (header = rbtnode->data; header != NULL; header = header->next) { - if (header->type == newheader->type) + topheader_prev = NULL; + for (topheader = rbtnode->data; + topheader != NULL; + topheader = topheader->next) { + if (topheader->type == newheader->type) break; - header_prev = header; + topheader_prev = topheader; } - if (header != NULL) { + /* + * If header isn't NULL, we've found the right type. There may be + * IGNORE rdatasets between the top of the chain and the first real + * data. We skip over them. + */ + header = topheader; + while (header != NULL && IGNORE(header)) + header = header->down; + if (header != NULL && EXISTS(header)) { result = dns_rdataslab_subtract( (unsigned char *)header, (unsigned char *)newheader, @@ -2594,16 +2645,16 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, /* * If we're here, we want to link newheader in front of - * header. + * topheader. */ - INSIST(rbtversion->serial >= header->serial); - if (header_prev != NULL) - header_prev->next = newheader; + INSIST(rbtversion->serial >= topheader->serial); + if (topheader_prev != NULL) + topheader_prev->next = newheader; else rbtnode->data = newheader; - newheader->next = header->next; - newheader->down = header; - header->next = newheader; + newheader->next = topheader->next; + newheader->down = topheader; + topheader->next = newheader; rbtnode->dirty = 1; changed->dirty = ISC_TRUE; } else {